初窺dep

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Go語言程式組織和構建的基本單元是Package,但Go語言官方卻沒有提供一款“像樣的”Package Management Tool(包管理工具)。隨著Go語言在全球範圍內應用的愈加廣泛,缺少官方包管理工具這一問題變得日益突出。

2016年GopherCon大會後,在Go官方的組織下,一個旨在改善Go包管理的commitee成立了,共同應對Go在package management上遇到的各種問題。經過各種腦洞和討論後,該commitee在若干月後發布了“Package Management Proposal”,並啟動了最有可能被接納為官方包管理工具的項目dep的設計和開發。2017年年初,dep項目正式對外開放。截至目前,dep發布了v0.1.0版本,並處於alpha測試階段。

可以說,dep的進展還是蠻快的。按照dep官方說法,dep目前的manifest和lock檔案格式已經stable,並保證向後相容。同時,dep實現了“自舉”,即dep使用自己作為自己的包管理工具。由於dep的“特殊身份”,雖然dep離成熟尚遠,但dep的進展也吸引了諸多gopher的目光,很多組織已經開始將package management tool遷移為dep,為dep進行早期測試。

這裡,我也打算“嘗嘗鮮”,在本篇文章中和大家一起窺探和試用一下dep。

一、Go包管理的演化曆史

1、go get

在管窺dep之前,我們先來簡單看看Go語言套件管理的演化曆史。首當其衝的就是go get。

Go語言新手在初次接觸Go語言時會感覺到Go語言的package擷取真的是很方便:只需一行go get xxx,github.com上的大量go package就可以隨你取用。 但隨著對Go語言使用的深入,人們會發現go get給我們帶來方便的同時,也帶來了不少的麻煩。go get本質上是git、hg等這些vcs工具的進階wrapper。對於使用git的go package來說,go get的實質就是將package git clone到本地的特定目錄下($GOPATH/src),同時go get可以自動解析包的依賴,並自動下載相關依賴包。

go get機制的設計很大程度上源於Google公司內部的單一root的代碼倉庫的開發模式,並且似乎google內部各個project/repository的master分支上的代碼都是被認為stable的,因此go get僅僅支援擷取master branch上的latest代碼,沒有指定version、branch或revision的能力。而在Google公司以外的世界裡,這樣的做法會給gopher帶來不便:依賴的第三方包總是在變。一旦第三方包提交了無法正常build或介面不相容的代碼,依賴方立即就會受到影響。

而gopher們又恰恰希望自己項目所依賴的第三方包能受到自己的控制,而不是隨意變化。這樣,godep、gb、glide等一批第三方包管理工具出現了。

以應用最為廣泛的godep為例。為了能讓第三方依賴包“穩定下來”,實現項目的reproduceble build,godep將項目當前依賴包的版本資訊記錄在Godeps/Godeps.json中,並將依賴包的相關版本存放在Godeps/_workspace中。在編譯時間(godep go build)godep通過臨時修改GOPATH環境變數的方法讓go編譯器使用緩衝在Godeps/_workspace下的項目依賴的特定版本的第三方包,這樣保證了項目不再受制於依賴的第三方包的master branch上的latest代碼的變動了。

不過,godep的“版本管理”本質上是通過緩衝第三方庫的某個revision的快照實現的,這種方式依然讓人感覺難於管理。同時,通過對GOPATH的“偷梁換柱”的方式實現使用Godeps/_workspace中的第三方庫的快照進行編譯也無法相容Go原生編譯器,必須使用godep go xxx來進行。

為此,Go進一步引入vendor機制來減少gopher在包管理問題上的心智負擔

2、vendor機制

Go team也一直在關注Go語言套件依賴的問題,尤其是在Go 1.5實現自舉的情況下,官方同樣在1.5版本中推出了vendor機制。vendor機制是Russ Cox在Go 1.5發布前期以一個experiment feature身份緊急加入到go中的(go 1.6脫離experiment身份)。vendor標準化了項目依賴的第三方庫的存放位置(不再需要Godeps/_workspace了),同時也無需對GOPATH環境變數進行“偷梁換柱”了,go compiler原生優先感知和使用vendor下緩衝的第三方包。

