go1.12下Go mod使用實(shí)踐

Go Module是Go會在1.12中正式推出的包管理機(jī)制函筋。

Go mod 簡介

Golang一直存在一個被人詬病的問題是缺少一個官方的包依賴管理工具。從我個人的角度上來看存在兩個問題:

  1. GOPATH特性對于多工程的情況下积糯,支持不算友好。
  2. GOPATH無法對依賴包進(jìn)行有效的版本管理谦纱,沒有任何地方能夠表明依賴包的具體版本號看成,無法簡單清晰獲取到有效的依賴包版本信息等。

在Go1.11時,官方推出了go mod作為官方的依賴管理工具跨嘉。而go mod與之前的利用vendor特性的依賴管理工具的不同點(diǎn)在于川慌,go mod 更類似于maven這種本地緩存庫的管理方式,不論你有多少個工程,只要你引用的依賴的版本是一致的祠乃,那么在本地就只會有一份依賴文件的存在梦重。而vendor即使依賴的版本是相同的,但如果在不同的工程中進(jìn)行了引用亮瓷,也會在工程目錄下的vendor產(chǎn)生一份依賴文件琴拧。

所以Golang在1.11版本中引入了go mod機(jī)制,在統(tǒng)一的位置對依賴進(jìn)行管理嘱支。

go mod不同于以往基于GOPATH和Vendor的構(gòu)建方式蚓胸,其主要是通過GOPATH/pkg/mod下的緩存包來對工程進(jìn)行構(gòu)建挣饥。在Go 1.11中已經(jīng)可以使用,同以往新添加的功能一樣沛膳,go mod 可以通過GO111MODULE來控制是否啟用亮靴,GO111MODULE有一下三種類型。

  • on 所有的構(gòu)建于置,都使用Module機(jī)制
  • off 所有的構(gòu)建,都不使用Module機(jī)制贞岭,而是使用GOPATH和Vendor
  • auto 在GOPATH下的工程八毯,不使用Module機(jī)制,不在GOPATH下的工程使用

Go mod化處理步驟

這里我主要說一下瞄桨,對舊工程如何進(jìn)行g(shù)o mod化處理话速。通過網(wǎng)上搜索的文檔加上自我實(shí)踐,我總結(jié)成了以下三個步驟芯侥。對于新工程的處理可直接從第二部分開始泊交。

  • 將需要進(jìn)行版本管理的代碼從GOPATH路徑下移出
  • 在項(xiàng)目的根目錄下使用命令go mod init projectName
  • 在該目錄下執(zhí)行g(shù)o build main.go

從GOPATH中移出工程

這一步其實(shí)是不一定需要的,不過個人認(rèn)為可以將工程從GOPATH下移出柱查,單獨(dú)存放廓俭。只在GOPATH/pkg/mod目錄下只存放依賴文件。

在go1.12環(huán)境下唉工,我試驗(yàn)了一下環(huán)境變量GO111MODULE還是起作用的研乒。但是編譯時默認(rèn)為使用Module機(jī)制進(jìn)行編譯(即GO111MODULE=on)。

  1. 如果工程中存在go.mod文件淋硝,編譯時是從GOPATH/pkg/mod下查找依賴雹熬。
  2. 如果主動使用export GO111MODULE=off命令不使用Module機(jī)制,進(jìn)行編譯就會從GOPATH/src下查找依賴。會產(chǎn)生以下輸出谣膳。(編譯失敗是由于相應(yīng)目錄下無依賴文件)
    /usr/local/Cellar/go/1.12.5/libexec/src/golang.org/x/tools/internal/tool (from $GOROOT)
    /Users/dx/go/src/golang.org/x/tools/internal/tool (from $GOPATH)

初始化go mod

在這一步根據(jù)我的實(shí)踐竿报,需要說一下。一般網(wǎng)上的資料都是建議在工程的根目錄下執(zhí)行g(shù)o mod init projectName命令继谚。在執(zhí)行g(shù)o mod化之后烈菌,所有的引用都不再是以GOPATH為相對路徑的引用了,而是變成了以go.mod中初始化的項(xiàng)目名為起始的引用花履。

示例:

未使用go mod前僧界,當(dāng)前工程路徑和GOPATH為workspace/testmod,即當(dāng)前工程的結(jié)構(gòu)如下:

├── bin
├── pkg
└── src
    ├── api
    │   └── supply
    │       └── location
    │           └── location.go
    └── main.go

location.go

package location

import (
        "fmt"
)

func Hi(name string) string {
        return fmt.Sprintf("hello %s",name)
}

在main.go中引用location.go時臭挽,import中路徑為"api/supply/location"捂襟。

package main

import(
        "api/supply/location"
        "fmt"
)

func main() {
        fmt.Println(location.Hi("test"))
}

