Go的新玩具 vgo

大名鼎鼎的 Russ Cox 在18年2月20日在他的博客上介绍了他为go设计的新工具,版本化的golang包管理工具——vgo

vgo versioned go的缩写,意即带版本的go,从功能上类比java的maven,rust的cargo,node的npm,golang现有的dep等,但是有所不同。

〇、需要准备的概念

在这个新鲜出炉的vgo工具,我个人认为有一个非常重要也非常值得一提的概念称之为:语义导入版本(英文Semantic Import Versioning )。

先看两个在golang社区非常常见的两个版本概念。

  • 语义版本 (Semantic Versioning):典型代表 dep ( github.com/golang/dep ) 。使用版本控制的tag等表明包的版本,正确的写法如 v2.3.4 。其中2是主版本号,3是小版本号,4是补丁版本号。顾名思义,小版本号往往是添加新的特性,补丁版本号是补补修修。优点是精准选择版本,避免坑。
  • 导入版本 ( Import Versioning ) : 典型代表 gopkg ( gopkg.in ) , 具体使用者如go-redis ( gopkg.in/redis.v3 ),即包名中包含版本号,通过go get特性实现,具体参见gopkg官方说明。好处是非常方便更新修复bug。

那么什么是语义导入版本,也就呼之欲出了,即贪心的人两个都要。

即在包路径上写明主版本号,也同时使用语义版本


一、撸起袖子 上手就干

输入命令行安装

go get golang.org/x/vgo

(假设你本地安装的是最新的golang,且GOPATH什么的都配置好了 @.@ )


在任意目录创建一个名为hello的文件夹,同时创建一个main.go,并写入下面的代码(代码和整个例子都来自源网站 )。

package main // import "github.com/you/hello"

import (
	"fmt"
	"rsc.io/quote"
)

func main() {
	fmt.Println(quote.Hello())
}


创建一个空的go.mod 文件在这个目录下面(PS: 这个文件像maven的pom.xml、npm的package.json,里面会有当前的包下的库依赖,当然现在还是空的)。

touch go.mod

在目录下运行下面的命令,使用vgo构建这个简单的hello程序

vgo build

输出的内容如下所示

vgo: resolving import "rsc.io/quote"
vgo: finding rsc.io/quote (latest)
vgo: adding rsc.io/quote v1.5.2
vgo: finding rsc.io/quote v1.5.2
vgo: finding rsc.io/sampler v1.3.0
vgo: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
vgo: downloading rsc.io/quote v1.5.2
vgo: downloading rsc.io/sampler v1.3.0
vgo: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c

这个时候hello就构建完成了,运行./hello 可以输出十分亲切的“你好,世界”。

而此时go.mod里也自动生成了依赖关系,文件内容被修改成了:

module "github.com/you/hello"

require "rsc.io/quote" v1.5.2

module 指示这个模块的包路径。

require 顾名思义,即依赖XX包的v.x.x.x 版本。

(PS: 虽然这个地方感觉比较疑惑,自定义的格式真的好吗,是不是使用比如toml什么的标准的验证过的文件格式更好呢?)


二、vgo的其他用法

  • vgo list -m 查看所有依赖
  • vgo list -m -u 查看所有依赖同时检查更新,会打印出最新版本和当前版本
  • vgo test all 执行所有测试,包括依赖包的测试
  • vgo test rsc.io/sampler 执行指定包测试
  • vgo get -u 更新所有依赖
  • vgo list -t rsc.io/sampler 检查指定包所有可用的版本 即tag
  • vgo get rsc.io/sampler@v1.3.1 获取指定版本,并修改go.mod

排除指定版本:指明不使用版本,这个时候需要手改go.mod,添加一行如

exclude "rsc.io/sampler" v1.99.99

替换依赖:替换依赖包,go.mod语法如下

replace "rsc.io/quote" v1.5.2 => "github.com/you/quote" v0.0.0-myfork

也可以替换成本地文件夹

replace "rsc.io/quote" v1.5.2 => "../quote"

这样vgo就会替换这个依赖,vgo list -m 时候也会显出这个箭头表示替换。

MODULE                VERSION
github.com/you/hello  -
golang.org/x/text     v0.0.0-20180208041248-4e4a3210bb54
rsc.io/quote          v1.5.2
 => ../quote
rsc.io/sampler        v1.3.1


三、退到vendor 兼容不使用vgo的用户

有一种场景叫做和谐共处,我想使用vgo,但是构建我项目的人不想使用vgo,想用标准的go build构建,vgo也是可以的。

首先把项目放在gopath下,然后执行

vgo vendor

vgo就会把所有依赖都放在vendor目录下,这样go build直接就可以运行啦!


四、需要注意的几点

  1. 在vgo-import文章中(Semantic Import Versioning),提出了避免单例问题,同时依赖多版本的库,如果这个库在初始化时候有单例和相关操作,有可能会冲突,如都向默认的http 路由注册handler。
  2. 目前vgo的文档似乎还不是很健全,代码也还有一些bug,在生产环境可能还不适合去使用。
编辑于 2018-02-22