go modules详解

开发心情不好 · · 1511 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

go modules详解

[TOC]

go1.11开始,支持使用go modules管理依赖包. 刚加入的适合尝试过, 并不是特别好用, 特别是需要从老的vendor方式切换过来.但是golang包管理一直为人诟病, 官方尝试解决是值得肯定和期待的.

1.13即将正式加入此特性, 有必要对使用方法做一些整理, 避坑备用吧.

原理简介

并没有仔细研究过实现原理,2018年Go team 技术leader Russ Cox在博客发布数篇文章详细阐述了包管理技术方案: vgo(versioned Go), 具体参考vgo wiki, 其主要思想是: 、语义化包导入版本 Semantic Import Versioning, 最小版本选择(MVS)Minimal Version Selection, 可复现、可验证且验证过的构建(方式或过程)Reproducible, Verifiable, Verified Builds, Go模块定义Defining Go Modules等.

vgo和包管理

其中vgo是原型描述, 因其最小版本选择与之前的dep等包管理方法冲突, 随着vgo代码并入主分支,go modules包管理机制成为官方工具, dep等包管理工具可能要退出江湖了.

语义化版本

细节可参考官网

  • 版本格式:主版本号(major).次版本号(minor).修订号(patch)
  • 主版本号:做了不兼容的 API修改
  • 次版本号:向下兼容的功能性新增或改动
  • 修订号:向下兼容的问题修正等

根据这种定义, 主版本号改动即视为不兼容之前大版本, 包管理机制也要使用不同主版本的包得到正确管理, 而次版本号以下的改动视为兼容, 会做合并

module定义

A module is a collection of Go packages stored in a file tree with a go.mod file at its root

模块是Go引用包的集合, 这些包保存在项目根目录的go.mod文件中描述的文件树中.

原理上简单看, 从主模块构建(build list)表开始,递归遍历其下依赖, 升级到指定版本兼容的最新版本, 合并兼容的版本,最后得到final list

对build lists到操作, 具体定义和算法描述(比如upgrade一个module,upgrade所有modules)请参考原文

  • Construct the current build list.
  • Upgrade all modules to their latest versions.
  • Upgrade one module to a specific newer version.
  • Downgrade one module to a specific older version.
  • 实际项目使用会生成2个文件: go.mod, go.sum(checksum)

使用实践

  • 使用Go1.11以上版本, 请关注迭代过程中的改变
  • 是否启用go modules可由环境变量GO111MODULE控制(auto, on, off), 默认为auto: 项目在$GOPAH/src外会自动启动,否则兼容老的vendor方式.
  • 虽然说项目不在依赖GOPATH, 但是`go mod`下载的依赖包会cache到GOPATH/pkg/mod下面, 会按版本组织
$GOPATH/pkg/mod/github.com/sirupsen/logrus@v1.4.1

help 文档

目前go mod使用多的是init, tidy等子命令

go help modules
go help mod
go help mod init|tidy|vendor
# go.mod文件帮助
go help go.mod

步骤

基本用法还是比较简单的, 以下为示例:

# 创建project
make hello-mod
touch main.go
# coding... and 导入包,

# go mod 初始化,会生成go.mod, 项目module名为hello-mod
go mod init hello-mod
go mod tidy
cat go.mod
# 或在代码中import,然后直接build或test
go build
# 查看当前包版本信息(包括间接引用),执行对应更新
go list -m -json all
# 带目录路径信息
go list -m -f={{.Dir}}
go get xxxx
go build ./...
# 或者直接run
go run main.go

也可使用vendor方式下载包到项目下.

go init hello-vendor
go mod vendor
go run main.go

最初Russ Cox打算彻底废弃vendor方式, 经社区讨论最终得以保留, 以兼容Go1.11之前版本.

实操示例

避坑指南

看示例挺简单,实际上还是遇到不少坑的

代理

因为某些原因有些包无法直接下载, 需要代理,目前官方提供:

a module mirror for accelerating Go module downloads, an index for discovering new modules, and a global go.sum database for authenticating module content.

proxy.golang.org - a module mirror
sum.golang.org - an auditable checksum database to authenticate modules.
index.golang.org - an index which serves a feed of new module versions

status应该还是beta, 目前测试在国内可用

# 查看帮助
go help goproxy
# 环境变量设置
export GOPROXY=https://proxy.golang.org
# 类似的代理还有不少,下面这个在香港有服务器, 速度挺快: 
export GOPROXY=https://goproxy.io

go.mod文件

go.mod文件可保证构建过程可重现.

  • module定义模块路径, 比如go init hello-mod指定的hello-mod,子目录下到包可以从此相对路径指定
# 例如之前示例的hello-mod,假设之下有子目录sub包,在代码中包含:
import "hello-mod/sub"
  • require 表示依赖包
replace example.com/some/dependency => example.com/some/dependency v1.2.3
  • exclude 排除某个特定包
  • replace 使用另外版本替代模块版本

这是个文本文件, 可手动修改:

  • 如果依赖包源不可访问, 如若golang.org/x/tools无法访问, 可使用replace
  • 获取特定版本, 或满足某些条件(大于、小于等关系), 在require下对应项修改版本号
  • module query: go mod edit -require='github.com/xxx/xxxx@>=v1.2.3' (老版是go mod -require)
# 修改go.mod
require github.com/sirupsen/logrus <v1.4.2
# 重新运行会重现解析下载满足条件的依赖
go run main.go
# 查看发现版本降级为v1.4.1
cat go.mod
require github.com/sirupsen/logrus v1.4.2

go.sum文件

go.sum为依赖包版本信息加密校验和(the expected cryptographic checksums)

  • 运行go命令会进行校验
  • go mod verify校验本地cache的包与go.sum是否匹配
  • 最好与go.mod一起上传到repo中, 用于下载后进行依赖包校验

build 选项

  • --mod=readonly, 不更新依赖, 如在ci过程中build
  • --mod=vendor, 使用项目顶层目录下的vendor,需要确保vendor包完整准确, 因为依然会忽略其他目录下的vendor包
go run -mod=readonly main.go

升级或降级包

go list -m -json all
go list -m -f={{.Dir}} all
run go get -u # to use the latest minor or patch releases
run go get -u=patch # to use the latest patch releases

社区相关工具

  • github.com/goware/modvendor, 帮助copy额外依赖文件
$ GO111MODULE=on go mod vendor
$ modvendor -copy="**/*.c **/*.h **/*.proto" -v
  • github.com/marwan-at-work/mod, 帮助自动升级/降级模块版本, 修改import路径(如增加版本号)

Command line tool to automatically upgrade/downgrade major versions for modules

GO111MODULE=on go get github.com/marwan-at-work/mod/cmd/mod
# 更新项目自身版本
mod upgrade
cat go.mod
# module hello-vendor/v2
# import "hello-vendor/v2/sub"

# 升级依赖包版本
mod upgrade --mod-name=github.com/x/y

需要注意的是 --mod-name如果是自身, 则go.mod中module不会升版本, 但是代码中引用自身子包的版本增加, 这是否算一个bug呢?

references

  • 见链接

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:开发心情不好

查看原文:go modules详解

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1511 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传