Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

07 Mar 2018

用Go语言写一个简单的Gitweb Server

Git的发行版中带了一个叫gitweb的工具,可以以web的方式来查看git仓库。但是gitweb本身是一个CGI脚本,需要一个支持CGI的Web服务器来运行它。这篇文章介绍如何用Go语言写一个简单的服务器,用来运行gitweb。

gitweb的CGI脚本一般叫gitweb.cgi,随git一起发布。我的macOS上安装的git版本是2.16.2,gitweb.cgi所在的目录是

/usr/local/Cellar/git/2.16.2/share/gitweb/

在这个目录下除了gitweb.cgi之外,还有一个static目录,里面存放着gitweb的前端资源文件。

运行gitweb需要用到Go语言的http库以及cgi库。我们会进行一下编排:

  • localhost:3333启动http服务
  • 使用http.ServeFile来访问static目录里面的文件
  • 通过cgi库在服务器根目录提供gitweb.cgi服务

具体的代码如下:

package main

import (
   "log"
   "net/http"
   "net/http/cgi"
   "path/filepath"
   "strings"
)

var GITWEB_DIR = "/usr/local/Cellar/git/2.16.2/share/gitweb"
var GITWEB_CGI = filepath.Join(GITWEB_DIR, "gitweb.cgi")

func serveGitweb(w http.ResponseWriter, r *http.Request) {
   if strings.HasPrefix(r.URL.Path, "/static/") {
       http.ServeFile(w, r, filepath.Join(GITWEB_DIR, r.URL.Path))
       return
   }

   conf, err := filepath.Abs("./gitweb.conf")
   if err != nil {
       log.Fatal(err)
   }

   env := []string{
       "GITWEB_CONFIG=" + conf,
   }

   gitweb := cgi.Handler{
       Path: GITWEB_CGI,
       Root: `/`,
       Env:  env,
   }
   gitweb.ServeHTTP(w, r)
}

func main() {
   http.HandleFunc("/", serveGitweb)
   addr := ":3333"
   log.Print("ListenAndServe", addr)
   err := http.ListenAndServe(addr, nil)
   if err != nil {
       log.Fatal(err)
   }
}

上面的文件保存为gitweb.go。需要注意的是,为了使gitweb能够正常工作,我们在启动cgi之前,通过环境变量GITWEB_CONFIG为gitweb指定了一个配置文件gitweb.conf。在当前的例子中,此配置文件和gitweb.go在同一目录下,内容为:

our $projectroot = '/path/to/repos';
our $site_name = 'My Gitweb';

其实gitweb.conf是一个perl脚本,里面定义了两个变量,一个是$projectroot,告诉gitweb其服务的git仓库在什么位置;另个一是$site_name,用于作为该gitweb服务的名字。

gitweb.gogitweb.conf都准备好之后,可以运行:

go run gitweb.go

看到这行提示2018/03/07 21:10:40 ListenAndServe:3333的时候,说明gitweb已经运行于localhost:3333了。

其他参考:

  • gitweb.conf(5) Manual Page
  • gitweb(1) Manual Page
  • git-instaweb(1) Manual Page

(完)

Categories