GoModule:v2及新版本(Go Modules: v2 and Beyond译文)

Posted -_-void

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GoModule:v2及新版本(Go Modules: v2 and Beyond译文)相关的知识,希望对你有一定的参考价值。

GoModule:v2及新版本

英文原版:https://blog.golang.org/v2-go-modules

介绍

这是系列文章的第四部分

随着项目中新需求的添加,之前的功能和设计可能不太合适。开发者可能移除废弃的function,重命名type、或者将package分割成更好管理的多个部分。这种变动需要下游使用者调整代码来适应新的API,因此在做这种改动之前要仔细权衡利弊。

处于实验阶段的项目(majro版本为v0)可能会有大的改动,而stable阶段的项目(major版本为v1或以上)如果有大的改动则需要发布新的major版本。本文主要介绍如何发布新的major版本以及如何维护多个majro版本。

majro版本及module路径

module的正式且重要的规则:import compatibility rule

如果新的包与旧的包使用相同的导包路径,那么新的包必须兼容旧的包

根据定义,package的新major版本不会兼容之前的版本,意味着新的major版本必须有与之前版本不同的module路径。从v2开始,major版本必须出现在module路径的结尾(在go.mod文件的module语句中声明)。例如,当github.com/googleapis/gax-go发布了v2版本,那新的module路径就是github.com/googleapis/gax-go/v2,使用v2的用户需要修改import为github.com/googleapis/gax-go/v2

major版本作为后缀是GoModule与其他依赖管理的区别之一。后缀需要解决diamond dependency problem。在GoModule之前,gopkg.in允许package维护人员遵循我问现在称之为import compatibility rule的内容。对于gopkg.in,如果当前依赖包的import是gopkg.in/yaml.v1且另一个包的import是gopkg.in/yaml.v2这种,跟新的规则并不冲突,因为这两个yaml包的导包路径不同。go命令接受.v2这种major版本作为路径后缀,这是为gopkg.in做的特殊兼容,其他域名的module仍应使用/v2这种后缀。

major版本策略

推荐的策略是在新的以major版本后缀命名的目录下进行v2级以上版本的开发。

github.com/googleapis/gax-go @ master branch
/go.mod    → module github.com/googleapis/gax-go
/v2/go.mod → module github.com/googleapis/gax-go/v2

这种方法兼容非module模式的工具:代码库的文件路径与GOPATH模式下的go get兼容,这个策略也允许各个major版本在独立的目录下开发。

有的策略将不同majro版本放在不同分支,但是如果v2及以上的代码在代码库的默认分支上,那么不支持版本的工具(包括GOPATH模式下的go命令)可能无法识别major版本。

本文的示例将遵循major版本子目录的策略,这样可以保证最大的兼容性。我们建议module开发者遵循这种策略使得其用户也可以在GOPATH模式下开发。

发布v2及以上版本

本文以github.com/googleapis/gax-go为例:

$ pwd
/tmp/gax-go
$ ls
CODE_OF_CONDUCT.md  call_option.go  internal
CONTRIBUTING.md     gax.go          invoke.go
LICENSE             go.mod          tools.go
README.md           go.sum          RELEASING.md
header.go
$ cat go.mod
module github.com/googleapis/gax-go

go 1.9

require (
    github.com/golang/protobuf v1.3.1
    golang.org/x/exp v0.0.0-20190221220918-438050ddec5e
    golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3
    golang.org/x/tools v0.0.0-20190114222345-bf090417da8b
    google.golang.org/grpc v1.19.0
    honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099
)
$

要开始v2版本的开发,首先新建一个v2文件夹并将package复制进去

$ mkdir v2
$ cp *.go v2/
building file list ... done
call_option.go
gax.go
header.go
invoke.go
tools.go

sent 10588 bytes  received 130 bytes  21436.00 bytes/sec
total size is 10208  speedup is 0.95
$

现在从当前go.mod创建一个v2的go.mod并添加v2后缀到module路径中:

$ cp go.mod v2/go.mod
$ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
$

注意v2版本会认为是与v0、v1独立的版本:这两个版本共存在同一个build。所以如果v2级以上版本的module用于多个package,他们都需要升级到新的/v2导包路径:除非v2及以上版本依赖v0或v1版本。例如升级所有的github.com/my/project里面对github.com/my/project/v2的引用,可以使用findsed

$ find . -type f \\
    -name '*.go' \\
    -exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g'  \\;
$

现在就有了v2的module,但是我们想在发布之前先试一下。在发布v2.0.0(或其他非预发布版本)之前,仍可以开发新的API或者做重大改动。如果想让用户在我们发布新版本前实验新的API,可以先发布v2的预发布版本:

$ git tag v2.0.0-alpha.1
$ git push origin v2.0.0-alpha.1
$

一旦我们认为v2版本的API可用,并且确定不需要再做其他大改动,可以打上v2.0.0的tag:

$ git tag v2.0.0
$ git push origin v2.0.0
$

这时就维护了两个major版本,兼容修改或者bug修复将需要发布新的minor或者patch版本(如v1.1.0、v2.0.1等)。

总结

升级major版本会带来开发及维护成本,并且下游的用户需要做点事情才能进行迁移。项目越大开销越大,所以最好在确实需要的情况下进行major版本的升级。一旦确定了有重大变更,建议在master分支中开发多个major版本,这样可以与其他现有工具兼容。

对v1及以上module做重大变更应始终发生在vN+1版本上。发布新module意味着开发维护人员需要做更多的工作来迁移到新版本。因此请在发布新版本前验证其API并仔细考虑是否有必要在v1之后做重大变更。

以上是关于GoModule:v2及新版本(Go Modules: v2 and Beyond译文)的主要内容,如果未能解决你的问题,请参考以下文章

使用GoModule(Using Go Modules译文)

迁移到GoModule(Migrating to Go Modules译文)

go module基本使用

go module 基本使用

如何使用go module导入本地包

golang 之 go module