GO MOD
Go Mod : Golang 的包管理工具之一
中国代理
添加代理源
https://goproxy.cn
官方WIKI说明
Go Mod 的使用
在使用Go Mod之前,需要将环境变量GO111MODULE
设置为auto
或者on
,如果没有设置,将会默认开启。
也可以在运行Go指令之前,显示声明环境变量GO111MODULE=on
GO111MODULE 应该是 go mod 的1.11版本
项目初始化
$ go mod init <your project name>
$ # initialize new module in current directory
$ # 将当前目录初始化为Go Module
目录下会生成go.mod
文件,该文件中声明了项目需要引用的依赖modules
。
文件的第一行声明了本项目的名称,通常你可以指定在为github.com/your name/project name
例如
$ go mod init github.com/A-Donga/Golangs
添加依赖
只需要在Go文件中加入需要引入的Mod即可。
官方示例
package main
import (
"fmt"
"rsc.io/quote"
)
func main(){
fmt.Println(quote.Hello())
}
然后执行构建、编译指令(linux),最后运行即可。
$ go build -o hello
$ ./hello
值得注意的是,上述过程中,没有使用go get
指令。
常用指令
日常性操作
引用模块
将引用的代码加入到import中,当执行
go build
go test
等指令时,go mod 会自动查找、下载、引用相关module
。-
可以使用
go get project@version
的方式引用特定module的特定版本,也可以直接在go.mod
文件夹直接写入相关信息。
version可取的值- 分支名称
- 版本号
- 提交git的记录ID
简单指令
go list -m all
查看所有引用Module(直接或间接)的版本。go list -u -m all
查看所有引用Module(直接或间接)的最高版本信息。-
go get -u ./...
或者go get -u=patch ./...
将项目的所有引用Module(直接或间接)或者补丁升级到最新版本。patch指代补丁版本 go语言的版本规范:v(major).(minor).(patch)
go build ./...
从根目录编译项目,如果想要编译当前目录,去掉./...
即可, 指令变为:go build
。go test ./...
从根目录测试项目,如果想要测试当前目录,去掉./...
即可,指令变为:go test
。go mod tidy
去掉go.mod
中不需要的依赖,并标注当前的系统信息。go mod vendor
引导创建vendor目录。
Go Mod 概念声明
Modules
Modules
是相关的Go软件包的集合,这些Go软件包一起作为一个单元进行了版本控制。
模块记录了每个依赖需求并创建了可以复用的构建。
通常,版本控制库(如Github、GitLib等)仅包含一个定义在存储库的根目录的一个模块。
(如果一个存储库中包含了多个模块将会导致更多的工作量)
存储库(Repositories)、模块(Modules)、包(Packages)之间的关系如下:
- 一个存储库包含一个或多个Go模块。
- 每个模块包含一个或多个Go包。
- 每个包在一个目录下包含了一个或多Go源文件
模块必须根据Semver规范进行语义版本控制,通常采用v(major).(minor).(patch)的形式。
例如v0.1.0,v1.2.3或v1.5.0-rc.1(必须使用前置符号:v)。
如果使用Git工具,则标记为提交版本。
公共、私有模块存储库和代理都可以使用。
go.mod
模块被声明在Go源码文件树根目录下的go.mod文件中。模块源码可以存在于GOPATH环境变量之外。
四种等级:module
require
replace
exclude
这里根据github.com/my/thing
声明了一个示例:
module github.com/my/thing
require (
github.com/some/dependency v1.2.3
github.com/another/dependency/v4 v4.0.0
)
模块通过在go.mod
中的module
指令(通常为第一行)提供的模块路径声明其身份(标识符)。
模块路径作为该模块内所有包的工共前缀。
模块路径和模块内的Package的相对于go.mod
文件的路径组合成为了该包的导入路径。
举例说明:
现在你有一个模块路径为github.com/user/mymod
的模块仓库。
包含两个包:github.com/user/mymod/foo
和github.com/user/mymod/bar
。
go.mod
的第一行将被声明为module github.com/user/mymod
,同时在磁盘上可能是如下的存在方式。
mymod
|-- bar
| `-- bar.go
|-- foo
| `-- foo.go
`-- go.mod
在Go的源码中,应该使用包含了模块路径的全路径进行引入指定包。
例如在上面的例子中,如果需要引用bar.go这个文件,你应该做如下声明:
import "github.com/user/mymod/bar"
exclude
和replace
指令仅在当前模块上起作用。
在构建过程中,其他模块中的exclude
和replace
指令将会被忽略。
因此,replace和exclude语句允许主模块完全控制其自身的构建,而不受依赖项的完全控制。
版本选择
如果在Go源码中,引入了一个没有在go.mod中声明的模块,在执行go build
或者go test
的指令时,将会自动寻找目标模块的最高版本,并使用require
指令进行引入。
比如你想引用模块A,而模块A的当前最高版本为v1.2.3,然后在你的模块中,go.mod将会使用require
指令引入M v1.2.3。
这代表着,你接受版本>=v1.2.3并且小于v2。(在规范中,v(y)于v(x)不兼容)
最小版本选择算法用于选择构建中使用的所有模块的版本。
对于构建中的每个模块,通过最小版本选择的版本始终是主模块中的require指令或其依赖项之一明确列出的版本的语义上最高的版本。
上述表达很难懂,没关系,看例子
你的模块中依赖了两个模块:A,B, A模块依赖D模块(v1.0.0),B模块依赖D模块(v1.1.1),那么此时最小版本选择算法将会选择Dv1.1.1
。
即使一段时间后,v1.2.0已经可用,但是最小版本仍会选择v1.1.1。当然你可以利用指令手动升级,升级到最新可用版本,或者直接手动选择版本。
如何使用模块
如果安装并支持模块
如果需要使用模块,有以下两种方式(个人推荐方式一)
当你完成安装后,你有一下两种方式启用模块支持
- 在
$GOPATH/src
树之外的目录中调用go
命令,并在当前目录或其任何父目录中使用有效的go.mod
文件,并且未设置环境变量GO111MODULE
(或将其显式设置为auto)。 - 在设置了环境变量的
GO111MODULE=on
调用go
命令。
如何声明一个模块
为一个已经存在的项目创建一个go.mod
文件:
-
进入到项目根目录
$ cd <project path>
如果是
GOPATH
路径外,你不需要用GO111MOUDLE
显式激活。如果你想要在
GOPATH
路径内使用:$ # for linux or mac $ export GO111MOUDLE=on $ cd $GOPATH/src/<project path>
-
对项目进行模块初始化,并将信息写入
go.mod
$ go mod init
这一步将会创建
go.mod
并将模块信息写入,同时如果目录存在其他类型的模块管理工具,将会自动匹配并以require
指令导入到go.mod
文件中。
共支持9种依赖引用格式:- GLOCKFILE
- Godeps/Godeps.json
- Gopkg.lock
- dependencies.tsv
- glide.lock
- vendor.conf
- vendor.yaml
- vendor/manifest
- vendor/vendor.json
有关此部分的详细信息请查看:Go-模块转换
值得注意的是,如果你引用了
v2+
的模块,或者正在构建、初始化这类模块,需要在go mod init
指令运行之后,手动编辑go.mod
、Go文件,引用指定的模块路径。
可以参考语义版本控制
进行修正。
即使已经从其他以来管理工中转换过来了。
直到你成功运行go build
指令后,你才可以使用go tidy
指令。 -
正常操作希望操作的指令即可
go build ./...
go test ./...
go test all
如何升级或降级依赖版本
日常的升级、降级操作通过指令go get
自动更新go.mod
文件来实现,当然,你可以选择直接编辑go.mod
文件。
Go指令go build
、go test
甚至 go list
也会将必要的依赖引入进来(更新go.mod
文件,同时下载需要的依赖)。
将指定依赖升级到最高可用版本:
$ go get example.com/package
更新某个依赖项以及他的依赖到最新可用版本
$ go get -u example.com/package
查看所有依赖(直接或间接)的minor
和patch
的最高可用信息。
$ go list -u -m all
查看所有直接引用的模块的minor
和patch
版本信息
$ go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}: {{.Version}} -> {{.Update.Version}}{{end}}' -m all 2> /dev/null
注
go list -u -f
为格式化输出,-f后面跟上格式化方式,支持基本布尔运算。
这句话理解起来有些难度,用处不是特别大,比如你想查找所有的目录,可以使用:
$ go list -f {{.Dir}}
加上直接依赖
$ go list -f {{if (or .Main .Indirect)}}
后面的指令可以类推
更多详细的信息可以查看
$ go help list
在当前模块内,将所有直接或间接依赖升级到最新最新可用版本,在根目录运行:
$ go get -u ./...
或
$ go get -u=patch
升级指定包
$ go get foo
或
$ go get -u foo
发布模块
由于国内的网络问题,基本上官方文档的方案不可用,因此不做翻译,这里链接一个非常好的说明文档:https://studygolang.com/articles/26694?fr=sidebar。
官方原文链接:https://github.com/golang/go/wiki/Modules#how-to-prepare-for-a-release
有疑问加站长微信联系(非本文作者)