簡(jiǎn)潔的 Go 多版本管理機(jī)制
本文轉(zhuǎn)載自微信公眾號(hào)「Golang技術(shù)分享」,作者機(jī)器鈴砍菜刀。轉(zhuǎn)載本文請(qǐng)聯(lián)系Golang技術(shù)分享公眾號(hào)。
一門充滿生機(jī)的編程語(yǔ)言,一定是不斷進(jìn)化向前的。隨著 Go 項(xiàng)目的持續(xù)發(fā)展,它目前已經(jīng)發(fā)布到了 1.17 大版本,而且每個(gè)大版本內(nèi)還會(huì)有不少小版本的迭代。對(duì)于 Go 的版本更新,我們?cè)撊绾巫龊枚喟姹竟芾怼?/p>
多版本管理的重要性
這里簡(jiǎn)單列舉幾個(gè)我們需要 Go 多版本管理的理由。
- 穩(wěn)定性考量:雖然 Go1 一直在良好地遵守向后兼容準(zhǔn)則,但通?;诜€(wěn)定性考慮,我們并不會(huì)直接升級(jí)到最新版本。
- 多項(xiàng)目開發(fā):各項(xiàng)目依賴的 Go 版本不一致。
- 版本兼容:測(cè)試代碼前后兼容性,或者確保 bug 修復(fù)在不同 Go 版本的正確性,對(duì)于開源項(xiàng)目,保證版本兼容性非常重要。
- 學(xué)習(xí)新特性:例如雖然我們還在使用 Go 1.16 開發(fā),但是并這不能阻礙你嘗鮮 Go 1.17 新功能。
如何多版本管理
我們需要有兩個(gè)先決條件
- 已經(jīng)安裝好了某版本的 Go
- 安裝好了 git
安裝
運(yùn)行g(shù)o get golang.org/dl/go
- $ go install golang.org/dl/go<version>@latest
通過包裝器,下載特定 Go 版本和它對(duì)應(yīng)的工具鏈。
- $ go download
例如安裝1.14.12版本,可以這樣執(zhí)行。
- $ go install golang.org/dl/go1.14.12@latest
- $ go1.14.12 download
使用
使用包裝器 go1.14.12,我們可以基于 Go v1.14.12 進(jìn)行構(gòu)建和測(cè)試。
- $ go1.14.12 mod init hello
- go: creating new go.mod: module hello
- $ echo 'package main; import "fmt"; func main() { fmt.Println("Hello, World") }' > hello.go
- $ go1.14.12 build
- $ ./hello
- Hello, World
當(dāng)然,如果你想讓 Go v1.14.12 ”喧賓奪主“,成為 go 命令的代言人,可以這樣做。
- $ go version
- go version go1.17 darwin/amd64
- $ export GOROOT=$(go1.14.12 env GOROOT)
- $ export PATH=${GOROOT}/bin:$PATH
- $ go version
- go version go1.14.12 darwin/amd64
這個(gè)go1.14.12 env GOROOT 路徑就是 Go v1.14.12 版本的內(nèi)容。所以,如果我們想卸載這個(gè)版本,直接將該路徑文件夾刪除即可;想閱讀該版本源碼,直接查看該路徑下的src/內(nèi)容即可 。
獲取最新開發(fā)版本
有一個(gè)特別的版本標(biāo)記:gotip,它用于安裝最新的開發(fā)版本。
- $ go install golang.org/dl/gotip@latest
- $ gotip download
可以看到,當(dāng)前拉取到的最新的開發(fā)版本是 go1.18-1afa432。
實(shí)現(xiàn)思路
實(shí)現(xiàn)多版本下載安裝的秘訣就在于 https://go.googlesource.com/dl 這個(gè)倉(cāng)庫(kù),https://github.com/golang/dl 是它的鏡像庫(kù)。
查看倉(cāng)庫(kù)代碼,我們能看到一系列版本目錄
隨意選擇一個(gè)版本進(jìn)入,會(huì)發(fā)現(xiàn)存在一個(gè) main.go 文件
而 main.go 文件內(nèi)容如下
我們通過go install golang.org/dl/go1.14.12@latest下載的 go1.14.12 包裝器就是這個(gè) main.go 編譯而成。
因此,我們后續(xù)通過 go1.14.12 包裝器下載和運(yùn)行的邏輯就在于internal/version包中的 Run 方法了。
- // Run runs the "go" tool of the provided Go version.
- func Run(version string) {
- log.SetFlags(0)
- // 獲取 Go 安裝目錄
- root, err := goroot(version)
- if err != nil {
- log.Fatalf("%s: %v", version, err)
- }
- // 執(zhí)行 go<version> download 命令時(shí)邏輯
- if len(os.Args) == 2 && os.Args[1] == "download" {
- if err := install(root, version); err != nil {
- log.Fatalf("%s: download failed: %v", version, err)
- }
- os.Exit(0)
- }
- // 判斷該版本 Go 安裝狀態(tài)
- if _, err := os.Stat(filepath.Join(root, unpackedOkay)); err != nil {
- log.Fatalf("%s: not downloaded. Run '%s download' to install to %v", version, version, root)
- }
- // 運(yùn)行該版本 Go
- runGo(root)
- }
鑒于篇幅原因, 下載的install和運(yùn)行的runGo函數(shù)邏輯本文就不再展開了,想深入了解的同學(xué)可以自行探索。
另外,為了讓每個(gè)版本都有一個(gè) Go 包裝器主程序(避免重復(fù)的手工操作),這里使用了一個(gè)幫助命令genv:可以快速生成對(duì)應(yīng)版本的包裝器代碼
總結(jié)
本文介紹了 Go 官方提供的多版本管理方案,包括使用、安裝、卸載等,可以感受到它的簡(jiǎn)潔與高效。同時(shí)我們簡(jiǎn)單查看了這一套實(shí)現(xiàn)代碼邏輯。
最后,希望本文內(nèi)容能夠助你用好 Go 多版本管理,歡迎留言討論。