不過即便有了vendor的支援,vendor內第三方依賴包的代碼的管理依舊是不規範的,要麼是手動的,要麼是藉助godep這樣的第三方包管理工具。目前自舉後的Go代碼本身也引入了vendor,不過go項目自身對vendor中代碼的管理方式也是手動更新,Go自身並未使用任何第三方的包管理工具。

題外話:作為一門語言的標準庫,應該是使用這門語言的開發人員所使用的所有lib依賴的根依賴。但在go中,go標準庫居然還要依賴golang.org/x/目錄下的包,既然能被std lib依賴,那麼說明其已經成熟,那為何不把x內的stable的庫挪到std lib中呢?這點著實讓人有些不解。

~/.bin/go18/src/vendor/golang_org/x]$lscrypto/    net/    text/

從Go官方角度出發,官方go包依賴的解決方案的下一步就應該是解決對vendor下的第三方包如何進行管理的問題:依賴包的分析、記錄和擷取等,進而實現項目的reproducible build。dep就是用來做這事兒的。

二、dep簡介

go package management commitee的牽頭人物是微服務架構go-kit作者Peter Bourgon,但當前主導dep開發的是sam boyer,sam也是dep底層包依賴分析引擎-gps的作者。

和其他一些第三方Go包管理工具有所不同,dep在進行active dev前是經過commitee深思熟慮的,包括:features、user story等都在事前做了初步設計。如果你拜讀這些文檔,你可能會覺得解決包依賴問題,還是蠻複雜的。不過,對於這些工具的使用者來說,我們面對的是一些十分簡化的互動介面。

1、安裝dep

dep是標準的go cli程式,執行一條命令即完成安裝:

# go get -u github.com/golang/dep/cmd/dep# dep helpdep is a tool for managing dependencies for Go projectsUsage: dep <command>Commands:  init    Initialize a new project with manifest and lock files  status  Report the status of the project's dependencies  ensure  Ensure a dependency is safely vendored in the project  prune   Prune the vendor tree of unused packagesExamples:  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 github.com/pkg/errors  add a dependency to the projectUse "dep help [command]" for more information about a command.

在我的測試環境中,go的版本為1.8;dep的版本為commit d31c621c3381b9bebc7c10b1ac7849a96c21f2c3。

注意:由於dep還在active dev過程中且處於alpha測試階段,因此本文中執行的dep命令、命令列為以及輸出結果在後續dep版本中很可能會有變動,甚至是很大變動。

2、dep一般工作流程

安裝好dep後,我們就來看看使用dep的一般工作流程。我們首先準備一個demo程式:

//depdemo/main.gopackage mainimport (    "net/http"    "go.uber.org/zap"    "github.com/beego/mux")func main() {    logger, _ := zap.NewProduction()    defer logger.Sync()    sugar := logger.Sugar()    mx := mux.New()    mx.Handler("GET", "/", http.FileServer(http.Dir(".")))    sugar.Fatal(http.ListenAndServe("127.0.0.1:8080", mx))}

a) dep init

如果一個項目要使用dep進行包管理,那麼首先需要在這個項目的根下執行dep init。在這裡,我們對depdemo進行dep改造。

在depdemo目錄下,執行dep init:

# dep init -vSearching GOPATH for projects...  Using master as constraint for direct dep github.com/beego/mux  Locking in master (626af65) for direct dep github.com/beego/muxFollowing dependencies were not found in GOPATH. Dep will use the most recent versions of these projects.  go.uber.org/zapRoot project is "github.com/bigwhite/experiments/depdemo" 1 transitively valid internal packages 2 external packages imported from 2 projects(0)   ✓ select (root)(1)    ? attempt github.com/beego/mux with 1 pkgs; at least 1 versions to try(1)        try github.com/beego/mux@master(1)    ✓ select github.com/beego/mux@master w/1 pkgs(2)    ? attempt go.uber.org/zap with 1 pkgs; 12 versions to try(2)        try go.uber.org/zap@v1.4.0(2)    ✓ select go.uber.org/zap@v1.4.0 w/7 pkgs(3)    ? attempt go.uber.org/atomic with 1 pkgs; 6 versions to try(3)        try go.uber.org/atomic@v1.2.0(3)    ✓ select go.uber.org/atomic@v1.2.0 w/1 pkgs  ✓ found solution with 9 packages from 3 projectsSolver wall times by segment:     b-source-exists: 1.090607387s  b-deduce-proj-root: 288.126482ms         b-list-pkgs: 131.059753ms              b-gmal: 114.716587ms         select-atom:    337.787µs             satisfy:    298.743µs         select-root:    292.889µs            new-atom:    257.256µs     b-list-versions:     42.408µs               other:     22.307µs  TOTAL: 1.625761599s

