Go 虚拟环境管理工具 gvm 原理介绍与使用指南

2024-01-24 15:04

本文主要是介绍Go 虚拟环境管理工具 gvm 原理介绍与使用指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文谈下我对 Go 版本管理的一些想法。让后,我将介绍一个小工具,gvm。这个话题说起来也很简单,但如果想用的爽,还是要稍微梳理下。

背景介绍

Go 的版本管理,并非包的依赖管理,而且关于如何在不同的 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.22Please 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 环境。

好在,gvm 也提供直接通过下载二进制包的方式安装 Go。

❯ gvm install go1.19 --binary
Installing go1.19 from binary source

Go 安装完成,就可以使用 gvm 随意安装切换任意版本的 Go 了。

$ gvm install go1.11

等待运行完成即可。

首次安装的时间可能会比较久,主要取决于你的网络,因为第一次需要从 github 下载源码。

查看版本

首先,查看下我的系统已经安装哪些 Go 版本有哪些吧,相关命令 gvm list。

$ gvm listgvm gos (installed)go1.11go1.12go1.13go1.13beta1

安装了 4 个版本,其中,go1.13beta1 是非稳定版本,所以说,如果我们想尽快尝试 go 的新特性,gvm 还是很便捷的。

除了查看已安装的版本,还可以通过 gvm listall 查看所有版本,版本来源于源码中的 tag 标签。

$ gvm listallgvm gos (available)go1go1.0.1go1.0.2go1.0.3go1.1...go1.13go1.13beta1go1.13rc1go1.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

博文地址:Go 虚拟环境管理工具 gvm

这篇关于Go 虚拟环境管理工具 gvm 原理介绍与使用指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/640063

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

java程序远程debug原理与配置全过程

《java程序远程debug原理与配置全过程》文章介绍了Java远程调试的JPDA体系,包含JVMTI监控JVM、JDWP传输调试命令、JDI提供调试接口,通过-Xdebug、-Xrunjdwp参数配... 目录背景组成模块间联系IBM对三个模块的详细介绍编程使用总结背景日常工作中,每个程序员都会遇到bu

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数