如何靈活地進行 Go 版本管理

本文談下我對 Go 版本管理的一些思考,並給大家介紹一個小工具,gvm。這個話題說起來也很簡單,但如果想用的爽,還是要稍微梳理下。

背景介紹

Go 的版本管理,並非包的依賴管理。平時的工作中,很多時候並不會遇到這樣的需求,所以可能並不是很明白它的價值。

簡單說下我寫這篇文章的背景吧。

最近幾周,Go 最重要的一則消息應該莫過 9月份 Go 1.13 的正式發佈。它的相關升級可查看 Go 1.13 正式發佈,看看都有哪些值得關注的特性 或官方 Go 1.13 Relase Notes

對於一名 gopher 而言,可能早已按捺不住自己那顆躁動的心,想盡快體驗下新版的升級項。但問題是,切換至新版 Go 通常會遇到一些問題,比如不同版本的環境配置,安裝的輔助工具和程序包在不同版本下可能會存在兼容或被覆蓋等問題。

我自然就希望有一套方案可以幫助我完成 Go 版本的切換,實現不同版本間環境的完全隔離。

思考方案

談到環境隔離,有很多方案可供選擇,如多主機、虛擬機、容器等技術。這些聽起來都挺不錯,都能實現需求。但如果只是爲了 Go 版本管理,完全可以自己實現。

多版本切換,主要是不同版本環境變量的隔離。Go 1.10 之前,我們關心的變量有 GOROOT、GOPATH 和 PATH。Go 1.10 之後,GOROOT 已經默認爲 go 的當前安裝路徑,只要考慮 GOPATH 和 PATH 即可。

最近,剛答過一個關於 Go 環境變量的問題,查看回答。其中對每個變量的作用進行了比較細緻的描述。

如何實現

現在,我要實現我自己電腦上的兩個版本的 Go 自由切換,該如何做呢?

假設它們分別位於 ~/.goversions/sdk/ 目錄下的 go1.11/ 和 go1.13/。我現在要啓用 go 1.11,運行如下命令即可:

$ export PATH=~/.goversions/sdk/go1.11/bin/:$PATH

此時,GOROOT 已經自動識別,爲 ~/.goversions/sdk/go1.11/。Go 相關的工具鏈,源碼,標準庫都在這個目錄下。

但除 Go 自帶外,還有其他第三方標準庫、編譯生成的庫文件等內容,它們都位於 GOPATH 下,如果不設置,默認爲 ~/go,在切換多版本的時候,就會產生混亂。我們可以爲每個版本單獨設置個 GOPATH。

如 go1.11,設置 GOPATH 爲 ~/.goversions/gopath/go1.11-global/。

$ mkdir ~/.goversions/gopath/go1.11-global/
$ export GOPATH=~/.goversions/gopath/go1.11-global/

一個獨立的環境創建好了。

如果現在要切換至 go 1.13,幾個命令即可搞定。

$ export PATH=~/.goversions/sdk/go1.13/bin/:$PATH
$ mkdir -pv ~/.goversions/gopath/go1.13-global/
$ export GOPATH=~/.goversions/gopath/go1.13-global/ 

切換成功。

雖然,已經實現了需求,但總覺得用起來非常不爽。爲了操作方便,其實可以把上面的思路提煉成 shell 腳本,整理成一套工具。

是不是蠢蠢欲動,想試一下?

但很遺憾,已經沒這個機會了,因爲這個工具已經有人開發了,思路類似,但卻比這裏描述的要強,它就是 gvm, 地址 moovweb/gvm

什麼是 gvm

gvm,即 Go Version Manager,Go 版本管理器,它可以非常輕量的切換 Go 版本。對比其他語言,通常也有類似的工具,如 NodeJS 的 NVM,Python 的 virtualenv 等。

gvm 不僅包含上面提到的版本切換,還可以直接通過源碼編輯安裝任意版本的 Go,當然最好是 1.5 及之後版本,原因後面解釋。

一件比較尷尬的點,gvm 產生背景並非是爲了 Go 在不同版本間的切換,開發團隊當初開發這個工具主要爲了解決項目的依賴問題,通過切換環境實現包依賴的切換。下面,我會演示如何做到這一點。

但問題是,現在 Go 的依賴管理已經日趨完善,官方的 go module 也越來越好用,GOPATH 在被逐漸弱化,gvm 似乎也就只剩下幫我們快速體驗不同 Go 版本的功能還有點價值。

廢話說了那麼多,開始正式體驗下這個工具吧。

如何安裝

安裝很簡單,只要如下一行命令即可搞定。

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

輸出顯示:

Cloning from https://github.com/moovweb/gvm.git to /home/vagrant/.gvm
which: no go in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin)
No existing Go versions detected
Installed gvm v1.0.22

Please restart your terminal session or to get started right away run
 `source /home/vagrant/.gvm/scripts/gvm`

安裝完成!

重啓控制檯或執行 source $HOME/.gvm/scripts/gvm 即可啓用 gvm。

提醒下,不同操作系統還需要相應的依賴項要裝,具體查看 項目說明 的介紹。 這裏面沒有提到 Windows,不知道可不可用。

gvm 安裝 Go

gvm 通過從 github 下載源碼編譯 Go 的安裝。而版本則是基於源碼中的 tag。因爲 1.5 版本及之後,Go 已經實現了自編譯,因而要使用 gvm 安裝 Go,我們要提前有可用的 Go 環境。

Go 的安裝可以閱讀我之前的一篇文章 詳細聊聊如何安裝 Go,我認爲介紹的還算詳細。

Go 安裝完成,就可以使用 gvm 隨意安裝切換任意版本的 Go 了。

$ gvm install go1.11

等待運行完成即可。

首次安裝的時間可能會比較久,主要取決於你的網絡,因爲第一次需要從 github 下載源碼。

查看版本

首先,查看下我的系統已經安裝哪些 Go 版本有哪些吧,相關命令 gvm list。

$ gvm list

gvm gos (installed)

   go1.11
   go1.12
   go1.13
   go1.13beta1

安裝了 4 個版本,其中,go1.13beta1 是非穩定版本,所以說,如果我們想盡快嘗試 go 的新特性,gvm 還是很便捷的。

除了查看已安裝的版本,還可以通過 gvm listall 查看所有版本,版本來源於源碼中的 tag 標籤。

$ gvm listall

gvm gos (available)

   go1
   go1.0.1
   go1.0.2
   go1.0.3
   go1.1

   ...

   go1.13
   go1.13beta1
   go1.13rc1
   go1.13rc2

但這個操作在 mac 上無法執行,gvm 的實現中用到了 Linux 的 sort 命令,它與 mac 上的 sort 不兼容。

怎麼解決?

安裝個軟件 coreutils, 它之中有個 qsort 命令可用。通過 brew install coreutils 可直接安裝。然後,修改下文件 $HOME/.gvm/scripts/function/tool,將其中的 sort 修改爲 qsort 即可。

選擇版本

選擇啓用的版本就非常簡單了。如下:

$ gvm use go1.11 [--default]

啓用成功後,可以通過 go version 和 go env 確認下。如果想默認一個版本,加上 --default 設置即可。

包環境管理

gvm 除了 Go 版本的管理,還可以管理包環境,相關命令是 pkgenv 和 pkgset。如果沒使用包依賴管理工具,它也是挺方便的。

演示個例子,假設我們要創建一個新的項目 blog,可提前創建相應的環境。

$ gvm pkgset create blog  # 創建
$ gvm pkgset use blog     # 啓用

閒雜,我們通過 go get 安裝的包都會默認在 blog 環境下。基於的原理是 go get 默認會把安裝的放在 GOPATH 中的第一個目錄下。

好了,就介紹這麼多吧。有興趣的朋友可以再研究研究。畢竟在有了 go mod 之後,這個功能以後是基本不會用了。

gvm 目錄結構

gvm 是 shell 編寫,默認是安裝在 $HOME/.gvm/ 目錄下。查看下它的目錄結構會有助我們瞭解它的實現。

其中幾個主要的目錄,如下:

archive             # go 源碼
bin                 # gvm 可執行文件
environments        # 不同環境的環境變量配置
scripts             # gvm 的子命令腳本
logs                # 日誌信息
pkgsets             # 每個獨立環境 gopath 所在路徑

在研究了 gvm 的實現後,我們會發現,這一套思路其實也適用於其他很多工具的版本管理。如果之後再遇到同樣的需求,即使我們沒有現成的工具,自己實現一套也是可以的。

總結

本文從我的需求出發,引出瞭如何靈活地進行管理 Go 版本的話題。

以往的經驗告訴我,既然其他語言都有工具實現這樣的需求,Go 也應該有。搜索了下,找到了 gvm。雖說我在使用它的時候,發現了一些 bug 與體驗不好的地方,但總體而言,已經足夠滿足我的需求。

參考

Go 語言多版本安裝及管理利器 - gvm
moovweb/gvm
gvm + go mod

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章