當前階段,dep init命令的執行效率的確不高,因此需要你耐心的等待一會兒。如果你的project依賴的外部包很多,那麼等待的時間可能會很長。並且由於dep會下載依賴包,對於國內的朋友來說,一旦下載qiang外的包,那麼dep可能會“阻塞”在那裡!

dep init大致會做這麼幾件事:

  • 利用gps分析當前程式碼封裝中的包依賴關係;
  • 將分析出的項目包的直接依賴(即main.go顯式import的第三方包,direct dependency)約束(constraint)寫入項目根目錄下的Gopkg.toml檔案中;
  • 將項目依賴的所有第三方包(包括直接依賴和傳遞依賴transitive dependency)在滿足Gopkg.toml中約束範圍內的最新version/branch/revision資訊寫入Gopkg.lock檔案中;
  • 建立root vendor目錄,並且以Gopkg.lock為輸入,將其中的包(精確checkout 到revision)下載到項目root vendor下面。

執行完dep init後,dep會在目前的目錄下產生若干檔案:

├── Gopkg.lock├── Gopkg.toml├── main.go└── vendor/

我們逐一來看一下:

Gopkg.toml:

[[constraint]]  branch = "master"  name = "github.com/beego/mux"[[constraint]]  name = "go.uber.org/zap"  version = "1.4.0"

Gopkg.toml記錄了depdemo/main.go的兩個direct dependency:mux和zap。通過gps的分析(可以參見上面init執行時輸出的詳細分析過程日誌),dep確定的依賴版本約束為:mux的master分支、zap的1.4.0 version。

產生的Gopkg.lock中則記錄了depdemo/main.go在上述約束下的所有依賴的可用的最新版本:

Gopkg.lock:[[projects]]  branch = "master"  name = "github.com/beego/mux"  packages = ["."]  revision = "626af652714cc0092f492644e298e5f3ac7db31a"[[projects]]  name = "go.uber.org/atomic"  packages = ["."]  revision = "4e336646b2ef9fc6e47be8e21594178f98e5ebcf"  version = "v1.2.0"[[projects]]  name = "go.uber.org/zap"  packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","internal/multierror","zapcore"]  revision = "fab453050a7a08c35f31fc5fff6f2dbd962285ab"  version = "v1.4.0"[solve-meta]  analyzer-name = "dep"  analyzer-version = 1  inputs-digest = "77d32776fdc88e1025460023bef70534c5457bdc89b817c9bab2b2cf7cccb22f"  solver-name = "gps-cdcl"  solver-version = 1

vendor目錄下,則是lock檔案中各個依賴包的本地clone:

# tree -L 2 vendorvendor├── github.com│   └── beego└── go.uber.org    ├── atomic    └── zap

至此,dep init完畢,相關依賴包也已經被vendor,你可以使用go build/install進行程式構建了。

b)、提交Gopkg.toml和Gopkg.lock

如果你對dep自動分析出來的各種約束和依賴的版本沒有異議,那麼這裡就可以將Gopkg.toml和Gopkg.lock作為項目源碼的一部分提交到程式碼程式庫中了。這樣其他人在下載了你的代碼後,可以通過dep直接下載lock檔案中的第三方包版本,並存在vendor裡。這樣就使得無論在何處,項目構建的依賴庫理論上都是一致的,實現reproduceable build。

是否需要提交vendor下的依賴包代碼到代碼倉庫?這取決於你。提交vendor的好處是即便沒有dep,也可以實現真正的reproduceable build。但vendor的提交會讓你的程式碼程式庫變得異常龐大,且更新vendor時,大量的diff會影響到你對代碼的review。下面的內容我們以不提交vendor為前提。

c)、dep ensure

現在我們的depdemo已經加入了Gopkg.toml和Gopkg.lock。這時,如果你將depdemo clone到你的本地,你還無法進行reproduceable build,因為這時vendor還不存在。這時我們需要執行下面命令來根據Gopkg.toml和Gopkg.lock中的資料構建vendor目錄和同步裡面的包:

# dep ensure# ls -FGopkg.lock  Gopkg.toml  main.go  vendor/

