go包管理

摘自:html

http://blueskykong.com/2019/02/18/go-dep-1/git

https://www.cnblogs.com/apocelipes/p/10295096.html#vcs-semvergithub

GOPATH和GOROOT

GOROOT的目的就是告知go當前的安裝位置,默認go會安裝在/usr/local/go下,但也容許自定義安裝位置(經過 export GOROOT=$HOME/go1.9.3指定)。編譯的時候從GOROOT去找SDK的system libarirygolang

GOPATH必需要設置,GOPATH告知go,須要代碼(包括本項目即內部依賴和引用外部項目的代碼即外部依賴)的時候去哪裏查找。GOPATH能夠隨着項目的不一樣而從新設置。chrome

GOPATH下會有3個目錄:src、bin、pkg。json

  • src目錄:go編譯時查找代碼的地方;按照golang默認約定,go run,go install等命令的當前工做路徑(即在此路徑下執行上述命令)。
  • bin目錄:go get這種bin工具的時候,二進制文件下載的目的地; golang編譯可執行文件存放路徑
  • pkg目錄:編譯生成的lib文件存儲的地方。golang編譯包時,生成的.a文件存放路徑

內部依賴管理緩存

  • 編譯時會去$GOPATH/src/目錄去查找須要的代碼

GOPATH來管理外部依賴工具

  • go容許import不一樣代碼庫的代碼,例如github.com, k8s.io, golang.org等等;對於須要import的代碼,可使用 go get 命令取下來放到GOPATH對應的目錄中去。例如go get github.com/globalsign/mgo(下載和建立項目要保持目錄一致,這樣才能保證可以正確的引用外部導入和內部導入),會下載到$GOPATH/src/github.com/globalsign/mgo中去,當其餘項目在import github.com/globalsign/mgo的時候也就能找到對應的代碼了。fetch

  • 對於go來講,其實並不在乎你的代碼是內部仍是外部的,總之都在GOPATH裏,任何import包的路徑都是從GOPATH開始的。Go 語言原生包管理的缺陷:
    • 依賴 列表/關係 沒法持久化到本地,須要找出全部依賴包而後一個個 go get
    • 只能依賴本地全局倉庫(GOPATH/GOROOT),沒法將庫放置於局部倉庫($PROJECT_HOME/vendor)

vendor

  • vendor就是讓go編譯時,優先從項目源碼樹根目錄下的vendor目錄查找代碼,若是vendor中有,則再也不去GOPATH中去查找。
  • 以kube-keepalived-vip爲例。該項目會調用k8s.io/kubernetes的庫(Client),但若是你用1.5版本的kubernetes代碼來編譯keepalived,會編譯不過。1.5版本中代碼有變化,已經沒有這個Client了。這就是前面說的依賴GOPATH來解決go import所帶來的問題,代碼不對上了。
  • 使用vendor目錄能夠把全部依賴的包都拷貝到了vendor目錄下,對於須要編譯該項目的人來講,只要把代碼從github上clone到$GOPATH/src之後,就能夠進去go build了(注意,必須將kube-keepalived-vip項目拷貝到$GOPATH/src目錄中,不然go會無視vendor目錄,仍然去$GOPATH/src中去找依賴包)。

govendor

  • 該工具將項目依賴的外部包拷貝到項目下的 vendor 目錄下,並經過 vendor.json 文件來記錄依賴包的版本,方便用戶使用相對穩定的依賴。ui

  • 使用步驟

    #安裝
    go get -u github.com/kardianos/govendor
    
    # 進入項目的根目錄
    # 建立 vendor 文件夾和 vendor.json 文件,此時文件中只有本項目的信息
    govendor init
    
    # 拷貝GOPATH下的代碼到vendor目錄中,更新vendor.json
    govendor add +external
    
    # 列出已經存在的依賴包
    govendor list
    
    # 找出使用的對應包
    govendor list -v fmt
    
    # 拉取指定版本的包
    govendor fetch golang.org/x/net/context@a4bbce9fcae005b22ae5443f6af064d80a6f5a55
    govendor fetch golang.org/x/net/context@v1   # Get latest v1.*.* tag or branch.
    govendor fetch golang.org/x/net/context@=v1  # Get the tag or branch named "v1".
  • govendor還能夠直接指定依賴包版原本獲取包

img

Modules

go module 是go包的集合,是源代碼交換和版本化控制的基本單元

  • 「模塊根目錄」 ( Module root ) : 包含了名爲 go.mod 文件的目錄,能夠存放於文件系統上的任何位置,而不用管 GOPATH 路徑究竟是什麼
  • 「模塊路徑」 ( Module path ) : 與模塊根目錄對應的導入路徑的前綴
  • 「主模塊」( Main module ) : 包行了運行 go 命令的所在目錄的模塊

