golang的包管理---vendor/dep等


首先關於vendor

1 提出問題

我們知道,一個工程稍大一點,通常會依賴各種各樣的包。而Go使用統一的GOPATH管理依賴包,且每個包僅保留一個版本。而不同的依賴包由各自的版本工具獨立管理,所以當所依賴的包在新版本發生接口變更或刪除時,會面臨很多問題。
為避免此類問題,我們可能會為不同的工程設置不同的GOPATH,或者更改依賴包路徑名稱。這樣手動維護起來也很頭疼。

2 解決問題

Go 1.5引入了vendor文件夾,其對語言使用,go命令沒有任何影響。若某個路徑下邊包含vendor文件夾,則在某處引用包時,會優先搜索vendor文件夾下的包。
在Go 1.5開啟該項特性需設置GO15VENDOREXPERIMENT=1,而從Go 1.6開始,該項特性默認開啟。

3 使用方式

3.1 vendor搜索方式

vendor包的搜索方式為:自包引用處,從其所在文件夾查詢是否有vendor文件夾包含所引用包;若沒有,然后從其所在文件夾的上層文件夾尋找是否有vendor文件夾包含所引用包,若沒有,則再搜索上層文件夾的上層文件夾...,直至搜索至\(GOPATH/src並搜索完成時止。 例如,如下代碼中,`\)GOPATH/src/x/y/z/main.go引用了包"v",則不論vendor/v/v.go`置於src/,src/x/,src/x/y/,src/x/y/z/中任意一個文件夾下,均可以找到。

$ cat $GOPATH/src/x/y/z/main.go

package main

import (
    "v"
)

func main() {
    v.V()
}
$ cat vendor/v/v.go

package v

import "fmt"

func V() {
    fmt.Println("I'm a vendor test")
}
$ go run main.go

I'm a vendor test

當vendor存在嵌套時,若不同的vendor文件夾包含相同的包,且該包在某處被引用,尋找策略仍遵循如上規則。即從包引用處起,逐層向上層文件夾搜索,首先找到的包即為所引,也就是從$GOPATH/src來看,哪個vendor包的路徑最長,使用哪個。

如下代碼中,\(GOPATH/src/x/y/z/main.go所在工程有兩個vendor文件夾(分別位於\)GOPATH/src/x/vendor/v/,$GOPATH/src/x/y/z/vendor/v/)包含相同的包"v",目錄樹為:

$ tree $GOPATH/src

src
 └ x
   ├ vendor
   │  └ v
   │     └ v.go
   └ y
     └ z
       ├ vendor
       │ └ v
       │    └ v.go
       └ main.go
$ cat $GOPATH/src/x/vendor/v/v.go

package v

import "fmt"

func V() {
    fmt.Println("I'm a vendor test, My path is x/vendor/v/")
}
$ cat $GOPATH/src/x/y/z/vendor/v/v.go

package v

import "fmt"

func V() {
    fmt.Println("I'm a vendor test, My path is x/y/z/vendor/v/")
}

輸出為:

$ go run main.go

I'm a vendor test, My path is x/y/z/vendor/v/

可以看到,真正調用的是$GOPATH/src/x/y/z/vendor/v/v.go。

3.2 vendor使用規約

使用vendor時,建議遵循如下兩條規約。

  • a) 當欲將某包vendor時,可能想將所有依賴包均vendor;
  • b) 盡量將vendor依賴包結構扁平化,不要vendor套vendor。
    如下示例代碼演示vendor扁平化使用。
    main.go位於$GOPATH/src/github.com/olzhy/test下。
package main

import (
    "strings"
    "sync"
    "time"

    "github.com/z"
    "github.com/y"
    "golang.org/z"
)
...

$GOPATH/src/github.com/olzhy/test目錄樹。

├─ main.go
└─ vendor
    ├─ github.com
    │   ├─ x
    │   └─ y
    └─ golang.org
         └─ z

參考資料
[1] https://go.googlesource.com/proposal/+/master/design/25719-go15vendor.md
[2] https://blog.gopheracademy.com/advent-2015/vendor-folder/
[3] https://tonybai.com/2015/07/31/understand-go15-vendor/
轉自:

https://leileiluoluo.com

接下來是關於dep

dep 是 golang 項目依賴管理之一,是官方的實驗項目,目前更新很頻繁處於高速發展期,所以選 dep 作為 golang 的依賴管理器是比較靠譜的。(已知 glide 僅支持不再開發新功能)
目前 dep v0.5.0 release 已經發布,最新的 changelog 顯示只支持 golang 1.9+ 以上的版本
golang 最原始的依賴管理是 go get ,執行命令后會拉取代碼放入 src 下面,但是它是作為 GOPATH 下全局的依賴,並且 go get 還不能版本控制,以及隔離項目的包依賴在沒有依賴管理工具的時候,golang 項目有一種目錄結構比較流行如下:

