xdays

Golang依赖管理

August 17, 2019

关于 Module

Module 在 1.11 成为官方的依赖管理工具,虽然引起了不小的关于 Go Module 的争吵 ,但是应该就是以后主流的依赖管理工具了。

Module 使用

当前版本 1.12.8 中 go 自动判断是否启用 module 功能,当位于 GOPATH 里时关闭,否则自动开启。

GO111MODULE=auto

新建一个 module

mkdir example
cd example
go mod init github.com/xdays/example

然后你就基本不需要单独跑go get来获取依赖了,go rungo build等命令会根据你的import来自动下载依赖并确立依赖的版本,至于怎么确立的可以在跑完命令后参考go.mod文件的内容。

再者就是如果你更新了依赖版本,可以通过如下命令来清掉旧版本

go mod tidy

Module 的管理

对于包管理者来说也可以通过上面的步骤切换到 module 上来,但是当需要更新大版本的时候就需要注意了。官方的原则是:

“If an old package and a new package have the same import path, the new package must be backwards compatible with the old package.”

简而言之,更新大版本只需要如下几个步骤:

  1. 将上一个版本开个分支,比如v5,然后打上 tag,继续维护
  2. 在 master 分支上开发不兼容的v6分支,然后打上对应的 tag
  3. 最重要的是更新 module 的 path,在最后添加上大版本的后缀,如果之前是github.com/xdays/example,那么更新之后就是github.com/xdays/example/v6,所以其实已经是不同的 package 了

更复杂的需求可以参考官方的 Module 文档

使用中遇到的问题

go-redis 代码不兼容问题

问题

测试代码在这里redis-migrate,直接运行代码有问题

$ go run main.go
./main.go:105:55: cannot use &rangeBy (type *redis.ZRangeBy) as type redis.ZRangeBy in argument to srcClient.cmdable.ZRangeByScoreWithScores
./main.go:110:33: cannot use &z (type *redis.Z) as type redis.Z in argument to dstClient.cmdable.ZAdd

但是通过go get获取的 redis-migrate 却没有问题

go get github.com/xdays/go-utils/redis-migrate
redis-migrate                                            <aws:loop-staging>
found 5 keys
start migrating key test3 from scratch
set ttl to -1ns
start migrating key test5 from scratch
set ttl to -1ns
start migrating key test2 from scratch
set ttl to -1ns
start migrating key test1 from scratch
set ttl to -1ns
start migrating key test4 from scratch
set ttl to -1ns

分析

如果我在开启了 module,这样 import

import "github.com/go-redis/redis"

那么 go module 拿到的就是最小的稳定版本,go.mod 里是这样的

github.com/go-redis/redis v6.15.3+incompatible

而如果我用传统的方式获取这个 package,那我拿到的就是 master 分支的代码

go get github.com/go-redis/redis
cd $GOPATH/src/github.com/go-redis/redis
git branch

可以看到两种方式拿到的 package 的版本并不一样。

解决

把 import 的 package 路径改为

import "github.com/go-redis/redis/v7"

然后执行

go mod tidy

再看go.mod,已经更新到最新的版本了

github.com/go-redis/redis/v7 v7.0.0-beta.2

所以如果项目开启了 module,在 import 依赖的时候要去看下依赖的go.mod对应的路径,看看是不是有版本声明的后缀。这是go-redis 的版本声明