go module 详解

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

GOPATH和GOROOT

GOROOT不是必须要设置的。默认go会安装在/usr/local/go下,但也允许自定义安装位置,GOROOT的目的就是告知go当前的安装位置,编译的时候从GOROOT去找SDK的system libariry。

GOPATH必须要设置,但并不是固定不变的。GOPATH的目的是为了告知go,需要代码的时候,去哪里查找。注意这里的代码,包括本项目和引用外部项目的代码。GOPATH可以随着项目的不同而重新设置。

GOPATH下会有3个目录:src、bin、pkg。

  • src目录:go编译时查找代码的地方;
  • bin目录:go get这种bin工具的时候,二进制文件下载的目的地;
  • pkg目录:编译生成的lib文件存储的地方。

包管理

上面小节提到,依赖的代码去$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变量中。

检出依赖

 如果要增加新的依赖包:

  • 运行 go get github.com/globalsign/mgo
  • 代码中 import github.com/globalsign/mgo

项目编写好了,使用GOPATH的依赖包测试ok了的时候,执行:

godep save 

如上的命令将会自动扫描当前目录所属包中import的所有外部依赖库(非系统库),并将所有的依赖库复制到当前工程中,产生文件 Godeps/Godeps.json 文件。

godep save时godep把所有依赖包代码从GOPATH路径拷贝到Godeps目录下,并去除代码管理目录

 

依赖包会有更新,如何更新依赖包?可以通过如下的命令实现。

  • 运行 go get -u github.com/globalsign/mgo
  • 运行 godep update github.com/globalsign/mgo

 


拉取依赖 restore

通过命令 godep restore同步依赖库,godep restore执行时,godep会按照Godeps/Godeps.json内列表,依次执行go get -d -v来下载对应依赖包到GOPATH路径下

 

总结:

本文主要介绍了几种go依赖包管理工具,首先介绍了go的环境安装,配置对应的环境变量;其次讲到包管理的两种类型:内部依赖和外部依赖的管理。内部依赖包的管理很简单,go原生的外部依赖包管理存在很多缺陷,随后介绍了开源社区推出的godep和govendor,在vendor基础上进行了功能的完善。还有目前常用的包依赖管理工具glide和官方的dep,将会在后面的文章介绍,尽请期待。

 

Modules

初始化包

首先设置下环境变量 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

  • MAJOR 主版本号,如果有大的版本更新,导致 API 和之前版本不兼容。我们遇到的就是这个问题。
  • MINOR 次版本号,当你做了向下兼容的新 feature。
  • PATCH 修订版本号,当你做了向下兼容的修复 bug fix。
  • v 所有版本号都是 v 开头。

比如我们用的 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 是一个开源项目,当用户请求一个依赖库时,如果它发现本地没有这份代码就会自动请求源,然后缓存到本地,用户就可以从 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 代理。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值