Go Module 工程化實踐(三):工程實踐篇

尊重生命,即便是螞蟻,也不會踩死。 -- JayL

3. 工程實踐篇

如何實現企業內項目的Go Module工程化遷移?

以本人以往所在公司的實際現狀做爲樣例,說明具體的Go Module工程化遷移過程。html

原有Go項目均採用單一vendor的模式進行依賴控制,即企業內全部Go項目的第三方依賴均引用該統一的vendor倉庫,由專人專組獨立維護。這樣作的好處就是依賴包不會隨實際開發者的版本變動而變動,企業內部維護一套相對穩定的版本,缺點就是缺乏了依賴包的版本控制。git

Go Module工程化遷移的目標就是保持本地版本的穩定的同時兼顧版本控制功能。github

3.1 modules倉庫

在非Go Module項目中,全部項目的依賴包,使用了vendor倉庫,在遷移到Go Module模式下,一樣須要相應的modules倉庫, 來保證本地開發包依賴版本的穩定。golang

modules倉庫的依賴包從何而來。不妨看看:apache

$: tree -L 1 $GOPATH/pkg/mod/cache/download
├── cloud.google.com
├── git.apache.org
├── git.yixindev.net
├── github.com
├── go.opencensus.io
├── go.uber.org
├── golang.org
├── gonum.org
├── google.golang.org
├── gopkg.in
├── gotest.tools
├── honnef.co
├── k8s.io
└── layeh.com

這就是咱們要維護的modules倉庫依賴包。在開發過程當中,新的依賴包都會下載到這個路徑。將新的依賴包版本複製到modules倉庫相應的路徑。就完成了modules倉庫依賴包的版本維護。bash

須要注意的點是:gitlab

咱們是從$GOPATH/pkg/mod/cache/download目錄中複製新的依賴包到modules倉庫中。但並非全部的文件都須要進行維護,特別是本地下載過程當中的一些臨時文件。優化

$: tree -L 1 $GOPATH/pkg/mod/cache/download/github.com/x-mod/httpclient/@v/
├── list
├── list.lock
├── v0.1.2.info
├── v0.1.2.lock
├── v0.1.2.mod
├── v0.1.2.zip
├── v0.1.2.ziphash
├── v0.2.0.info
├── v0.2.0.lock
├── v0.2.0.mod
├── v0.2.0.zip
├── v0.2.0.ziphash
├── v0.2.1.info
├── v0.2.1.lock
├── v0.2.1.mod
├── v0.2.1.zip
└── v0.2.1.ziphash

在這個github.com/x-mod/httpclient依賴包中,咱們僅僅須要具體版本的四個類型文件:google

  • info
  • mod
  • zip
  • ziphash

其它類型的文件,是不須要進行modules倉庫維護的。因此能夠在modules倉庫中經過.gitignore進行忽略。.net

3.2 CI過程更新

完成了modules倉庫的維護後,咱們就能夠對原有項目的CI過程進行更新了。在CI編譯機或者容器上

  • git clone modules repo 到指定位置 path/to/modules
  • 開啓GoModule編譯選項, 設置export GO111MODULE=on
  • 設置GoProxy環境變量, 設置經過本地文件代理: export GOPROXY=file:///path/to/modules

如今全部GO項目就會開啓GoModule選項同時,能夠完成依賴包的版本控制。如何缺乏依賴包,只須要從本地將新增依賴包的版本添加到modules倉庫便可。

3.3 企業倉庫GoGet代理優化

若是閱讀了Go Get原理以後,針對企業依賴包的GoGet,咱們能夠寫一個簡單的http代理程序, 這樣就設定本身的:

// Example
// code server http://aaa.com:888/user/repo.git
// code import path: bbb.com/user/repo
// 
// host => aaa.com:888
// vcs  => git
// root => bbb.com

type Getter struct {
    host    string //gitlab address
    vcs     string //git
    root    string //git
}

func NewGetter(host string, vcs string, root string) *Getter {
    return &Getter{
        host: host,
        vcs:  vcs,
        root: root,
    }
}

func (x *Getter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Query().Get("go-get") == "1" {
        sp := strings.Split(r.URL.Path[1:], "/")
        if len(sp) < 2 {
            http.Error(w, fmt.Errorf("unsupport path: %s", r.URL.Path).Error(), http.StatusBadRequest)
            return
        }
        prefix := fmt.Sprintf("%s/%s/%s", x.host, sp[0], sp[1])
        repository := fmt.Sprintf("%s/%s/%s.%s", x.root, sp[0], sp[1], x.vcs)
        fmt.Fprintf(w, `<html><head><meta name="go-import" content="%s %s %s" /></head></html>`, prefix, x.vcs, repository)
        log.Println("go get [", prefix, "] from repository [", repository, "].")
        return
    }
    http.Error(w, fmt.Errorf("unsupport request: %s", r.URL.Path).Error(), http.StatusBadRequest)
}

經過這個簡單的代理,你就能夠實現:

code server http://aaa.com:888/user/repo.git
code import path: bbb.com/user/repo

host => aaa.com:888
vcs => git
root => bbb.com

這樣的非標依賴包的拉取了。

這一篇拖了很久,花一個小時完結掉這個系列。

更多文章可直接訪問我的BLOG:GitDiG.com

相關閱讀:

相關文章
相關標籤/搜索