golang包管理解决之道——go modules初探

golang的包管理是一直是为人诟病之处,从golang1.5引入的vendor机制,到准官方工具dep,目前为止还没一个简便的解决方案。html

不过如今go modules随着golang1.11的发布而和咱们见面了,这是官方提倡的新的包管理,乃至项目管理机制,能够再也不须要GOPATH的存在。git

 

go module的初始化

如今modules机制仍在早期阶段,因此golang提供了一个环境变量“GO111MODULE”,默认值为auto,若是当前目录里有go.mod文件,就使用go modules,不然使用旧的GOPATH和vendor机制,由于在modules机制下go get只会下载go modules,这一行为会在之后版本中成为默认值,这里咱们保持auto便可,若是你想直接使用modules而不须要从GOPATH过分,那么把“GO111MODULE”设置为on。github

modules和传统的GOPATH不一样,不须要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录均可以做为module,只要其中包含有go.mod文件。golang

咱们就用一个空目录来建立咱们的第一个module:web

要初始化modules,须要使用以下命令(假设已经安装配置好golang1.11):chrome

go mod init [module name]

咱们的module叫test,因此就是:json

go mod init test

初始完成后会在目录下生成一个go.mod文件,里面的内容只有一行“module test”。websocket

 

包管理

那么咱们怎么进行包管理呢?别担忧,当咱们使用go build,go test以及go list时,go会自动得更新go.mod文件,将依赖关系写入其中。socket

若是你想手动处理依赖关系,那么使用以下的命令:工具

go mod tidy

这条命令会自动更新依赖关系,而且将包下载放入cache。

下面咱们使用chromedp的一个简单example做为实验代码main.go,看下go modules是如何处理包的依赖关系的。

咱们手动运行go mod tidy:

查找并下载包

咱们发现多了一个go.sum,咱们看看它里面是什么内容:

没错,你已经猜到了,这是咱们直接引用的package和它自身须要的以来的版本记录,go modules就是根据这些去找到须要的packages的。

顺带一提,若是咱们不作任何修改,默认会使用最新的包版本,若是包打过tag,那么就会使用最新的那个tag对应的版本。

下面咱们使用go build来编译咱们的代码:

go build

值得注意的是,新增了一个编译选项“-mod”,它有以下的可选值:

go build -mod=readonly

在这个模式下任何会致使依赖关系变更的状况都将致使build失败,前面提到过build能查找并更新依赖关系,使用这个选项能够检查依赖关系的变更。

go build -mod=vendor

意思是忽略cache里的包,只使用vendor目录里的版本。

构建完成后目录结构以下:

咱们的代码成功构建了,包管理都由go modules替咱们完成了。

 

包的版本控制

包管理的另一项重要功能就是包的版本控制。modules一样能够作到。

在介绍版本控制以前,咱们要先明确一点,若是上层目录和下层目录的go.mod里有相同的package规则,那么上层目录的无条件覆盖下层目录,目的是为了main module的构建不会被依赖的package所影响。

那么咱们看看go.mod长什么样:

module test

require github.com/chromedp/chromedp v0.1.2

若是有多个依赖,能够是这样的:

module github.com/chromedp/chromedp

require (
	github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013
	github.com/disintegration/imaging v1.4.2
	github.com/gorilla/websocket v1.2.0
	github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794
	github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856
	golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81
)

前面部分是包的名字,也就是import时须要写的部分,而空格以后的是版本号,版本号遵循以下规律:

vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
vX.0.0-yyyymmddhhmmss-abcdefabcdef
vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
vX.Y.Z

也就是版本号+时间戳+hash,咱们本身指定版本时只须要制定版本号便可,没有版本tag的则须要找到对应commit的时间和hash值。

默认使用最新版本的package。

如今咱们要修改依赖关系了,咱们想使用chromedp 的v0.1.0版本,怎么办呢?

只须要以下命令:

go mod edit -require="github.com/chromedp/chromedp@v0.1.0"

@后面加上你须要的版本号。go.mod已经修改了:

module test

require github.com/chromedp/chromedp v0.1.0

咱们还须要让go modules更新依赖关系,这里咱们手动go mod tidy以后:

注意颜色较深的那两行,咱们已经切换到了v0.1.0版本了。

 

go modules是一个很大的主题,之后我还将进一步介绍它。

若是想进一步深刻go modules的使用,能够阅读个人这篇文章:再探go modules:使用与细节

 

由于go1.11刚发布不久,这篇文件做为探路,一定会有错误和疏漏,欢迎你们指正!

相关文章
相关标签/搜索