简洁的 Go 多版本管理机制

开发 后端
本文介绍了 Go 官方提供的多版本管理方案,包括使用、安装、卸载等,可以感受到它的简洁与高效。同时我们简单查看了这一套实现代码逻辑。

[[440441]]

本文转载自微信公众号「Golang技术分享」,作者机器铃砍菜刀。转载本文请联系Golang技术分享公众号。

一门充满生机的编程语言,一定是不断进化向前的。随着 Go 项目的持续发展,它目前已经发布到了 1.17 大版本,而且每个大版本内还会有不少小版本的迭代。对于 Go 的版本更新,我们该如何做好多版本管理。

多版本管理的重要性

这里简单列举几个我们需要 Go 多版本管理的理由。

  • 稳定性考量:虽然 Go1 一直在良好地遵守向后兼容准则,但通常基于稳定性考虑,我们并不会直接升级到最新版本。
  • 多项目开发:各项目依赖的 Go 版本不一致。
  • 版本兼容:测试代码前后兼容性,或者确保 bug 修复在不同 Go 版本的正确性,对于开源项目,保证版本兼容性非常重要。
  • 学习新特性:例如虽然我们还在使用 Go 1.16 开发,但是并这不能阻碍你尝鲜 Go 1.17 新功能。

如何多版本管理

我们需要有两个先决条件

  • 已经安装好了某版本的 Go
  • 安装好了 git

安装

运行go get golang.org/dl/go 命令将下载特定 Go 版本的包装器。

  1. $ go install golang.org/dl/go<version>@latest 

通过包装器,下载特定 Go 版本和它对应的工具链。

  1. $ go download 

例如安装1.14.12版本,可以这样执行。

  1. $ go install golang.org/dl/go1.14.12@latest 
  2. $ go1.14.12 download 

使用

使用包装器 go1.14.12,我们可以基于 Go v1.14.12 进行构建和测试。

  1. $ go1.14.12 mod init hello 
  2. go: creating new go.mod: module hello 
  3. $ echo 'package main; import "fmt"; func main() { fmt.Println("Hello, World") }' > hello.go 
  4. $ go1.14.12 build 
  5. $ ./hello 
  6. Hello, World 

当然,如果你想让 Go v1.14.12 ”喧宾夺主“,成为 go 命令的代言人,可以这样做。

  1. $ go version 
  2. go version go1.17 darwin/amd64 
  3. $ export GOROOT=$(go1.14.12 env GOROOT) 
  4. $ export PATH=${GOROOT}/bin:$PATH 
  5. $ go version 
  6. go version go1.14.12 darwin/amd64 

这个go1.14.12 env GOROOT 路径就是 Go v1.14.12 版本的内容。所以,如果我们想卸载这个版本,直接将该路径文件夹删除即可;想阅读该版本源码,直接查看该路径下的src/内容即可 。

获取最新开发版本

有一个特别的版本标记:gotip,它用于安装最新的开发版本。

  1. $ go install golang.org/dl/gotip@latest 
  2.  
  3. $ gotip download 

可以看到,当前拉取到的最新的开发版本是 go1.18-1afa432。

实现思路

实现多版本下载安装的秘诀就在于 https://go.googlesource.com/dl 这个仓库,https://github.com/golang/dl 是它的镜像库。

查看仓库代码,我们能看到一系列版本目录

随意选择一个版本进入,会发现存在一个 main.go 文件

而 main.go 文件内容如下

我们通过go install golang.org/dl/go1.14.12@latest下载的 go1.14.12 包装器就是这个 main.go 编译而成。

因此,我们后续通过 go1.14.12 包装器下载和运行的逻辑就在于internal/version包中的 Run 方法了。

  1. // Run runs the "go" tool of the provided Go version. 
  2. func Run(version string) { 
  3.  log.SetFlags(0) 
  4.   // 获取 Go 安装目录 
  5.  root, err := goroot(version) 
  6.  if err != nil { 
  7.   log.Fatalf("%s: %v", version, err) 
  8.  } 
  9.    
  10.   // 执行 go<version> download 命令时逻辑 
  11.  if len(os.Args) == 2 && os.Args[1] == "download" { 
  12.   if err := install(root, version); err != nil { 
  13.    log.Fatalf("%s: download failed: %v", version, err) 
  14.   } 
  15.   os.Exit(0) 
  16.  } 
  17.    
  18.   // 判断该版本 Go 安装状态 
  19.  if _, err := os.Stat(filepath.Join(root, unpackedOkay)); err != nil { 
  20.   log.Fatalf("%s: not downloaded. Run '%s download' to install to %v", version, version, root) 
  21.  } 
  22.   // 运行该版本 Go 
  23.  runGo(root) 

鉴于篇幅原因, 下载的install和运行的runGo函数逻辑本文就不再展开了,想深入了解的同学可以自行探索。

另外,为了让每个版本都有一个 Go 包装器主程序(避免重复的手工操作),这里使用了一个帮助命令genv:可以快速生成对应版本的包装器代码/main.go。这里的实现见internal/genv/main.go代码。

总结

本文介绍了 Go 官方提供的多版本管理方案,包括使用、安装、卸载等,可以感受到它的简洁与高效。同时我们简单查看了这一套实现代码逻辑。

最后,希望本文内容能够助你用好 Go 多版本管理,欢迎留言讨论。

 

责任编辑:武晓燕 来源: Golang技术分享
相关推荐

2010-12-10 15:40:58

JVM内存管理

2016-09-06 22:05:41

HttpCookieWeb

2013-09-29 15:11:46

Linux运维内存管理

2009-07-08 15:10:00

Servlet会话管理

2010-07-23 09:34:48

Python

2010-09-26 13:23:13

JVM内存管理机制

2022-06-01 16:01:58

MySQL内存管理系统

2009-09-25 12:59:53

Hibernate事务

2010-04-08 15:43:28

Oracle缓冲块

2011-06-29 17:20:20

Qt 内存 QOBJECT

2009-09-23 17:48:00

Hibernate事务

2020-11-08 14:32:01

JavaScript变量内存管理

2022-02-28 10:25:17

Python参数传递拷贝

2016-10-09 14:41:40

Swift开发ARC

2010-09-27 13:26:31

JVM内存管理机制

2011-11-10 14:46:54

Windows8电源管理

2017-08-17 17:09:28

PostgreSQL 数据块机制

2019-01-23 17:08:52

Python内存管理RealPython

2020-08-18 19:15:44

Redis内存管理

2011-08-18 13:28:35

Objective-C内存
点赞
收藏

51CTO技术栈公众号