那一天我二十一歲,在我一輩子的黃金時代,我有好多奢望。我想愛,想吃,還想在一瞬間變整天上半明半暗的雲,後來我才知道,生活就是個緩慢受錘的過程,人一每天老下去,奢望也一每天消逝,最後變得像捱了錘的牛一樣。但是我過二十一歲生日時沒有預見到這一點。我覺得本身會永遠生猛下去,什麼也錘不了我。 -- 王小波 《黃金時代》
接上篇: Go Module 工程化實踐(一):基礎概念篇。git
go get
取包原理篇不管是否開啓Go Module
功能,go get
從版本控制系統VCS
中取包的基礎過程是相似的,除了在新的實現中再也不循環拉取submodule
子模塊之外。github
go get
基礎取包流程假設依賴包github.com/liujianping/foo
不在本地,須要經過go get
獲取。發起如下命令:golang
$: go get github.com/liujianping/foo
命令發出後:正則表達式
go get
能夠指定具體包的import
路徑或者經過其自行分析代碼中的import
得出須要獲取包的路徑。可是import
路徑,並不直接就是該包的查詢路徑。在go get
的源碼實現中,包的查詢路徑是經過一組正則匹配出來的。也就是說,import
路徑是必須匹配這組正則表達式的,若是不匹配的話,代碼是確定沒法編譯的。筆者就貼一下這組正則表達式中的github正則與私有倉庫的正則:segmentfault
// Github { prefix: "github.com/", re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`, vcs: "git", repo: "https://{root}", check: noVCSSuffix, }, //省略其它VCS... // General syntax for any server. // Must be last.私有倉庫將會使用該正則 { re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?P<vcs>bzr|fossil|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`, ping: true, },
以包路徑github.com/liujianping/foo
爲例,正則匹配後,得出的查詢路徑就是:ssh
https://github.com/liujianping/foo
curl
再結合go-get
參數,向遠端VCS系統發起https://github.com/liujianping/foo?go-get=1
請求。svn
包的遠端倉庫地址,能夠經過go get
請求的響應中的go-import
的meta標籤中的content中獲取的。gitlab
$: curl https://github.com/liujianping/foo?go-get=1 | grep go-import <meta name="go-import" content="github.com/liujianping/foo git https://github.com/liujianping/foo.git">
例子中的包對應的遠端倉庫地址就是:https://github.com/liujianping/foo.git
.測試
clone
到本地雖然版本控制系統VCS
自己就存在各種區別,可是一些基礎操做大多相似。在go get
中具體clone
的過程會根據具體的VCS
採用對應的操做。
go get
代理取包流程瞭解了go get
取包的基礎流程後,說說Go Module
功能開啓後的完整流程。
開啓Go Module
後,go get
增長了一個新的環境變量GOPROXY
。該環境變量一旦開啓,go get
就徹底切換到新的取包流程,即GOPROXY
流程,暫時就這麼稱呼吧。
在GOPROXY
流程中,官方定義了一組代理接口, 請參考官方接口定義。
GET $GOPROXY/<module>/@v/list returns a list of all known versions of the given module, one per line.GET $GOPROXY/<module>/@v/<version>.info returns JSON-formatted metadata about that version of the given module.
GET $GOPROXY/<module>/@v/<version>.mod returns the go.mod file for that version of the given module.
GET $GOPROXY/<module>/@v/<version>.zip returns the zip archive for that version of the given module.
其實這組接口的定義就是$GOPATH/pkg/mod/cache/download
中的文件系統。就是說,咱們能夠直接將此目錄下的文件系統做爲代理使用,以下命令:export GOPROXY=file:///$GOPATH/pkg/mod/cache/download/
關於GOPROXY
代理服務,網上有不少實現,官方也推薦了幾個。各有各的問題,只能這樣說。由於,對於一些定製話的需求,例如:
尚無完美的解決方案。可是即便這樣,咱們仍是能夠根據具體的工程化需求構建企業內部的一套標準的GO Module
流程來。具體方案,在下一篇工程實踐篇中講解。
私有倉庫的取包過程當中出現的問題大多集中在基礎取包過程當中。具體的異常又可能發生在2.1.1~2.1.3任一階段。分別列舉常見問題與解決思路。
clone
階段的權限問題一般狀況下,私有倉庫的訪問是基於帳號權限的。例如,private.vcs.com/group/foo
的包路徑,在go get
過程當中,會正則匹配出https://private.vcs.com/group/foo.git
的倉庫路徑,假設VCS系統是gitlab搭建的。
那麼在git clone https://private.vcs.com/group/foo.git
的過程當中,系統會提醒用戶提供用戶名與登陸密碼。每次輸入就會很累贅。
解決方案有二:
增長$HOME/.gitconfig
配置:[url "ssh://git@github.com/MYORGANIZATION/"]
insteadOf = https://github.com/MYORGANIZA...
將原有的https訪問方式替換成ssh方式。
增長$HOME/.netrc
:machine github.com login YOU password APIKEY
將其中的 APIKEY 換成本身的登陸KEY。
雖然採用的github爲例,但適用於gitlab服務。其實,還有一種解決方案,該方案,還能解決2.3.2中的問題,故在下節中講解。
因爲歷史緣由,筆者公司的gitlab服務地址就是非標準的路徑,標準路徑應該是: https://private.vcs.com
,而筆者公司的gitlab路徑則是: https://private.vcs.com:888
.
若是按go get
流程,import包路徑應該採用d:private.vcs.com:888/group/foo
,就能夠正確匹配出該倉庫的合理地址了。可是很不幸,在實際操做中,失敗了結。具體緣由讀者能夠自行測試一下。
此時惟一的辦法,就是搭建一箇中間服務:https://private.vcs.com
可以經過go get
的包路徑匹配查詢正確的倉庫地址。
更多文章可直接訪問我的BLOG:GitDiG.com