ensure成功後,你就可以進行reproduceable build了。

我們可以通過dep status查看當前的依賴情況(包括direct and transitive dependency):

# dep statusPROJECT               CONSTRAINT     VERSION        REVISION  LATEST   PKGS USEDgithub.com/beego/mux  branch master  branch master  626af65   626af65  1go.uber.org/atomic    *              v1.2.0         4e33664   4e33664  1go.uber.org/zap       ^1.4.0         v1.4.0         fab4530   fab4530  7

d) 指定約束

dep init產生的Gopkg.toml中的約束是否是我們預期的呢?這個還真不一定。比如:我們將對zap的約束手工改為1.3.0:

//Gopkg.toml... ...[[constraint]]  name = "go.uber.org/zap"  version = "<=1.3.0"

執行dep ensure後,查看status:

# dep statusPROJECT               CONSTRAINT     VERSION        REVISION  LATEST   PKGS USEDgithub.com/beego/mux  branch master  branch master  626af65   626af65  1go.uber.org/atomic    *              v1.2.0         4e33664   4e33664  1go.uber.org/zap       <=1.3.0         v1.4.0         fab4530   fab4530  7

不過,此時Gopkg.lock中的zap version依舊是v1.4.0,並沒有修改。要想更新lock和vendor下的資料,我們需要給ensure加上一個-update參數:

# dep ensure -update# git diff Gopkg.lockdiff --git a/depdemo/Gopkg.lock b/depdemo/Gopkg.lockindex fce53dc..7fe3640 100644--- a/depdemo/Gopkg.lock+++ b/depdemo/Gopkg.lock@@ -16,12 +16,12 @@ [[projects]]   name = "go.uber.org/zap"   packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","internal/multierror","zapcore"]-  revision = "fab453050a7a08c35f31fc5fff6f2dbd962285ab"-  version = "v1.4.0"+  revision = "6a4e056f2cc954cfec3581729e758909604b3f76"+  version = "v1.3.0" [solve-meta]   analyzer-name = "dep"   analyzer-version = 1-  inputs-digest = "77d32776fdc88e1025460023bef70534c5457bdc89b817c9bab2b2cf7cccb22f"+  inputs-digest = "b09c1497771f6fe7cdfcf61ab1a026ccc909f4801c08f2c25f186f93f14526b0"   solver-name = "gps-cdcl"   solver-version = 1

-update讓dep ensure嘗試去保證並同步Gopkg.lock和vendor目錄下的資料,將Gopkg.lock下的zap的version改為Gopkg.toml下約束的最大值,即v1.3.0,同時更新vendor下的zap代碼。

e) 指定依賴

我們也可以直接更新dependency,這將影響Gopkg.lock和vendor下的資料,但Gopkg.toml不會被修改:

# dep ensure 'go.uber.org/zap@<1.4.0'# git diffdiff --git a/depdemo/Gopkg.lock b/depdemo/Gopkg.lockindex fce53dc..3b17b9b 100644--- a/depdemo/Gopkg.lock+++ b/depdemo/Gopkg.lock@@ -16,12 +16,12 @@ [[projects]]   name = "go.uber.org/zap"   packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","internal/multierror","zapcore"]-  revision = "fab453050a7a08c35f31fc5fff6f2dbd962285ab"-  version = "v1.4.0"+  revision = "6a4e056f2cc954cfec3581729e758909604b3f76"+  version = "v1.3.0" [solve-meta]   analyzer-name = "dep"   analyzer-version = 1-  inputs-digest = "77d32776fdc88e1025460023bef70534c5457bdc89b817c9bab2b2cf7cccb22f"+  inputs-digest = "3307cd7d5942d333c4263fddda66549ac802743402fe350c0403eb3657b33b0b"   solver-name = "gps-cdcl"   solver-version = 1

這種情況下會出現Gopkg.lock中的version不滿足Gopkg.toml中約束的情況。這裡也讓我比較困惑!

三、dep探索

上面的dep使用基本工作流程完全可以滿足日常包管理的需求了。但對於喜歡求甚解的我來說,必要要探索一下dep背後的行為和原理。

1、dep init的兩種不同結果

我們回到depdemo的初始狀態,即起點:尚未產生dep metadata file的時刻。我們在兩種情況下,分別執行dep init:

  • $GOPATH/src下沒有go.uber.org/zap
