1. 缘起
我们的Go团队这两年完全是按照之前写的《小厂内部私有Go module拉取方案》[1]和《小厂内部私有Go module拉取方案(续)》[2]中的方案搭建的内部拉取私有仓库的基础设施,总体感觉不错,目前也没有什么大问题。
唯一麻烦一点的,就像《小厂内部私有Go module拉取方案》[3]中提到的,当新增一些用作私有依赖包的repo时,govanityurls的vanity.yml需要手动更新或通过工具自动更新。维护这样一套设施,开发人员肯定不喜欢去做。
月初一位同事的主机发现无法通过内部的GOPROXY server拉取私有module,虽然事后证明这很是网络层面的问题,但也引发我的思考,在统一代理之外是否有拉取私有module的补充方案?恰好前些天,组内一童鞋分享了Rust[4]直接用内部自建的gitlab上的一个repo作为依赖的方法,只需要在cargo.toml中做简单配置:
foo-rs = {git = "http://192.168.10.10/ard/foo-rs", branch = "master"}
基于go module目前的机制是否可以支持类似Rust这种相对优雅的方案呢?本着当时对go.mod配置与go get的认知一时没有想出来:(。不过心中也大致给这样的方案画出了一个框框:
基于现有go.mod语法
改动最小
用go.mod而非go.work,这样可提交到代码库做版本管理,所有组员均可使用
我想到了基于go mod replace来做,当然需要对replace做一些扩展,于是我向go官方项目提交了proposal[5]!
2. 提案(proposal)
提案[6]的核心就是扩展go mod的replace语法,让replace的target支持一个remote的vcs仓库,下面是一个例子:
module github.com/bigwhite/demo
go 1.20
require (
mycompany.com/go/common v1.1.0
)
replace mycompany.com/go/common v1.1.0 => 192.168.10.159/ard/go/common v1.1.0
//或 replace mycompany.com/go/common => 192.168.10.159/ard/go/common
//或 replace mycompany.com/go/common => 192.168.10.159/ard/go/common v1.1.0
//或 replace mycompany.com/go/common v1.1.0 => 192.168.10.159/ard/go/common
这样我们既可保留我们为私有module自定义的cannoical import paths(如mycompany.com/go/common),又可以方便基于自建vcs server拉取私有module。
3. 反转
我的提案提出没两个小时就被close了,我去看了一下详情,seankhliao[7]回复:Go现在已经支持这种用法,并给出一个例子:
192.168.10.159/ard/go/common.git
我不确定seankhliao是否完全理解了我的提案,但他的回复还是让我开始怀疑我是否遗漏了什么。于是我又去重新学习了一下go module的reference[8]以及go cmd的reference[9],之后脑子中形成了一个待确认的方案。
当前go.mod的replace指示符语法如下:
replace module-path [module-version] => replacement-path [replacement-version]
其中的replacement-path [replacement-version]构成target部分,目前支持两种target:
一种是module path,如:
replace example.com/othermodule => example.com/othermodule v1.2.3
另外一种是本地文件系统中的路径:
replace example.com/othermodule => ../othermodule
需要注意的是当replacement-path使用module path时必须带有replacement-version,下面的例子会导致go编译或运行命令报错:
replace example.com/othermodule v1.2.3 => example.com/othermodule
以前我总以为当replacement-path使用module path时,这个module path必须是那种带有域名的repo地址,根据seankhliao的例子,这块似乎也可以是一个诸如:“192.168.10.159/ard/go/common.git”的remote repo,如果是这样,那么即便不使用统一的内部go proxy,我们也可以直接从内部的自建vcs server上拉取private module了,下面我们就来验证一下这个方案。
4. 方案的确认试验
下面是试验环境的拓扑: