go init
go tidy
go test // 测试模块
go list -m all // 列出模块的依赖包
go list -m -version 包 // 列出模块依赖包的所有版本
GOCACHE =C:\Users\admin\AppData\Local\go-build
GOENV =C:\Users\admin\AppData\Roaming\go\env
GO111MODULE =
GOPATH =C:\Users\admin\go
GOPROXY =https://proxy.golang.org,direct
GOROOT =c:\go
GOTOOLDIR =c:\go\pkg\tool\windows_386
GOROOT不是必须要设置的。默认go会安装在/usr/local/go下,但也允许自定义安装位置,GOROOT的目的就是告知go当前的安装位置,编译的时候从GOROOT去找SDK的system libariry。
GOPATH必须要设置,但并不是固定不变的。GOPATH的目的是为了告知go,需要代码的时候,去哪里查找。注意这里的代码,包括本项目和引用外部项目的代码。GOPATH可以随着项目的不同而重新设置。
GOPATH下会有3个目录:src、bin、pkg。
上面小节提到,依赖的代码去$GOPATH指定的位置寻找,这部分代码可能是本项目或者外部引用的项目。下面依次介绍这两种情况。
如笔者示例route_auth.go的引入:
import (
"gwp/Chapter_2_Go_ChitChat/chitchat/data"
"net/http"
)
route_auth.go需要引用data/user.go,项目结构如下:
编译时会去$GOPATH/src/目录去查找需要的代码,因此只要上面data/user.go在$GOPATH/src/gwp/Chapter_2_Go_ChitChat/chitchat/data里面,go编译的时候就能找到。
对于外部依赖的管理 go没有想java这样maven来管理包和包版本,而是直接使用gopath来管理这些外部依赖
GOPATH来管理外部依赖
Go允许import不同代码库的代码,例如github.com,golang.org,go.etcd.io 等等;对于需要import的代码 可以使用go get取下来放到gopath对应的目录中去,例如go get github.com/globalsign/mgo,会下载到$GOPATH/src/github.com/globalsign/mgo中去当其他项目在import github.com/globalsign/mgo 时也能找到对应的代码
看到这里也就明白了,对于go来说,其实并不在意你的代码是内部的还是外部的,总之都在gopath里,任何import包的路径都是从gopath开始的;唯一的区别是,内部依赖的包是开发者自己写的,外部依赖的包是go get下来的别人写的。
Go语言原生外包管理的缺陷:
能拉取源码的平台很有限,绝大数是依赖github.com
不能区分版本,以至于令开发者以最后一项包名作为版本划分
依赖列表无法持久化,需要一个一个go get到本地
只能依赖本地全局仓库(GOPATH/GOROOT),无法将库放置于局部仓库($PROJECT_HOME/vendor)
Vendor
就是首先回去src/vendor目录下去找代码 然后再从src下找代码
问题时:目录中依赖包仍然没有版本信息 这样依赖包脱离了版本管理,对于升级,问题追溯会有点困难
如何方便的得到本项目依赖了哪些包,并方便的将其拷贝到vendor目录下?依靠人工实在不现实。
godep
Godep早期管理并不依赖vendor go1.5之前版本可以使用 在venfor推出以后 godep 也改为venfor了。godep建议在golang1.6以后使用,且godep依赖vendor
godep的使用者众多,如docker,kubernetes, coreos等go项目很多都是使用godep来管理其依赖,当然原因可能是早期也没的工具可选。
go get -u -v github.com/tools/godep
通过如上的命令安装,成功安装后,在$GOPATH的bin目录下会有一个godep可执行的二进制文件,后面执行的命令都是用这个,建议这个目录加入到全局环境变量中。
编译运行
因为go命令是直接到GOPATH目录下去找第三方库,且在1.6以后支持vendor方式编译,而使用godep下载的依赖库放到Godeps/workspace目录下的,但是不影响继续使用依赖GOPATH目录,所以与三方工具本身不冲突。因此使用:
godep go build main.go
godep中的go命令,就是将原先的go命令加了一层壳,执行godep go的时候,会将当前项目的workspace目录加入GOPATH变量中。
如果要增加新的依赖包:
项目编写好了,使用GOPATH的依赖包测试ok了的时候,执行:
godep save
如上的命令将会自动扫描当前目录所属包中import的所有外部依赖库(非系统库),并将所有的依赖库复制到当前工程中,产生文件 Godeps/Godeps.json 文件。
godep save时godep把所有依赖包代码从GOPATH路径拷贝到Godeps目录下,并去除代码管理目录
依赖包会有更新,如何更新依赖包?可以通过如下的命令实现。
拉取依赖 restore
通过命令 godep restore同步依赖库,godep restore执行时,godep会按照Godeps/Godeps.json内列表,依次执行go get -d -v来下载对应依赖包到GOPATH路径下。
本文主要介绍了几种go依赖包管理工具,首先介绍了go的环境安装,配置对应的环境变量;其次讲到包管理的两种类型:内部依赖和外部依赖的管理。内部依赖包的管理很简单,go原生的外部依赖包管理存在很多缺陷,随后介绍了开源社区推出的godep和govendor,在vendor基础上进行了功能的完善。还有目前常用的包依赖管理工具glide和官方的dep,将会在后面的文章介绍,尽请期待。
首先设置下环境变量 GO111MODULE=auto 如果go的版本是v1.11之后的可以不用设置这个变量,因为1.11之后的版本,默认都是使用go module而且从Go 1.11开始,当当前目录或任何父目录有go.mod时,只要该目录位于$GOPATH/src之外,go命令就可以使用模块(在$ GOPATH/src内部,出于兼容性考虑,即使找到了go.mod,go命令仍然在旧的GOPATH模式下运行。)从Go 1.13开始,模块模式将是所有开发的默认模式。
go mod init 模块名
就能在目录下看到go.mod文件,里面包含了模块的名称,和go的版本
module goModule
go 1.12
require里是程序需要的第三方包,也标明了版本号,而下载的源码包在$GOPATH/pkg/mod文件夹里。
Go模块的主要动机是改善管理使用其他开发者编写的代码(代码依赖)的体验
vMAJOR.MINOR.PATCH
比如我们用的 Go 语言,目前是 1.12.0。它还是 Go 1,每次升级都保证是兼容的,12的版本号是新 feature,而最末尾的版本号是修复。说明当前的版本上了之后还没有修复过问题。
Go.mod:
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote v1.5.2
)
golang.org/x/text软件包已升级到最新的标记版本(v0.3.0)。 go.mod文件中golang.org/x/text也已更新为指定的v0.3.0。
indirect注释指明依赖项不被当前模块直接使用,而是由其依赖的模块所使用的。 其实golang.org/x/text 是我go get 直接获取的
go list -m -versions rsc.io/sampler 查看这个包所有版本
在go list-m all的输出中,当前模块也被称为主模块,总是会出现在第一行,后面跟随的是根据模块路径排序后展示的依赖项:example.com/hello
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1
在示例中,rsc.io/quote的v3版本的模块路径不再是rsc.io/quote,而是rsc.io/quote/v3。此约定称为语义导入版本控制
以上依次来试验了下面几种情况:
· go mod init 创建一个新模块,初始化描述它的go.mod文件。
· go buil,go test和其他程序包构建命令根据需要向go.mod添加新的依赖项。
· go list -m all打印当前模块的依赖关系。
· go get更改所需依赖的版本(或添加新的依赖)。
· go mod tidy删除未使用的依赖项。
如果你不喜欢 go mod 的缓存方式,你可以使用 go mod vendor 回到 godep 或 govendor 使用的 vendor 目录进行包管理的方式。
当然这个命令并不能让你从godep之类的工具迁移到 go modules,它只是单纯地把 go.sum 中的所有依赖下载到 vendor 目录里,如果你用它迁移 godep 你会发现 vendor 目录里的包会和 godep 指定的产生相当大的差异,所以请务必不要这样做。
新的工作模式也带来了一些问题,在大陆地区我们无法直接通过 go get 命令获取到一些第三方包,这其中最常见的就是 golang.org/x 下面的各种优秀的包。一旦工作在模块下,go build 将不再关心 GOPATH 或是 vendor 下的包,而是到 GOPATH/pkg/mod 查询是否有cache,如果没有,则会去下载某个版本的 module,而对于某些包的 module,在大陆地区往往会失败。我们将在下篇文章介绍 go module 的 proxy 配置实现。
goproxy 是一个开源项目,当用户请求一个依赖库时,如果它发现本地没有这份代码就会自动请求源,然后缓存到本地,用户就可以从 goproxy.io 请求到数据。当然,这些都是在一个请求中完成的。goproxy.io 只支持 go module 模式。当用户执行 go get 命令时,会去检查 $GOPROXY//@v/list 这个文件中是否有用户想要获取的版本,如果有,就依次获取 $GOPROXY//@v/.info、$GOPROXY//@v/.mod、$GOPROXY//@v/.zip 等文件,如果没有就直接从源码库中去下载。
通过命令:
export GOPROXY=https://goproxy.io复制代码
设置了这个环境变量,一旦设置生效,后续 go 命令会通过 go module download protocol与 proxy 交互下载特定版本的 module。当然,我们还可以置空 GOPROXY 变量,来关闭 GOPROXY 代理。