# dep init -vSearching GOPATH for projects...  Using master as constraint for direct dep github.com/beego/mux  Locking in master (626af65) for direct dep github.com/beego/muxFollowing dependencies were not found in GOPATH. Dep will use the most recent versions of these projects.  go.uber.org/zapRoot project is "github.com/bigwhite/experiments/depdemo" 1 transitively valid internal packages 2 external packages imported from 2 projects... ...# dep statusPROJECT               CONSTRAINT     VERSION        REVISION  LATEST   PKGS USEDgithub.com/beego/mux  branch master  branch master  626af65   626af65  1go.uber.org/atomic    *              v1.2.0         4e33664   4e33664  1go.uber.org/zap       ^1.4.0         v1.4.0         fab4530   fab4530  7
  • $GOPATH/src下存在go.uber.org/zap
# dep init -vSearching GOPATH for projects...  Using master as constraint for direct dep github.com/beego/mux  Locking in master (626af65) for direct dep github.com/beego/mux  Using master as constraint for direct dep go.uber.org/zap  Locking in master (b33459c) for direct dep go.uber.org/zap  Locking in master (908889c) for transitive dep go.uber.org/atomicRoot project is "github.com/bigwhite/experiments/depdemo" 1 transitively valid internal packages 2 external packages imported from 2 projects... ...# dep statusPROJECT               CONSTRAINT     VERSION        REVISION  LATEST   PKGS USEDgithub.com/beego/mux  branch master  branch master  626af65   626af65  1go.uber.org/atomic    *              branch master  908889c   4e33664  1go.uber.org/zap       branch master  branch master  b33459c   b33459c  7

不知道大家發現兩種情況下產生的結果的異同與否。我們只看兩個dep status輸出中的zap一行:

go.uber.org/zap       ^1.4.0         v1.4.0         fab4530   fab4530  7vs.go.uber.org/zap       branch master  branch master  b33459c   b33459c  7

dep自動分析後得到截然不同的兩個結果。

第一種情況,我們稱之為dep init的network mode,即dep發現本地GOPATH下面沒有zap,於是dep init通過network到upstream上尋找zap,並“Dep will use the most recent versions of these projects”,即v1.4.0版本。

第二種情況,我們稱之為dep init的GOPATH mode, 即dep發現本地GOPATH下面存在zap,於是dep init認定“Using master as constraint for direct dep go.uber.org/zap”,即master branch。

至於為何GOPATH mode下,dep init會選擇master,我個人猜測是因為dep覺得既然你本地有zap,那很大可能zap master的穩定性是被你所接受了的。在“dep: updated command spec”中,似乎dep init打算通過增加一個-gopath的flag來區分兩種工作模式,並將network mode作為預設工作mode。但目前我所使用的dep版本還沒有實現這個功能,其預設工作方式依舊是先GOPATH mode,如果沒有找到依賴包的存在,則針對該包實施network mode。

從這裡也可以看得出來,對於dep init 輸出的約束,你最好還是檢視一下,看是否能接受,否則就通過上面提到的“指定約束”來更正dep的輸出。

2、dep對項目的依賴包的cache

在進行上面的實驗中,我們發現:在本地GOPATH/src下面沒有zap的情況下,dep似乎是直接將zap get到本地vendor目錄的,而不是先get到GOPATH/src下,在copy到vendor中。事實是什麼樣的呢?dep的確沒有操作GOPATH/src目錄,因為那是共用的。dep在$GOPATH/pkg/dep/sources下留了一塊“自留地”,用於cache所有從network上下載的依賴包:

# ls -F $GOPATH/pkg/dep/sources/https---github.com-beego-mux/  https---github.com-uber--go-atomic/  https---github.com-uber--go-zap/# ls -aF /root/go/pkg/dep/sources/https---github.com-uber--go-zap./             buffer/            config_test.go   field.go       .gitignore      http_handler.go       LICENSE.txt           options.go          sugar.go       writer.go../            CHANGELOG.md       CONTRIBUTING.md  field_test.go  glide.lock      http_handler_test.go  logger_bench_test.go  README.md           sugar_test.go  writer_test.goarray.go       check_license.sh*  doc.go           flag.go        glide.yaml      internal/             logger.go             .readme.tmpl        time.go        zapcore/array_test.go  common_test.go     encoder.go       flag_test.go   global.go       level.go              logger_test.go        stacktrace.go       time_test.go   zapgrpc/benchmarks/    config.go          encoder_test.go  .git/          global_test.go  level_test.go         Makefile              stacktrace_test.go  .travis.yml    zaptest/

