go

go module

go module的使用技巧

Posted by Liangjf on March 30, 2020

go module的使用技巧

go mod 确实方便,无视翻墙问题,下载啥都可以。

go mod 一般是使用以下命令:

  • go mod init xxx
  • go mod tidy
  • go mod edit

这里着重说下 go mod edit 的作用。

go mod edit 用来修改 go.mod 文件的包的版本关系。

  • 修改包版本
  • 自定义本地包。方便测试(本地包需要是 module 方式的)

      module test
    
      go 1.12
    
      require (
          gopkg v0.0.0
      )
    
      replace gopkg v0.0.0 => ../gopkg
    

这样就可以实现 module 方式,调用本地包了。

go mod edit 修改go.mod,然而它有两点缺陷:

  • 首先是它的-require必须接受“package@version”这种形式,缺一不可,而且不能识别文档规定的master和latest标志。
  • edit只适合用于修改依赖版本,给package改名,屏蔽特定的package这三个功能,不适用于添加依赖。

由于以上两个特点,因此有了新版的go get特性。

  • go get会自动下载并安装package,然后更新到go.mod
  • 使用go get package[@version]来安装指定版本的package,不指定version时默认行为和go get package@latest一样
  • version可以是vx.y.z这种形式或者直接使用commit的checksum,也可以是master或者latest
  • 当version是latest时,也就是默认行为,对于有tags的package,会选取最新的tag,对于没有tags的package,则选取最新的commit
  • 当version是master时,不管package有没有打tag,都会选择master分支的最新commit
  • 可以在version前使用>,>=,<,<=,表示选取的版本不得超过/低于version,在这个范围内的符合latest条件的版本
  • go get -u可以更新package到latest版本
  • go get -u=patch将只更新小版本,例如从v1.2.4到v1.2.5
  • 当想要修改package的版本时,只需要go get package@指定的version即可

注意两个坑:

  • 没开go mod方式,直接go get,就是拉取最新的master分支。
  • 开启go mod,直接go get,拉取的是有打tag,就下载tag的版本,没打tag,就拉取最新的master分支

背景:公司有两个私有项目放在私有 git 上,这里叫 A 和 B,A 项目有引用 B 的包

  • 1、go mod 会自动下载最新 tag 的代码,如果没有会自动引入最新的 master 提交,这样没问题。但是有 tag 的情况下只会引入 tag,没法引用最新的代码(如果 B 有改动必须打 Tag ?)
  • 2、上面的问题可以用 replace 的方案解决,但是如果团队开发,大家的 gopath 都不一致,go mod 文件会有多份,如何解决?

解决方案:

  • 使用replace的相对路径(./或../形式) ,比如:replace github.com/b => ../b
  • 手动go get -u github.com/b@branch(或者是commit),go.mod会自动生成 github.com/b@V0.0.0-data-hash

公司通过 gitlab 搭建了私有库,二方依赖库下载不下来怎么办?

这个几乎是最常见的问题,比较简单的解决方案是 hack 一下 git 配置:

git config --global url."git@gitlab.your-company.com:<your>/<package>.git".insteadOf "https://gitlab.your-company.com/<your>/<package>.git"

这个方案依赖你本地的 ~/.ssh/id_rsa, 这样你就可以正常 go get 了。

Dockerfile 中构建镜像怎么解决私有库的依赖包问题?

方案一

上述方式通过修改 git config ,却依赖你本地的 ~/.ssh/id_rsa,在构建时可以通过 multistage-build 把私钥 add 到 stage 0 里面 build,然后用后面新的 stage 生成镜像,这样构建的镜像就不会包含私钥;

方案二

更为安全的方式是,在每次构建 Docker 镜像之前,先在本地用 go mod vendor 把包缓存下来,在 Dockerfile 构建镜像过程中还是用 GOPATH 和 Vendor 机制来管理依赖。