如何灵活地进行 Go 版本管理

本文首发于个人博客,若是以为有用,欢迎点赞收藏,让更多的朋友看到。git

本文谈下我对 Go 版本管理的一些思考,并给你们介绍一个小工具,gvm。这个话题提及来也很简单,但若是想用的爽,仍是要稍微梳理下。github

背景介绍

Go 的版本管理,并不是包的依赖管理。平时的工做中,不少时候并不会遇到这样的需求,因此可能并非很明白它的价值。golang

简单说下我写这篇文章的背景吧。web

最近几周,Go 最重要的一则消息应该莫过 9月份 Go 1.13 的正式发布。它的相关升级可查看 Go 1.13 正式发布,看看都有哪些值得关注的特性 或官方 Go 1.13 Relase Notesshell

对于一名 gopher 而言,可能早已按捺不住本身那颗躁动的心,想尽快体验下新版的升级项。但问题是,切换至新版 Go 一般会遇到一些问题,好比不一样版本的环境配置,安装的辅助工具和程序包在不一样版本下可能会存在兼容或被覆盖等问题。bash

我天然就但愿有一套方案能够帮助我完成 Go 版本的切换,实现不一样版本间环境的彻底隔离。markdown

思考方案

谈到环境隔离,有不少方案可供选择,如多主机、虚拟机、容器等技术。这些听起来都挺不错,都能实现需求。但若是只是为了 Go 版本管理,彻底能够本身实现。网络

多版本切换,主要是不一样版本环境变量的隔离。Go 1.10 以前,咱们关心的变量有 GOROOT、GOPATH 和 PATH。Go 1.10 以后,GOROOT 已经默认为 go 的当前安装路径,只要考虑 GOPATH 和 PATH 便可。session

最近,刚答过一个关于 Go 环境变量的问题,查看回答。其中对每一个变量的做用进行了比较细致的描述。curl

如何实现

如今,我要实现我本身电脑上的两个版本的 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


欢迎关注个人公众号!

相关文章
相关标签/搜索