dep對於依賴包的所以git請求均在這個緩衝目錄下進行。

3、 vendor flatten平坦化

go在1.5加入vendor機制時,是考慮到“鑽石形依賴”中存在同一個依賴包的不同版本的。我們來看看dep是否支援這一點。我們設計了一個實驗:

我們建立一個這樣的“鑽石形”實驗環境,foo依賴a、b兩個包,而a、b兩個包分別依賴f的不同版本(通過在a、b中的Gopkg.toml聲明這種約束,見圖中標註)。

下面是foo項目下面的main.go:

// foo/main.gopackage mainimport "bitbucket.org/bigwhite/b"import "bitbucket.org/bigwhite/a"func main() {    a.CallA()    b.CallB()}

未引入dep前,我們來運行一下該代碼:

$go run main.gocall A: master branch   --> call F:    call F: v1.1.0   --> call F endcall B: master branch   --> call F:    call F: v2.0.1   --> call F end

可以看到同樣是f包的輸出,由於a、b分別依賴f的不同版本,因此輸出不同。

我們對foo進行一個dep 分析,看看dep給了我們什麼結果:

$dep init -vSearching GOPATH for projects...  Using master as constraint for direct dep bitbucket.org/bigwhite/a  Locking in master (9122a5d) for direct dep bitbucket.org/bigwhite/a  Using master as constraint for direct dep bitbucket.org/bigwhite/b  Locking in master (2415845) for direct dep bitbucket.org/bigwhite/b  Locking in master (971460c) for transitive dep bitbucket.org/bigwhite/fRoot project is "Foo" 1 transitively valid internal packages 2 external packages imported from 2 projects ... ...No versions of bitbucket.org/bigwhite/b met constraints:    master: Could not introduce bitbucket.org/bigwhite/b@master, as it has a dependency on bitbucket.org/bigwhite/f with constraint ^2.0.0, which has no overlap with existing constraint ^1.1.0 from bitbucket.org/bigwhite/a@master    v2.0.0: Could not introduce bitbucket.org/bigwhite/b@v2.0.0, as it is not allowed by constraint master from project Foo.    v1.0.0: Could not introduce bitbucket.org/bigwhite/b@v1.0.0, as it is not allowed by constraint master from project Foo.    master: Could not introduce bitbucket.org/bigwhite/b@master, as it has a dependency on bitbucket.org/bigwhite/f with constraint ^2.0.0, which has no overlap with existing constraint ^1.1.0 from bitbucket.org/bigwhite/a@master

dep init運行失敗。由於a依賴的f@^1.1.0和b依賴的f@^2.0.0兩個約束之間沒有交集,無法調和,dep無法solve這個依賴,於是init failed!

但失敗背後還有一層原因,那就是dep的設計要求flatten vendor,即使用dep的項目只能有一個root vendor,所以直接依賴或傳遞依賴的包中包含vendor的,vendor目錄也都會被strip掉。這樣一旦依賴包中存在帶有衝突的約束,那麼dep init必將失敗。

四、小結

dep一個重要feature就是支援semver 2.0規範,不過semver的規則好多,不是這裡能說清楚的,大家可以到semver官方站細讀規則,或者在npm semver calculator這個網站直觀感受semver規則帶來的變化。

dep實驗告一段落。從目前來看,dep已經進入可用階段,建議有條件的童鞋能積極的使用dep,並為dep進行前期測試,發現問題提issue,為dep的快速完善出出力。

depdemo的代碼在這裡;a, b,f包的代碼在這裡、這裡和這裡。

五、參考資料

  • dep FAQ
  • dep roadmap
  • dep updated command spec
  • dep features
  • The Saga of Go Dependency Management by sam boyer
  • gps for implementors

微博:@tonybai_cn
公眾號:iamtonybai
github.com: https://github.com/bigwhite

2017, bigwhite. 著作權.

Related posts:

  1. 理解Go 1.5 vendor
  2. Go 1.6中值得關注的幾個變化
  3. godep支援Go 1.5 vendor
  4. CVS Primer
  5. Advanced CVS

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.