提交 e8e8f0e3 编写于 作者: kingreatwill's avatar kingreatwill

go mod深入学习

上级 daaf72ba
go mod 1.13
## 核心文件:go.mod
```
module xx.com/x
go 1.12
require other/thing v1.0.2 // 这是注释
require new/thing/v2 v2.3.4 // indirect
require(
new/thing v2.3.4
old/thing v0.0.0-20190603091049-60506f45cf65
exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5
```
```
module
go
require
exclude
replace
```
indirect 注释标记了该模块不是被当前模块直接导入的,只是被间接导入。
replace my/example/pkg => ./pkg // 可以替换本地包
Go 命令行工具会自动处理 go.mod 中指定的模块版本。当源代码中 import 指向的模块不存在于 go.mod 文件中时,Go 命令行工具会自动搜索这个模块,并将最新版本(最后一个 tag 且非预发布的稳定版本)添加到 go.mod 文件中。
如果没有 tag,则使用伪版本(第 7 行),这是一种版本语法,专门用于标记没有 tag 的提交(一些 golang.org/x/ 下的包就是没有 tag 的)。如: v0.0.0-20190603091049-60506f45cf65 。
前面部分为语义化版本号,用于标记版本;中间部分为 UTC 的提交时间,用于比较两个伪版本以其确定先后顺序;后面部分是 commit 哈希的前缀,用于标记该版本位于哪个 commit。
## 版本管理文件:go.sum
每行由模块导入路径、模块的特定版本和预期哈希组成。
在每次缺少模块时,如果缓存中不存在,则需要下载并计算其哈希添加到 go.sum 中;如果缓存中存在,则需要匹配 go.sum 中的已有条目。
这样,构建软件的用户就可以使用哈希验证其构建是否跟你的构建相同( go mod verify ),而无论他们怎样获取依赖项,都可以得到相同的版本。同时也保证了项目依赖不会发生预料之外的恶意修改和其他问题。这也是为什么要将 go.sum 文件加入版本管理(Git)的原因。
语义化版本号格式为: X.Y.Z (主版本号.次版本号.修订号),使用方法如下:
- 进行不向下兼容的修改时,递增主版本号。
- API 保持向下兼容的新增及修改时,递增次版本号。
- 修复问题但不影响 API 时,递增修订号。
## 常用命令
- go mod init :创建一个新模块,初始化 go.mod 文件,参数为该模块的导入路径,推荐使用这种形式。如: go mod init github.com/linehk/example 。
- go get :更改依赖项版本(或添加新的依赖项)。
- go build 、 go test 等命令:Go 命令行工具会根据需要添加新的依赖项。如: go test ./... ,测试当前模块。
- go list -m all :打印当前模块依赖。
- go mod tidy :移除无用依赖。
- go list -m -versions github.com/gin-gonic/gin :列出该模块的所有版本。
- go mod verify :验证哈希。
#### go env
```
set GONOPROXY=
set GONOSUMDB=
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOSUMDB=off
```
设置GOPROXY代理:
```
go env -w GOPROXY=https://goproxy.cn,direct
```
设置GOPRIVATE 会同事设置GONOPROXY GONOSUMDB
设置GOPRIVATE来跳过私有库,比如常用的Gitlab或Gitee,中间使用逗号分隔:
```
go env -w GOPRIVATE=*.gitlab.com,*.gitee.com
```
关闭验证包的有效性
```
go env -w GOSUMDB=off
```
还原设置
```
go env -u GOSUMDB
```
忽略http安全(也不会走sumdb)
```
go get -insecure modxxx
```
所以在使用 Go 命令行工具或 go.mod 文件时,就可以使用语义化版本号来进行 模块查询 ,具体规则如下:
- 默认值( @latest ):将匹配最新的可用标签版本或源码库的最新未标签版本。
- 完全指定版本( @v1.2.3 ):将匹配该指定版本。
- 版本前缀( @v1 或 @v1.2 ):将匹配具有该前缀的最新可用标签版本。
- 版本比较( @<v1.2.3 或 @>=v1.5.6 ):将匹配最接近比较目标的可用标签版本。 < 则为小于该版本的最- 新版本, > 则为大于该版本的最旧版本。当使用类 Unix 系统时,需用引号将字符串包裹起来以防止大于小于号被解释为重定向。如: go get 'github.com/gin-gonic/gin@<v1.2.3' 。
- 指定某个 commit( @c856192 ):将匹配该 commit 时的版本。
- 指定某个分支( @master ):将匹配该分支版本。
![](../img/go/go-mod-1.png)
如上图所示,为了能让 Go Modules 的使用者能够从旧版本更方便地升级至新版本,Go 语言官方提出了两个重要的规则:
- 导入兼容性规则(import compatibility rule):如果旧包和新包具有相同的导入路径,则新包必须向后兼容旧包。
- 语义化导入版本规则(semantic import versioning rule):每个不同主版本(即不兼容的包 v1 或 v2)使用不同的导入路径,以主版本结尾,且每个主版本中最多一个。如:一个 rsc.io/quote、一个 rsc.io/quote/v2、一个 rsc.io/quote/v3。
```
module my-module/v2
require (
some/pkg/v2 v2.0.0
some/pkg/v2/mod1 v2.0.0
my/pkg/v3 v3.0.1
)
```
格式总结为pkgpath/vN,其中N是大于1的主要版本号。在代码里导入时也需要附带上这个版本信息,如import "some/pkg/v2"。如此一来包的导入路径发生了变化,也不用担心名称相同的对象需要向后兼容的限制了,因为golang认为不同的导入路径意味着不同的包。
不过这里有几个例外可以不用参照这种写法:
1. 当使用gopkg.in格式时可以使用等价的require gopkg.in/some/pkg.v2 v2.0.0
2. 在版本信息后加上+incompatible就可以不需要指定/vN,例如:require some/pkg v2.0.0+incompatible
3. 使用go1.11时设置GO111MODULE=off将取消这种限制,当然go1.12里就不能这么干了
除此以外的情况如果直接使用v2+版本将会导致go mod报错。
v2+版本的包允许和其他不同大版本的包同时存在(前提是添加了/vN),它们将被当做不同的包来处理。
另外/vN并不会影响你的仓库,不需要创建一个v2对应的仓库,这只是go modules添加的一种附加信息而已。
当然如果你不想遵循这一规范或者需要兼容现有代码,那么指定+incompatible会是一个合理的选择。不过如其字面意思,go modules不推荐这种行为。
而与 Git 分支的集成如下:
![](../img/go/go-mod-git.png)
vendor 目录
以前使用 vendor 目录有两个目的:
- 可以使用依赖项的确切版本用来构建。
- 即使原始副本消失,也能保证这些依赖项是可用的。
而模块现在有了更好的机制来实现这两个目的:
- 通过在 go.mod 文件中指定依赖项的确切版本。
- 可用性则由缓存代理($GOPROXY)实现。
而且 vendor 目录也很难管理这些依赖项,久而久之就会陷入与 node_modules 黑洞一样的窘境。
node_modules 黑洞
![](../img/go/go-mod-2.png)
所以,默认情况下使用 Go Modules 将完全忽略 vendor 的依赖项,但是为了平稳过度,可以使用 go mod vendor 命令可以创建 vendor 目录。
并在 Go 命令行工具使用 -mod=vendor 参数,如:go test -mod=vendor ./...;或设置环境变量 GOFLAGS 为 -mod=vendor,这样会假定 vendor 目录包含正确的依赖项副本,并忽略 go.mod 文件中的依赖项描述来构建。
## go-mod服务
proxy.golang.org-符合上提供的规范的模块镜像go help goproxy。
sum.golang.org-一个可审核的校验和数据库,go命令将使用该数据库对模块进行身份验证。有关更多详细信息,请查看“ 确保公共安全模块生态系统提案 ”。
index.golang.org-一个索引,用于提供新模块版本的供稿, proxy.golang.org可以使用这些新版本。可以在 https://index.golang.org/index 上查看提要。该提要以新行分隔的JSON形式提供,提供了模块路径(作为Path),模块版本(作为Version)以及proxy.golang.org首次缓存它的时间(作为Timestamp)。该列表按时间顺序排序。有两个可选参数:
- 'since':返回列表中模块版本的最早允许时间戳(RFC3339格式)。默认为时间的开始,例如 https://index.golang.org/index?since=2019-04-10T19:08:52.997264Z
- 'limit':返回列表的最大长度。默认值= 2000,最大值= 2000,例如 https://index.golang.org/index?limit=10
......@@ -8,6 +8,15 @@ pprof
https://www.cnblogs.com/qcrao-2018/p/11832732.html
编译出dll
https://www.cnblogs.com/timeddd/p/11731160.html
go build --buildmode=c-shared -o Test.dll
dotnet
[DllImport(DLL_NAME, EntryPoint = "Test")]
GO
用于让出CPU时间片
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册