使用go mod后,當(dāng)前工程路徑為workspace/testmod,在src目錄下執(zhí)行g(shù)o mod init testmod后,在main.go中引用location.go時,import中路徑需要變更為"testmod/api/supply/location",否則編譯時會報(bào)錯build command-line-arguments: cannot load api/supply/location: cannot find module providing package api/supply/location

go.mod

module testmod

go 1.12

main.go

package main

import(
        "api/supply/location"
        "fmt"
)

func main() {
        fmt.Println(location.Hi("test"))
}

執(zhí)行g(shù)o build拉去依賴并編譯

這一步的主要作用是拉去代碼中的依賴文件欢峰。將會看到類似如下的輸出

$ go build main.go
go: finding github.com/mitchellh/go-wordwrap latest
go: finding github.com/maruel/panicparse/stack latest
go: finding github.com/nsf/termbox-go latest

再執(zhí)行完了之后葬荷,查看go.mod文件會發(fā)現(xiàn)產(chǎn)生了類似如下的內(nèi)容:

module github.com/test/testmod

require (
    github.com/gizak/termui v2.2.0+incompatible
    github.com/maruel/panicparse v1.1.1 // indirect
    github.com/mattn/go-runewidth v0.0.3 // indirect
    github.com/mitchellh/go-wordwrap v0.0.0-20180828145344-9e67c67572bc // indirect
    github.com/nsf/termbox-go v0.0.0-20180819125858-b66b20ab708e // indirect
    github.com/spf13/pflag v1.0.2 // indirect
)

至此涨共,對于一個項(xiàng)目的go mod化就已經(jīng)完成了。對于go.mod文件中的內(nèi)容會在下一節(jié)進(jìn)行敘述宠漩。

go mod命令簡介

這個子命令用來處理 go.mod 文件举反,上一小節(jié)我們已經(jīng)見過 go mod init 了。下面介紹下幾個用得到的命令扒吁。

  • go mod edit -fmt 格式化 go.mod 文件火鼻。

  • go mod edit -require=path@version 添加依賴或修改依賴版本,這里支持模糊匹配版本號雕崩,詳情可以看下文 go get 的用法魁索。()

  • go mod edit -replace=path1@version=path2@version使用path2路徑的包來代替path1路徑的包。

    對于國內(nèi)用戶來說盼铁,手動維護(hù)這個文件是必然的粗蔚,因?yàn)槟阈枰?golang.org/x/text 替換成 github.com/golang/text。示例

    go mod edit -replace=golang.org/x/sys@v0.0.0-20180830151530-49385e6e1522=github.com/golang/sys@v0.0.0-20180830151530-49385e6e1522

  • go mod tidygo.mod 刪除不需要的依賴饶火、新增需要的依賴鹏控,這個操作不會改變依賴版本。

  • go mod download命令會根據(jù)go.mod文件下載對應(yīng)的依賴項(xiàng)到GOPATH/pkg/mod路徑下肤寝。

go get 命令

在Go1.11后当辐,可以用此命令來獲取依賴的特定版本,可以用來升級和降級依賴鲤看。會自動修改 go.mod 文件瀑构,而且依賴的依賴版本號也可能會變。在 go.mod 中使用 exclude 排除的包刨摩,不能 go get 下來寺晌。

與以前不同的是,新版 go get 可以在末尾加 @ 符號澡刹,用來指定版本呻征。go get 命令需在go.mod同級目錄下執(zhí)行,否則會報(bào)出錯誤go: cannot use path@version syntax in GOPATH mode罢浇。而且在使用go get下載依賴時陆赋,要求倉庫必須用 vX.Y.Z 格式打 tag,以下是簡單羅列的匹配規(guī)則嚷闭。

go get github.com/gorilla/mux    # 匹配最新的一個 tag
go get github.com/gorilla/mux@latest    # 和上面一樣
go get github.com/gorilla/mux@v1.6.2    # 匹配 v1.6.2
go get github.com/gorilla/mux@e3702bed2 # 匹配 v1.6.2
go get github.com/gorilla/mux@c856192   # 匹配 c85619274f5d
go get github.com/gorilla/mux@master    # 匹配 master 分支

latest 匹配最新的 tag攒岛。

v1.2.6 完整版本的寫法。

v1.2 匹配帶這個前綴的最新版本胞锰,如果最新版是 1.2.7灾锯,它們會匹配 1.2.7。

c856192 版本 hash 前綴嗅榕、分支名顺饮、無語義化的標(biāo)簽吵聪,在 go.mod 里都會會使用約定寫法 v0.0.0-20180517173623-c85619274f5d,也被稱作偽版本兼雄。

go get 可以模糊匹配版本號吟逝,但 go.mod 文件只體現(xiàn)完整的版本號,即 v1.2.0赦肋、v0.0.0-20180517173623-c85619274f5d块攒,只不過不需要手寫這么長的版本號,用 go get 或上文的 go mod edit -require 模糊匹配即可佃乘,它會把匹配到的完整版本號寫進(jìn) go.mod 文件囱井。(在執(zhí)行g(shù)o get 命令后,會自動修改go.mod文件)

go build 命令

  • go build -mod=readonly 防止隱式修改 go.mod恕稠,如果遇到有隱式修改的情況會報(bào)錯,可以用來測試 go.mod 中的依賴是否整潔扶欣,但如果明確調(diào)用了 go mod鹅巍、go get 命令則依然會導(dǎo)致 go.mod 文件被修改。
  • go build -mod=vendor 在開啟模塊支持的情況下料祠,用這個可以退回到使用 vendor 的時代骆捧。

使用本地包進(jìn)行開發(fā)測試

單獨(dú)把這個拿出來說一下的原因是,基于我們自己項(xiàng)目的一個需求髓绽,我們是把一些公共的配置與函數(shù)部分統(tǒng)一成了一個單獨(dú)的公共庫敛苇,但是在go mod的情況下,就會出現(xiàn)一個問題顺呕,每次對公共庫的修改測試都需要走提交更新枫攀、修改go.mod文件、更新本地依賴才可以進(jìn)行測試株茶,這樣明顯是及其不方便的来涨。所以通過查詢資料和實(shí)踐,發(fā)現(xiàn)可以通過使用replace使用本地包來進(jìn)行測試启盛。

使用本地包代提線上包進(jìn)行測試的方法,例如修改公共庫commons,在go mod中我可以增加一條這樣的替換

replace github.com/test/commons v1.1.1 => /Users/test/Workspace/bizgocommons蹦掐,這樣就把使用的報(bào)的路徑指向了本地的包,省去了提交修改在下載的麻煩了僵闯。

注意:本地包在使用的時候不需要帶上版本信息卧抗。

go mod時遇到的問題

  1. 在工程中g(shù)o.etcd.io/etcd依賴時,在本地環(huán)境(mac)下可以成功編譯鳖粟,放到docker環(huán)境下(基礎(chǔ)鏡像為go1.12)的情況加會出現(xiàn)以下的錯誤信息社裆。
verifying go.etcd.io/etcd@v3.3.12+incompatible: checksum mismatch
    downloaded: h1:V6PRYRGpU4k5EajJaaj/GL3hqIdzyPnBU8aPUp+35yw=
    go.sum:     h1:xR2YQOYo5JV5BMrUj9i1kcf2rEbpCQKHH2sKTtpAHiQ=

使用download中的值替換后,即可在docker下成功編譯向图。

通過實(shí)踐和上網(wǎng)查詢浦马,個人覺得原因是mac和docker環(huán)境下下載的etcd是有區(qū)別的时呀,可能含有某些操作系統(tǒng)相關(guān)的內(nèi)容。導(dǎo)致兩者的校驗(yàn)值不同晶默。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谨娜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子磺陡,更是在濱河造成了極大的恐慌趴梢,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件币他,死亡現(xiàn)場離奇詭異坞靶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蝴悉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門彰阴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拍冠,你說我怎么就攤上這事尿这。” “怎么了庆杜?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵射众,是天一觀的道長。 經(jīng)常有香客問我晃财,道長断盛,這世上最難降的妖魔是什么罗洗? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任钢猛,我火速辦了婚禮栖博,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘厢洞。我一直安慰自己躺翻,他們只是感情好丧叽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著公你,像睡著了一般踊淳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天迂尝,我揣著相機(jī)與錄音脱茉,去河邊找鬼。 笑死垄开,一個胖子當(dāng)著我的面吹牛琴许,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溉躲,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼榜田,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锻梳?” 一聲冷哼從身側(cè)響起箭券,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疑枯,沒想到半個月后辩块,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荆永,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年废亭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屁魏。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡滔以,死狀恐怖捉腥,靈堂內(nèi)的尸體忽然破棺而出氓拼,到底是詐尸還是另有隱情,我是刑警寧澤抵碟,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布桃漾,位于F島的核電站,受9級特大地震影響拟逮,放射性物質(zhì)發(fā)生泄漏撬统。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一敦迄、第九天 我趴在偏房一處隱蔽的房頂上張望恋追。 院中可真熱鬧,春花似錦罚屋、人聲如沸苦囱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撕彤。三九已至,卻和暖如春猛拴,著一層夾襖步出監(jiān)牢的瞬間羹铅,已是汗流浹背蚀狰。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留职员,地道東北人麻蹋。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像廉邑,于是被迫代替她去往敵國和親哥蔚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容