.
└── src
    ├── demo
    │   └── main.go
    ├── github.com
    ├── golang.org
    └── gopkg.in

這樣做的話就是每一個項目一個 GOPATH 則上面的 GOPATH=/xx/xx/src 這樣設置后也是可以編譯的,且項目依賴都是 src 下的包,與全局的無關聯, go get 獲取依賴,也必須在項目 GOPATH 下。可以看到這樣的目錄結構還是有很多缺陷的。特別是 import 包的包目錄有時會很奇怪,沒有統一的風格,且 ide 或 編輯器支持也不夠理想。

所以目前 golang 引入了 vendor 目錄作為依賴管理目錄,且 ide 或 golang 編輯插件目前都能很好的支持 例如 gogland 索引依賴包時會優先查找項目根目錄下的 vendor 目錄, vscode 的 go 插件也是。那么目前比較流行的目錄結構如下:

.
├── Gopkg.lock
├── Gopkg.toml
├── main.go
└── vendor
    ├── github.com
    │   ├── gin-contrib
    │   ├── gin-gonic
    │   ├── golang
    │   ├── mattn
    │   └── ugorji
    ├── golang.org
    │   └── x
    └── gopkg.in
        ├── go-playground
        └── yaml.v2

項目目錄 $GOPATH/src/projectname/.

Getting Started

install / uninstall

brew install dep
brew uninstall dep
# /usr/local/bin/dep
windows
# 推薦 go get 安裝
go get -u github.com/golang/dep/cmd/dep
# $GOPATH/bin/dep.exe
Arch linux
pacman -S dep
# 刪除 pacman -R dep
二進制安裝
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
# $GOPATH/bin/dep
# 刪除 > rm $GOPATH/bin/dep
源碼安裝
go get -d -u github.com/golang/dep
cd $(go env GOPATH)/src/github.com/golang/dep
DEP_LATEST=$(git describe --abbrev=0 --tags)
git checkout $DEP_LATEST
go install -ldflags="-X main.version=$DEP_LATEST" ./cmd/dep
git checkout master

推薦安裝方式為 各系統的快捷安裝,最方便且不容易出錯, 如果想使用最新/指定版本,推薦源碼安裝

初始化項目
推薦使用上述第二種目錄結構

mkdir $GOPATH/src/example
cd $GOPATH/src/example
dep init
# 生成 vendor/ 目錄下 Gopkg.toml Gopkg.lock

使用流程

Usage
Dep is a tool for managing dependencies for Go projects

Usage: "dep [command]"

Commands:
  init     Set up a new Go project, or migrate an existing one
  status   Report the status of the project's dependencies
  ensure   Ensure a dependency is safely vendored in the project
  prune    Pruning is now performed automatically by dep ensure.
  version  Show the dep version information

Examples:
  dep init                               set up a new project
  dep ensure                             install the project's dependencies
  dep ensure -update                     update the locked versions of all dependencies
  dep ensure -add github.com/pkg/errors  add a dependency to the project

Use "dep help [command]" for more information about a command.

獲取依賴策略

  • 獲取最新TAG的依賴包
    dep ensure -add github.com/gin-gonic/gin

  • 獲取指定分支的依賴包
    dep ensure -add github.com/gin-gonic/gin@master

  • 獲取指定TAG的依賴包
    dep ensure -add github.com/gin-gonic/gin@V1.2

  • 獲取指定TAG以上的依賴包
    dep ensure -add github.com/gin-gonic/gin@^V1.2

  • 獲取依賴包的 子包
    dep ensure -add github.com/prometheus/client_golang/prometheus/push

  • 獲取兩個子包的情況
    dep ensure -add github.com/prometheus/client_golang/prometheus/push github.com/prometheus/client_golang/prometheus/promhttp

  • 獲取過程:根據命令先判斷本地是否有緩存(緩存地址:$GOPATH/src/dep),存在則直接使用緩存,不存在則,先獲取 git 版本/分支/tag 根據命令找到對應的版本下載。

FQAs

  • 當拉取過程中如果出現 timeout 則請自備梯子.
  • 當拉取出現未知的錯誤,可以先手動刪除 緩存 在嘗試一次
  • 當出現 *build.NoGoError 錯誤,可能是 build 時當前依賴包並沒有 main 函數,這種情況一般是需要拉取依賴包的子包
  • 當已存在的項目 dep init 會遍歷當前項目的依賴包,並下載,所以時間會很久

轉自

https://studygolang.com/articles/13990/comment/18351


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM