Go語言入門——dep入門

來源:互聯網
上載者:User

標籤:結構   適合   alt   nal   首字母   文檔   資訊   ons   而且   

  本文出現了大量maven的內容,更適合java程式員閱讀,如果你的語言做依賴管理的方案與maven差異很大,可能在有些地方會不理解

  從很久之前go語言在依賴解決和管理方面方案的匱乏就被不少人詬病。光指望go get指令,很多事辦不成。我也不清楚從什麼時候開始,dep,這個官方的解決方案開始被推廣了。從說明上看,不會早於go 1.8,從github的原始碼上看,至少開源不會超過1年

  官方對於dep的介紹是“dep is the official experiment, but not yet the official tool.” 但又說 “dep is safe for production use.”。我並沒在實踐中真實使用,但也做了不少實驗,基本可以認定其穩定,且“知名”,未來如果有更好的依賴管理方案,十有八九也是上面加個UI的殼吧

  當然還有一個問題擺在面前:jenkins似乎沒有dep的外掛程式?那隻能靠手寫指令碼了

  在往下看之前先確定你清楚兩個術語:我們把 github.com/apodemakeles/ugo 這玩意叫project,這是一個github上的倉庫,也代表一個項目,把github.com/apodemakeles/ugo/time 這玩意兒叫package,是project下面一個go 語言的包。current project表示當前你正在編寫的項目  

 

  前置知識點

  首先你要清楚,go中擷取依賴包都是通過執行go get命令,通過解析代碼中的import語句,去下載相應的原始碼到$GOPATH/src下,然後再進行install,安裝在$GOPATH/pkg下。所以你如果要對應maven中下載的java的jar包的話,那實際上等於go中的源碼和一堆.a檔案。go get的說明

  但go get的問題是沒有版本上的控制,今天你啟動並執行代碼,可能和明天在jenkins上產生的程式碼完全不一樣

  另外一個問題也是拜go語言的特性所賜,由於所有的依賴項必須在$GOPATH下有對應的源碼和.a檔案,所以在同一台機上的不同項目,沒法使用同一依賴項的不同版本。難道你要在不同的項目編譯時間git checkout一下?

  所以在go 1.5開始官方引入了go vendor機制,簡單點說就是在原來的project目錄下加一個vendor檔案夾,源碼都“照搬”到這裡,目錄結構不動。所有import優先使用vendor中的源碼。這個口子一開,一時間第三方紛紛推出自己的依賴解決工具了,比如我以前用過的govendor。 go vendor的說明

 

  dep一瞥

  要使用dep,首先要去github下載dep源碼,編譯成本地的可執行檔。確保你的$GOPATH/bin在你的PATH中,這樣就可以在命令列執行dep命令了。具體詳見 github 和 dep官方文檔  ,不在此贅述

  隨便建立一個項目,當然要在$GOPATH下,此時先不要寫代碼,至少不要import遠端依賴,執行

dep init

  你能看到project路徑下多了三個東西,一個vendor檔案夾,這個未來要來放current project的遠程依賴的原始碼,一個Gopkg.toml檔案,你可以暫時將其類比為pom檔案,或者npm的package.json檔案,還有一個Gopkg.lock檔案,這是啥?

  

  既然toml檔案類似於pom或者package.json,那按照裡面的注釋,試著添加一個依賴項試試,比如像我一樣

[[constraint]]  name = "github.com/apodemakeles/ugo"  version = "=0.1.0"

  看起來意思是需要下載ugo這個project,並且限制版本為0.1.0,下面執行

dep ensure

  這個指令類似於install,compile之類,就是根據依賴的配置內容,下載依賴,編譯依賴。指令很快就執行完了,但什麼也沒發生?這就是我之前說“暫時”類比為pom檔案的原因,dep中要結合toml和代碼中的import語句,才會真的下載,編譯依賴項。把下面的代碼貼到項目中去

package mainimport (    "fmt"    "github.com/apodemakeles/ugo/time")func main() {    fmt.Println(utime.NowUnixTS())}

  重新執行dep ensure,你會看到vendor中有了原始碼,而那個不知道是什麼的lock檔案裡是這樣的:

# This file is autogenerated, do not edit; changes may be undone by the next ‘dep ensure‘.[[projects]]  name = "github.com/apodemakeles/ugo"  packages = ["time"]  revision = "96e9671d8beda19466b4296a8939ebfe26210683"  version = "v0.1.0"[solve-meta]  analyzer-name = "dep"  analyzer-version = 1  inputs-digest = "4b0b8768bb38a412e1bbfd9952fe578e6f5b1a7469e3f44e444d66ca0c7ffaf6"  solver-name = "gps-cdcl"  solver-version = 1

   現在再正式解釋toml檔案和lock檔案:

  toml檔案記錄著current project依賴項project的約束,而並不是應該有哪些project,有哪些project還是要看import了哪些package。這個約束主要體現在到底要採用目標project的某個tag的版本(version),還是某個branch,或者是某個commit sha1(revision),後面我們會稱其"type", 這三個對於一個constraint只能選一個。你可以試試去掉toml的內容,執行dep ensure,依舊可以下載檔案到vendor,依舊會修改lock檔案

  實際上除了constraint,還有其他幾個約束, 比較重要的有required,ignored,override,前兩個本文不會重點說明,override會在後面重點說明。toml檔案的說明

  lock檔案是工具產生的,你不應該手工編輯,lock檔案的packages對應你import的內容,而revision(一定會有,和type無關)和version則為vendor中源碼的真實反映。lock檔案的說明

  注意到version那項寫的是"v0.1.0"了沒有?這是我github上代碼真正的tag,在toml檔案中的約束忽略了首字母v,直接拉取了tag為v0.1.0的代碼

  接下來把toml中的version改為“=0.1.1” 試試,假設你需要更高版本ugo的一個功能,需要升級依賴。執行完dep ensure你會發現vendor中變化了,lock檔案也變了

  以上就是dep的簡略介紹,我建議大家看一下 dep的運行機制 。裡面提到了dep ensure這個命令,可以類比為函數的執行:toml和import就好比一個函數的輸入,經過第一個函數resolving,輸出的是lock檔案,把其當做輸入傳入到第二個函數vendoring,輸出的是vendor檔案夾中的內容。這樣有助於大家的理解,在本文沒涉及到的情況,可以自己推理出來

 

  類比maven的一個方案

  以下是我假象的,沒經過驗證的一個實際開發中的工作流程

  首先,最好確保你的項目使用semver標準——語義化的版本標準,semver說明 ,這裡規定了版本號碼代表的意思,比較,以及一些操作符。還規定最初版本從0.1.0開始(看到此一陣驚喜,我們組蒙對了)

  然後,瞭解你依賴的代碼,需要使用哪個版本。如果是自己團隊的類庫,遵守semver標準,利用git的tag功能來表示version, 比如打一個v0.1.0的標籤

  之後規規矩矩的按照go的要求建立一個項目,並且搞定版本控制。在ignore中寫上 vendor/。這裡我曾疑問,lock是否也可以排除?實際上可以,但官方文檔曾經提到過"commit" lock檔案

  在項目根目錄執行dep init。產生這三個東西。如果你可以copy一份toml過來,dep init完全不用執行,只要有toml檔案,dep ensure完全可以產生其他兩個

  之後編碼,涉及到遠程依賴的內容,先在import中匯入,再選擇對應版本,在toml中修改,之後執行dep ensure

  如果開發過程中需要升級,修改toml檔案,再執行dep ensure

  CI工具拉去到代碼後,由於有toml檔案,直接執行dep ensure就可以了,解決完依賴最後再執行go build

  這麼看起來似乎全域只有這一個命令是必須

  注意,在我建議的方案中,toml檔案要寫成這樣 version=“0.1.0”,不要再0.1.0前加等號,為什麼這樣,你先最好瞭解瞭解go dep 的version rule

 

  version rules

  version rules在此,簡單說,三位版本號碼第一位為major,跨major可以不相容,後兩位為minor和patch,必須保證在同一個major範圍內向後相容。說白了我以前用1.2.1版本,現在換成1.2.2或者1.3.1了,一定要沒錯誤,但2.1.0不行(這就是咱們架構組的規則)

  在dep中, =0.1.0代表確定這個版本, ^0.1.0代表 >=0.1.0 且 <1.0.0

 

[[constraint]]  name = "github.com/apodemakeles/ugo"  version = "0.1.0"

 

  這種寫法等價於^0.1.0,預設的一般是推薦的方案,為什麼推薦這種呢?你可以理解,如果你按照semver的規範,沒跨major的一定向後相容,所以即使擷取到0.1.1, 0.2.0,也不會出錯。可為什麼不能像maven一樣固定一個座標呢?

 

  傳遞依賴

  假設A依賴於B的一個功能(A,B是project, jar,或者dll),我們用A->B來表示,如果有A->B->C,則B對C為直接依賴,A對C為傳遞依賴。如果恰巧A->B->C且A->C呢,但這兩個C又不是一個版本,會發生什嗎?

  在node.js中並沒有這種困擾,在依賴檔案夾中會有兩個C存在,然而對於C#,Java,Go這些語言,他們共同特點是current project下最終一個C只會有一個真實在磁碟上的產物,(dll, jar,帶路徑的.a),這時候就發生了依賴衝突問題

  在C#的MSBuild中,隨便選一個C(我感覺總是選高版本),產生dll,但在運行時,任何一個用到C.dll的dll,會檢查當前依賴的版本範圍內有沒有C的版本,如果沒有則在運行時出錯

  在Java的Maven中,會採用“最短路徑”原則,此時A->C這條路徑比較近,採用這條路徑的pom中的版本。但這就又引來一個問題,如果這條短路徑的C版本比較低,恰好B要用一個更高的C版本,因為裡面有一個新方法,在運行時就會出錯

  那Go的dep呢?如果你在toml檔案中這麼寫

[[constraint]]  name = "github.com/apodemakeles/B"  version = "=xxx"[[constraint]]  name = "github.com/apodemakeles/C"  version = "=0.1.1"

 

  此時不管B->C的版本比0.1.1高還是低(B->C也寫為version="=x.x.x"),dep都不允許,都會報錯,理由是“has no overlap”。如果B->C和A->C在一個major中,那就放開吧,直接寫 verion="x.x.x"

  這就是我推薦不帶等號的原因

  但有時候就是要確定某一個版本怎麼辦?可以使用toml中另一個約束override

[[constraint]]  name = "github.com/apodemakeles/B"  version = "=xxx"[[override]]  name = "github.com/apodemakeles/C"  version = "=0.1.1"

  這樣會強制使用0.1.1的版本的C,但有可能出現上面maven同樣的情況,需要你自己負責

  

  零零散散的細節

  截止到這裡基本我覺得重要的內容就都說完了,toml和lock中還有很多內容沒說,比如required,ignored,這些東西自己看就好。還有一些dep ensure的參數,比如-update,-add,我覺得大家不知道更好,可以統一使用規範,就只用dep ensure。而且官方也不建議把branch或者revision作為版本控制

  •   如果你想要一個0.0.1版本的project,而伺服器只有0.1.0以上的版本,即使使用範圍比如^,~,也擷取不到。我猜是因為dep把0.1.0作為最初始的版本
  •        dep status可以查看當前依賴資訊
  •   dep ensure真挺慢

  

Go語言入門——dep入門

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.