go modules 終於不會再被GOPATH綁死了 - iT 邦幫忙
文章推薦指數: 80 %
可以使用GOProxy來解決某些地區無法使用go get的問題. 以往需要將vendor目錄一起提交到git, 避免CI/CD去拉到外部的依賴包. go modules有build cache, ...
第11屆iThome鐵人賽
DAY
12
2
SoftwareDevelopment
下班加減學點Golang與Docker系列第
12篇
gomodules終於不會再被GOPATH綁死了
11th鐵人賽
go
雷N
2019-09-1900:42:5911125瀏覽
GoModules
Gomodules出現原因
解除對GOPATH的完全依賴,有gomodules就能在$GOPATH外開專案了.
不同環境或者是多專案,需要一套切換vendor目錄.
同一個依賴包的多種版本共存問題,加入了版本化的支援.
可以使用GOProxy來解決某些地區無法使用goget的問題.
以往需要將vendor目錄一起提交到git,避免CI/CD去拉到外部的依賴包.
gomodules有buildcache,在CIbuildserver上速度飛快.
環境準備
Goversion>=1.11
GO111MODULE=on(GoMOdule模式),使用gomodule,不諮詢GOPATH,只是下載下來的依賴包依然存在GOPATH/pkg/mod/底下.
GO111MODULE=off,這表示是GOPATH模式,查找依賴包順序如同昨天提的vendor目錄和GOPATH下.
GO111MODULE=auto,默認模式,在這模式下要使用gomodule,需要滿足兩個條件
該專案目錄不在GOPATH/src/下
當前或上一層目錄存在go.mod檔案
GoMododules對於匯入依賴包的影響
可以在$GOPATH之外的地方建立專案
該專案GoModule開啟後,下載的package會放在$GOPATH/pkg/mod下.
$GOPATH/bin的功能依然保持
GoModCommands
有兩種方式能定義一個正確的Gomodule
//在$GOPATH/src的目錄下,建立合理的module路徑
//進入該module目錄,執行下面命令
gomodinit[modulename]
///
```bash
//在任意地方,建立好module路徑
//在該目錄下,執行
gomodinit[folder/]modulename
就會在該專案下生出了go.mod文件了.
go.mod的一些名詞
module
定義模組路徑
go
定義預期的goversion
require
指定依賴的功能包和其版本或是更高版本[預設是最新版]
exclude
排除該功能包和其版本
replace
使用不同的依賴包版本替換原有的依賴包版本
註解
//單行註解
/*多行註解*/
indirect被間接導入的依賴包
modulemy/package
go1.12
requireother/thingv1.0.2//註解
requirenew/thing/v2v2.3.4//indirect
excludeold/thingv1.2.3
replacebad/thingv1.4.5=>good/thingv1.4.5
同專案的子目錄
因為go.mod在專案的根目錄下,子目錄的導入路徑會是該專案的導入路徑+子目錄路徑.
舉例:建立了ithome的專案,底下有一個ironman的子目錄.
則不需要也在子目錄建立gomodinit指令,Gobuild會自動辨識ironman這目錄是ithome的一部分.
GoModRequire
安裝一下logrus
gogetgithub.com/sirupsen/logrus
go.mod的內容
modulemodtest
go1.12
requiregithub.com/sirupsen/logrusv1.4.2//indirect
此時把v1.4.2改成v1.4.1
執行
gomoddownload
go.mod的內容
modulemodtest
go1.12
requiregithub.com/sirupsen/logrusv1.4.1//indirect
也會發生$GOPATH/pkg/mod/github.com/sirupsen目錄下,多了[email protected]和1.4.2版本的源碼
GoModExclude
go.mod的內容
modulemodtest
go1.12
requiregithub.com/sirupsen/logrusv1.4.2//indirect
excludegithub.com/gin-gonic/ginv1.4.0
gogetgithub.com/gin-gonic/gin
會發現應該是要下載當前最新板的v1.4.0的gin;但因為有excludegin1.4.0;
所以改成下載v1.3.9
go.mod的內容
modulemodtest
go1.12
require(
github.com/gin-contrib/ssev0.1.0//indirect
github.com/gin-gonic/ginv1.3.0//indirect
github.com/golang/protobufv1.3.2//indirect
github.com/mattn/go-isattyv0.0.8//indirect
github.com/sirupsen/logrusv1.4.2
github.com/ugorji/gov1.1.7//indirect
gopkg.in/go-playground/validator.v8v8.18.2//indirect
gopkg.in/yaml.v2v2.2.2//indirect
)
excludegithub.com/gin-gonic/ginv1.4.0
如果exclude指定gin的依賴功能包,該功能包會避開該版號作安裝
GoModReplace
如果有package被replace,則編譯時會使用對應的項目來作取代.
與require類似,可以指向令一個repo
又或是指向本地的一個目錄
gomodtest
//go.mod
modulemodtest
go1.12
requiregithub.com/sirupsen/logrusv1.4.2//indirect
//modtest.go
packagegomodtest
import(
log"github.com/sirupsen/logrus"
)
funcInit(){
log.Info("godmodtestinit")
}
funcExec(){
log.Info("godmodtestexec")
}
gomaintest
//go.mod
modulegithub.com/tedmax100/gomaintest
go1.12
replacegithub.com/tedmax100/modtest=>../gomodtest
//main.go
packagemain
import(
modtest"github.com/tedmax100/modtest"
)
funcmain(){
modtest.Exec()
}
執行結果
notes
Replace和Exclude都只對當前這module有影響,對其他功能包不會去影響到;
其他功能包自己的replace也不會影響到這包.
自己寫個共用依賴模組用在自己的專案試試看
依賴包專案
目錄結構/GOPATH/src/ithome
gomodinitgithub.com/tedmax100/ithome
因為我等等要推上github的repo中,這裡就如以前說的會有域名/目錄/專案...
這樣的層次關係.
gogetgithub.com/sirupsen/logrus
這裡跟govendorfetch有些不同了,再有gomodules專案內輸入goget.
預設會去抓最新的tag版本;如果沒有設立tag,就抓最新的commit版本.
go.sum這時候就會把logrus目錄下go.mod跟go.sum的依賴包跟其版本保存起來.
go.sum其實跟npm的package-lock.json有著一樣的功能.
go.mod(npm的package.json)定義我們指名要的依賴跟版本.
go.sum把go.mod的所有依賴包,每一個像是樹的根節點一樣,開始走訪去下載,並且紀錄關係在此.
ironman/ironman.go
packageironman
import(
log"github.com/sirupsen/logrus"
)
funcPrintIronMan(){
log.Info("hiironman")
}
ithome.go
packageithome
import(
//這裡因為我們定義的modname就這麼長,
//子目錄的導入路徑會是該專案的導入路徑+子目錄路徑.
"github.com/tedmax100/ithome/ironman"
log"github.com/sirupsen/logrus"
)
funcPrintItHome(){
log.Info("hiItHome")
ironman.PrintIronMan()
}
存檔,commit,推上github.
這裡我沒有打releasetag.
可執行的專案
目錄結構/GOPATH/src/gomod
gomodinitgomod
//下載依賴包
goget-ugithub.com/tedmax100/ithome
main.go
packagemain
import(
"github.com/tedmax100/ithome"
)
funcmain(){
ithome.PrintItHome()
}
執行main.go
把依賴包給作個releasetag,試試看
//作個更新
goget-ugithub.com/tedmax100/ithome
可以看到ithome這依賴包,從本來是紀錄commithash,變成是紀錄tag版本號了.
把依賴包給再進個commit,但tag還在v0.0.1
//作個更新
goget-ugithub.com/tedmax100/ithome
正如前面說的,他會先找tag/release有沒有,沒有才去找最新的commit.
但因為我們已經有tagv0.0.1,所以怎樣更新依賴,
只要沒有更新版的依賴被release就不會被更新.
那!就來進版吧
各版本有下載過得都會在go/pkg/mod/匯入包路徑底下
反悔了!想退回去指定的某一版
gogetgithub.com/tedmax100/[email protected]
因為快取有了,就不必重抓
也會順便更改go.mod和go.sum的內容
這外部的難用,我要用自己魔改過得,放在vendor底下的
或我怕外部有人偷偷在代碼放後門,我要用自己網路cache有的,複製到vendor下
gomodvendor
這會建立出一個vendor目錄,底下有現在go.mod依賴包的代碼.
我們改一下程式
gomod/vendor/github.com/tedmax100/ithome/ithome.go
packageithome
import(
"github.com/tedmax100/ithome/ironman"
log"github.com/sirupsen/logrus"
)
funcPrintItHome(){
//就改這行,存檔
log.Info("hiItHomefromvendor")
ironman.PrintIronMan()
}
開心的在terminal輸入
gorunmain.go
笑XD
因為只要啟用了gomodules,就會完全忽略了vendor目錄的存在,只讀取go.mod的內容.
那怎辦呢?
原本的指令gobuild,goinstall,gorunm,gotest啦
等等的加上-mod=vendor
多安裝一些依賴包
gogetgithub.com/go-sql-driver/mysql
結果最後根本沒有半個地方有import
怎辦,自己檢查每一個.go檔案,看哪些沒有import?
哪些依賴又沒有抓到呢?
#addmissingandremoveunusedmodule
gomodtidy
依賴包的module名稱能不能帶上版本號?
要是有breakingchange,新舊版本無法兼容呢?
ithome/go.mod
modulegithub.com/tedmax100/[email protected]//這裡打上版本號
go1.12
requiregithub.com/sirupsen/logrusv1.4.2
改個程式
packageithome
import(
"github.com/tedmax100/ithome/ironman"
log"github.com/sirupsen/logrus"
)
funcPrintItHome(){
log.Info("hiItHomeV0.0.7")
ironman.PrintIronMan()
}
funcPrintItHomeV2(){
log.Info("hiItHomeV2.0")
ironman.PrintIronMan()
}
存檔commit,push作release
跑到執行專案,執行
goget-ugithub.com/tedmax100/ithome
這時候發現,不會去下載這2.0.0版本的依賴包
因為版本號的v2.0.0,這個第一個數字表示主版本號,不同版本間若是無法兼容使用,
則建議是提昇這版本號,且建議遠端分之多上v2分支.
版本號若是v1.10.13,這個1表示主要版本號,10表示次要版本號,13表示修正版本號
且goget-u會檢查gomod的版本號,並不會主動去下載並提昇到不同的主要版本號的依賴包.
這裡import改成使用v2版
packagemain
import(
"github.com/tedmax100/ithome/v2"
)
funcmain(){
ithome.PrintItHome()
ithome.PrintItHomeV2()
}
gomodtidy
開心了,收工
gomod可以相當完美的跟vendor做切換並存.
有機會來玩玩看goproxy.
留言
追蹤
檢舉
上一篇
govendor好多依賴要管理
下一篇
Defer延遲調用
系列文
下班加減學點Golang與Docker
共30篇
目錄
RSS系列文
訂閱系列文
83人訂閱
26
GogRPC第一次接觸...
27
GinWithSwagger,懶人APIDoc生成神器
28
Go鍊結參數LDFLAGS
29
Go交叉編譯與Docker<3
30
CIwithGo&DockeronGitlab
完整目錄
尚未有邦友留言
立即登入留言
iT邦幫忙鐵人賽
參賽組數
1087組
團體組數
52組
累計文章數
20470篇
完賽人數
572人
鐵人賽最新文章
gotodie?那個goto到底能不能用啊?
2021/12/12更新
予焦啦!一夢終須醒......
盤點清查與檢測掃描-資通安全健診
[13th][Day23]httpresponseheader(下)
[13th][Day22]httpresponseheader(上)
[13th][Day21]golangcontext
股票怎麼選?掌握這原則,你也能找到強勢股
Gitpush
盤點清查與檢測掃描-安全性檢測
前往鐵人賽
技術推廣專區
[Day2]抓取每日收盤價
[Day1]基本工具安裝
利用python取得永豐銀行API的Nonce
[Day03]tinyML開發板介紹
永豐金融API測試員
[Day01]在享受tinyML這道美食之前
[Day3]使用ta-lib製作指標
[Day4]函數打包與買進持有報酬率試算
計算API所需要的參數:HashID
計算API所需要的參數:IV
前往鐵人賽
熱門問題
公司想要客製化一套ERP系統該選擇軟體開發?套裝系統?還是自行設立部門?
軟體工程師會被監控嗎
我有一個客戶中了mljx病毒勒索950美金我免費轉讓有人要接嗎?
訂房網站DB架構
(以解決)請問GMAIL群組.假如公司之前有業務群[email protected].有新職員收不到這個.如何把新業務加入
加班提醒視窗
想找PDF編輯工具,Adobe太貴了,請問還有其他推薦的替代方案嗎?
家中的網路配置
切割vlan網段方式
【已解決】如何安裝舊版本的VS2019
IT邦幫忙
站方公告
【2021iThome鐵人賽】登登登!究竟獎落誰家,2021iThome鐵人賽得獎名單正式揭曉
熱門tag
看更多
13th鐵人賽
12th鐵人賽
11th鐵人賽
鐵人賽
2019鐵人賽
2018鐵人賽
javascript
2017鐵人賽
windows
php
python
windowsserver
linux
c#
程式設計
資訊安全
css
vue.js
sql
分享
熱門回答
公司想要客製化一套ERP系統該選擇軟體開發?套裝系統?還是自行設立部門?
軟體工程師會被監控嗎
想找PDF編輯工具,Adobe太貴了,請問還有其他推薦的替代方案嗎?
防火牆如何設定DenyPolicy,以提高資安機制?
家中的網路配置
(以解決)請問GMAIL群組.假如公司之前有業務群[email protected].有新職員收不到這個.如何把新業務加入
RedhatEnterpriselinux5.5安裝Oracle問題
MYSQL如何將欄位中的json陣列資料拆分出來
請問目前php8版本的問題
切割vlan網段方式
熱門文章
予焦啦!一夢終須醒......
gotodie?那個goto到底能不能用啊?
盤點清查與檢測掃描-資通安全健診
再增加五隻狗勾
自己在家接收來自飛機的ADS-B訊號!
2021/12/12更新
第七隻狗勾
第九隻狗勾
第六隻狗勾
第八隻狗勾
一週點數排行
更多點數排行
海綿寶寶(antijava)
㊣浩瀚星空㊣(yoching)
居然解出來了(partyyaya)
raytracy(raytracy)
ccenjor(ccenjor)
mathewkl(mathewkl)
japhenchen(japhenchen)
純真的人(jer5173)
小山丘(a243318490)
fillano(fillano)
×
At
輸入對方的帳號或暱稱
Loading
找不到結果。
標記
{{result.label}}
{{result.account}}
關閉
延伸文章資訊
- 1Go Module與Go get 常用參數說明 - 關於網路那些事...
不支持module,會從GOPATH 或vendor 來尋找。如果不是在GOPATH 執行go mod init 則會報錯。 GO111MODULE=auto, 會檢查當前目錄是否啟用go.mo...
- 2Tutorial: Create a Go module - go.dev
Start by creating a Go module. In a module, you collect one or more related packages for a discre...
- 3深入Go Module之go.mod文件解析 - 鸟窝
Go module就是一组统一打版和发布的package的集合,在根文件下有go.mod文件定义module path和依赖库的版本,package以子文件夹的形式存在module中,对 ...
- 4【Golang】還在把library 放在專案裡?該跟上使用Go Module ...
Golang 在1.11 開始就推出了Go Module,如果你才剛開始使用Golang,建議直接使用Go Module,才不會被GOPATH 搞的滿頭包。本篇先以初始專案視角介紹,如果要從舊的...
- 5從一知半解到略懂Go modules
Go 1.11 之後提供go modules 讓我們可以不需要把專案程式碼放在 $GOPATH/src ... go.mod 用來紀錄Go module 的名稱與所使用的Go 版本,以及相依的G...