GO111MODULE

要使用go module,首先要設置GO111MODULE=on

  • 若是設置爲 on ,那麼不管模塊在於何種路徑,都會啓用模塊支持,始終使用 module-aware mode,只根據 go.mod 下載 dependency 而徹底忽略 GOPATH 以及 vendor 目錄
  • 若是設置爲 off,禁用 go module 功能,go compiler 會始終使用 GOPATH mode,即不管要構建的源碼目錄是否在 GOPATH 路徑下,go compiler 都會在傳統的 GOPATH 和 vendor 目錄 (僅支持在 GOPATH 目錄下的 package) 下搜索目標程序依賴的 go package;
  • 若是沒有設置,或設置爲 auto,知足如下任一條件時才使用 module-aware mode:
    • 當前目錄位於 GOPATH/src 以外而且包含 go.mod 文件
    • 當前目錄位於包含 go.mod 文件的目錄下

既有項目

  • 假設你已經有了一個go 項目, 好比在$GOPATH/github.com/smallnest/rpcx下, 你可使用go mod init github.com/smallnest/rpcx在這個文件夾下(即模塊根目錄)建立一個空的go.mod (只有第一行 module github.com/smallnest/rpcx即模塊導入名稱)。

  • 下面是一個簡化的go.mod的內容

    module my/thing //模塊名稱
    
    require (//要求的依賴項列表以及版本
            one/thing v1.3.2
            other/thing v2.5.0 // indirect
            ...
    )
    
    exclude (//排除的依賴項,僅在當前模塊爲主模塊時生效
            bad/thing v0.7.3
    )
    
    replace (//替換的依賴項,僅在當前模塊爲主模塊時生效
            src/thing 1.0.2 => dst/thing v1.1.0
    )
  • go get ./...查找依賴,並記錄在go.mod文件中(你還能夠指定 -tags,這樣能夠把tags的依賴都查找到)。

  • 執行上面的命令會把go.modlatest版本換成實際的最新的版本,而且會生成一個go.sum記錄每一個依賴庫的版本和哈希值,用於驗證緩存的依賴項是否知足模塊要求

新的項目

你能夠在GOPATH以外建立新的項目。

go mod init packagename能夠建立一個空的go.mod,而後你能夠在其中增長require github.com/smallnest/rpcx latest依賴,或者像上面同樣讓go自動發現和維護。

go mod download能夠下載所須要的依賴,可是依賴並非下載到$GOPATH中,而是$GOPATH/pkg/mod中,用來當作緩存,多個項目能夠共享緩存的module。

go mod命令

//download    下載依賴的module到本地cache
//edit        edit go.mod from tools or scripts (編輯go.mod文件)
例如 go mod edit -require="github.com/chromedp/chromedp@v0.1.0",修改依賴關係使用chromedp 的v0.1.0版本
//tidy 增長丟失的module,去掉未用的module,如在項目的開發過程當中, 依賴有變動, 可以使用 go mod tidy 來應用這些變動到 go.mod 文件.
//graph       print module requirement graph (打印模塊依賴圖))
//init        在當前文件夾下初始化一個新的module, 建立go.mod文件
//vendor  在項目發佈時會要將依賴複製到項目中,會複製modules下載到vendor中, 貌似只會下載你代碼中引用的庫,而不是go.mod中定義所有的module。
//verify      verify dependencies have expected content (校驗依賴)
//why         explain why packages or modules are needed (解釋爲何須要依賴)
//go list -m -json all //依賴詳情

集成

go module 功能被集成到 go 命令行工具中,例如,在調用諸如 go buildgo installgo rungo test 之類的命令時,將啓動相應的操做,如緩存,建立或更新 go.modgo.sum

go get 升級

  • 運行 go get -u 將會升級到最新的次要版本或者修訂版本
  • 運行 go get -u=patch 將會升級到最新的修訂版本
  • 運行 go get package@version 將會升級到指定的版本號version

語義化版本

golang官方推薦的最佳實踐叫作semver,寫全了就是Semantic Versioning(語義化版本)。形如vX.Y.Z的形式顯然比一串hash更直觀,x.y.z, z是修訂版本號, y是次要版本號,如此一來包的導入路徑發生了變化,不一樣的導入路徑意味着不一樣的包,更具體的規範在這裏

相關文章
相關標籤/搜索