Go Modules 不完全教程
文章转载自公众号Go Modules 是 Golang 官方最近几个版本推出的原生的包管理方式,在此之前,社区也不乏多种包管理方案。在讨论 Go Modules 之前,我们先回顾一下 Golang 的包管理历史的发展。然后讨论一下 Go Modules 的使用以及一些特性,篇幅有限,有些地方不方便展开,后面有时间再深入。行文仓促,不当之处,多多指教。
0. 包管理的历史
Golang 的包管理一直被大众所诟病的一个点,但是我们可以看到现在确实是在往好的方向进行发展。下面是官方的包管理工具的发展历史:
-
在 1.5 版本之前,所有的依赖包都是存放在 GOPATH 下,没有版本控制。这个类似 Google 使用单一仓库来管理代码的方式。这种方式的最大的弊端就是无法实现包的多版本控制,比如项目 A 和项目 B 依赖于不同版本的 package,如果 package 没有做到完全的向前兼容,往往会导致一些问题。
-
1.5 版本推出了 vendor 机制。所谓 vendor 机制,就是每个项目的根目录下可以有一个 vendor 目录,里面存放了该项目的依赖的 package。
go build
的时候会先去 vendor 目录查找依赖,如果没有找到会再去 GOPATH 目录下查找。 -
1.9 版本推出了实验性质的包管理工具 dep,这里把 dep 归结为 Golang 官方的包管理方式可能有一些不太准确。关于 dep 的争议颇多,比如为什么官方后来没有直接使用 dep 而是弄了一个新的 modules,具体细节这里不太方便展开。
-
1.11 版本推出 modules 机制,简称 mod,也就是本文要讨论的重点。modules 的原型其实是 vgo,关于 vgo,可以参考文章末尾的参考链接。
除此之外,社区也一直在有几个活跃的包管理工具,使用广泛且具有代表性的主要有下面几个:
-
godep
-
glide
-
govendor
关于这几种包管理工具的使用这里就不再详述了。
1. modules 简单使用方式
下面看一下 modules 的简单使用方式。
1.1 准备工作
Golang 版本:1.12.3。在 1.12 版本之前,使用 Go modules 之前需要环境变量 GO111MODULE:
-
GO111MODULE=off: 不使用 modules 功能。
-
GO111MODULE=on: 使用 modules 功能,不会去 GOPATH 下面查找依赖包。
-
GO111MODULE=auto: Golang 自己检测是不是使用 modules 功能。
在 GOPATH 之外创建一个项目 mod-demo,包含一个 main.go 文件,内容如下:
packagemain
import(
"github.com/astaxie/beego"
)
funcmain() {
beego.Run()
}
1.2 初始化
初始化很简单,在项目根目录执行命令 go mod init mod-demo
,然后会生成一个 go.mod 文件如下。
? mod-demo $ gomod init mod-demo
go: creating new go.mod: module .
? mod-demo $ ls
go.mod main.go
? mod-demo $ catgo.mod
module .
go 1.12
这里比较关键的就是这个 go.mod 文件,这个文件中标识了我们的项目的依赖的 package 的版本。执行 init 暂时还没有将所有的依赖管理起来。我们需要将程序 run 起来(比如执行 go run/test),或者 build(执行命令 go build)的时候,才会触发依赖的解析。
比如使用 go run 即可触发 modules 工作。
? mod-demo $ gorun main.go
go: extracting github.com/astaxie/beego v1.12.0
2019/09/08 23:23:03.507 [I] http server Running on http://:8080
这个时候我们再查看 go.mod 文件:
? mod-demo $ catgo.mod
module mod-demo
go 1.12
require (
github.com/astaxie/beego v1.12.0
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
)
同时我们发现项目目录下多了一个 go.sum 用来记录每个 package 的版本和哈希值。go.mod 文件正常情况会包含 module 和 require 模块,除此之外还可以包含 replace 和 exclude 模块。
这些 package 并不是直接存储到 $GOPATH/src,而是存储到 $GOPATH/pkg/mod 下面,不同版本并存的方式。
? mod-demo $ ls$GOPATH/pkg/mod/github.com/astaxie
beego@v1.11.0 beego@v1.11.1 beego@v1.12.0
1.3 依赖升级(降级)
可以使用如下命令来查看当前项目依赖的所有的包。
? mod-demo $ golist -m-uall
go: finding github.com/beego/x2j latest
go: finding github.com/cloudflare/golz4 latest
go: finding github.com/siddontang/go latest
go: finding github.com/shiena/ansicolor latest
go: finding github.com/couchbase/go-couchbase latest
go: finding github.com/siddontang/rdb latest
go: finding gopkg.in/check.v1 latest
go: finding github.com/siddontang/ledisdb latest
go: finding github.com/ssdb/gossdb latest
go: finding github.com/couchbase/gomemcached latest
go: finding github.com/wendal/errors latest
go: finding github.com/couchbase/goutils latest
go: finding golang.org/x/net latest
go: finding github.com/cupcake/rdb latest
go: finding github.com/beego/goyaml2 latest
go: finding golang.org/x/crypto latest
go: finding github.com/bradfitz/gomemcache latest
github.com/Knetic/govaluate v3.0.0+incompatible
github.com/OwnLocal/goes v1.0.0
github.com/astaxie/beego v1.12.0
...
如果我想要升级(降级)某个 package 则只需要 go get 即可,比如:
go get package@version