前端学Go之Go modules 依赖管理

72 阅读5分钟

之前的依赖管理

GOPATH

Go1.5之前通过gopath目录管理模块,在gopath目录下有src、bin、pkg三个目录,所有的go仓库都必须在gopath/src路径下创建。

Go vendor

Go1.5推出的依赖管理方式,类似于node的node_modules目录,在每个仓库下有一个vendor目录,包含项目所需的所有依赖。好处是仓库各自管理自身的依赖库。可以使用go mod vendor 命令构建仓库的vendor目录

社区管理工具

比如 godep、govendor、glide、dep 等。其中 dep 拥趸众多,而且也得到了 Go 官方的支持,项目也放在 Golang 组织之下 golang/dep。

Go mod****

Go mod是Go1.11推出的管理方式,优势在于可以在任何地方创建go仓库、支持依赖库多版本共存、接入本地依赖库等。go的GO111MODULE环境变量控制go mod的使用GO111MODULE =off不使用go mod。GO111MODULE =on开启使用,GO111MODULE =auto,在gopath/src目录下不使用。

从Go 1.11开始,当当前目录或任何父目录有go.mod时,go命令可以使用模块,前提是该目录在GOPATH/src之外。(在GOPATH/src之外。(在GOPATH/src之内,为了兼容,go命令仍然以旧的GOPATH模式运行,即使发现了go.mod。)。从Go 1.13开始,模块模式将成为所有开发的默认模式。

使用 go mod 管理项目

只需要在仓库目录下执行命令即可:

go mod init example.com/greetings

执行完毕后一般会生成go.mod和go.sum两个文件

go.mod文件

go的依赖管理文件,作用对比package.json。用于记录仓库所使用的依赖库信息和模块信息。go通过使用go.mod中列出的特定依赖模块版本来解决导入问题。go mod tidy 当它遇到go.mod中任何模块都没有提供的包的导入时,go会自动查找包含该包的模块,并使用最新版本将其添加到go.mod。

语法如下

 // 语法 module module-path module example.com/mymodule // 模块名字,一般是项目的地址名称 
// 语法 go minimum-go-version go 1.18 // 编译此模块中的包所需的最低 Go 版本
// 引用的主要模块路径  // 语法 require module-path module-version require (
    example.com/othermodule v1.2.3 // 常规依赖
    example.com/othermodule v0.0.0-20200921210052-fa0125251cc4 // 伪版本号的依赖库
    example.com/othermodule/v2 v2.2.3 // 具有破坏性的版本更新     example.com/othermodule v2.2.3+incompatible // 具有破坏性的版本更新,但没有遵循命名规范     gopkg.in/yaml.v2 v2.4.0 // 路径命令的例外
    )
// 带有// indirect注释的依赖,表示是间接依赖,通常是由于此依赖没有包含在任何其他依赖的go.mod文件中
require(
    example.com/othermodule v1.2.3 // indirect
)
// 替换模块路径  // 语法 replace module-path [module-version] => replacement-path [replacement-version] replace (
    example.com/thatmodule => ../thatmodule // 任何版本的thatmodule都将被替换为本地模块     example.com/thatmodule => example.com/other/thatmodule v1.3.0 //任何版本的thatmodule都将被替换为其他模块     example.com/thatmodule v1.3.0 => example.com/thatmodule v1.4.0 // 指定某个版本的thatmodule替换为其他模块 )
// 使用 exclude 指令排除间接需要但由于某种原因无法加载的模块的特定版本  // 语法 exclude module-path module-version exclude example.com/thismodule v1.3.0 // 排除指定版本的模块
// retract指令指示不应使用您的模块的先前版本。用户不会使用 go get、go mod tidy 或其他命令自动升级到撤回的版本。  // 就是说retract的版本号用户获取不到。当版本过早发布或版本发布后发现严重问题时,撤消指令很有用
// 一般是依赖库作者添加的  // 语法 retract version | [version-low,version-high] retract (
    v1.1.0
    [v1.1.0, v1.2.0]
)
// 以上语法都与import语法规则一样,可以单独使用,也可以合并使用,即:  // retract (  //  v1.1.0  //  [v1.1.0, v1.2.0]  // )  // 或者  // retract v1.1.0  // retract [v1.1.0, v1.2.0] 

注意:

  1. 使用replace 可以调用本地依赖库
  1. 当出现 使用相同依赖的不同版本时,当遵循最小版本选择(MVS)原则。
  1. 带有/v2或更高结尾的依赖库表示是一个具有破坏性新特性的版本,导入使用时可以不用管版本后缀。例如:

    1. import  example.com/othermodule/v2 v2.2.3 
      othermodule.Func()
      

go.sum

用于记录所有的依赖库信息和的校验数据信息以验证以来库没有被篡改,作用对比package-lock.json文件。

语法如下

// <module> <version> <hash>
// <module> <version>/go.mod <hash>
// <module> <version>+incompatible/go.mod <hash>
example.com/thatmodule v1.4.1 h1:s0hze+J01
example.com/thatmodule v1.5.2/go.mod h1:Qx5cxh0
example.com/thatmodule v1.5.2+incompatible/go.mod h1:Qx5cxh0

如果版本以 /go.mod 结尾,则哈希仅用于模块的 go.mod 文件;否则,哈希用于模块的 .zip 文件中的文件。模块版本可以 .zip 文件的形式分发。

哈希列由算法名称(如 h1)和 base64 编码的加密哈希组成,以冒号 (:) 分隔。目前,SHA-256 (h1) 是唯一支持的哈希算法。如果将来发现 SHA-256 中的漏洞,将添加对另一种算法(名为 h2 等)的支持。

go.sum 文件可能包含一个模块的多个版本的哈希值。 go 命令可能需要从依赖项的多个版本加载 go.mod 文件,以便执行最小版本选择。 go.sum 还可能包含不再需要的模块版本的哈希值(例如,在升级之后)。 go mod tidy 将添加缺失的哈希,并从 go.sum 中删除不必要的哈希。

资料:

  1. 模块压缩文件
  1. 模块认证Authenticating modules
  1. 谈谈go.sum

推荐阅读

  1. Tutorial: Create a Go module
  1. Using Go Modules
  1. Go Modules Reference
  1. 深入理解 Go Modules 的 go.mod 与 go.sum