缘起

最近, 打算升级govendor到go mod, 为什么呢?

  1. 版本化的语义, govendor中是 revision 和 revisionTime
  2. 本地多版本共存, 不再像之前kite升级后, 导致 生成 kite客户端 很费力(因为生成模板是老版本, 新老不兼容)
  3. 清晰的依赖管理, go module 是将依赖作为一个group的, 使用 govendor 无法很好的管理依赖, 升级往往是 升级完kite, 再升级kite依赖, 导致每次升级都是一次耗费时间的辛苦活
  4. 官方的toolchain
  5. replace语义, 方便本地替换
  6. exclude语义, 方便拦截一些bug的版本

参考

首先, 阅读来自swtch的依赖管理的三篇文章 0. 入口索引: https://research.swtch.com/vgo

  1. 第一篇: https://research.swtch.com/vgo-intro
    1. 讲述了依赖管理的演进 09 nothing -> 2010 go install -> 2011 go get, 存在没有版本的问题: 1. api 稳定性变更 2. 可重复构建.
    2. 未来的规划: dep/glide 不将支持, 发布了vgo(兼容目前的依赖管理), go mod 是未来
    3. go mod 的演示
  2. 第二篇: https://research.swtch.com/vgo-tour
    1. 讲述了vgo的使用 (没有明显的依赖树, mod文件、版本检查都是有的、执行依赖的测试!、可降级、可以指定拒绝版本、替换、后退兼容) 可以不用看了
  3. 第三篇: https://research.swtch.com/vgo-import 保证函数语义不可变, 避免单例(防止重复注册导致崩溃, 以http handler注册为例, 升级v1到v2, handler可以使用 /v2结尾) 原子API更新(//go:fix 的注释)
  4. 第四篇: https://research.swtch.com/vgo-mvs
    讲述了 build列表构建、升级所有模块(go get -u)、升级单个模块(单个升级, 并不是简单的拉去最新的依赖, 还要避免之前的依赖降级)、降级一个模块 formulas: Horn、 dual-Horn、 dual-Horn、 2-SAT NL-complete NP-complete 4.1 The unique minimal downgrade does not use an older version of a given module unless absolutely necessary 4.2 The unique minimal upgrade does not use a newer version of a given module unless absolutely necessary 4.3 Minimal version selection always selects the minimal (oldest) module version that satisfies the overall requirements of a build 4.4 replace 和 exlude 都是模块内部的 (替换是顶级模块的.) 4.5 A module author is therefore in complete control of that module’s build when it is the main program being built, but not in complete control of other users’ builds that depend on the module
  5. 第5篇: https://research.swtch.com/vgo-repro 可重复的构建, 可验证的构建. 引入 goversion 工具. 主要是vgo
  6. 第6篇: https://research.swtch.com/vgo-module 定义了go modules. 讨论了go mododule的特性: 有版本的release. go mod 文件格式. 一个仓库一个模块, 下载协议, 代理服务, vendor兼容
  7. 第7篇: https://research.swtch.com/vgo-cmd 讨论了构建隔离级别、自动下载, vgo的特性
  • 总结:
  1. 提出了 import compatibility rule(相同import路径的向后兼容)、minimal version selection(默认选择最老的)
  2. 大部分依赖管理工具 只处理了 依赖copy, 并没有解决版本依赖, 建议使用go mod
  3. glide、godep 停止开发, dep、vgo作为官方的试验品, 也建议升级到 go mod.
  4. gomodule的意思是:a group of packages versioned as a single unit
  5. 提出了 Hyrum’s law: http://www.hyrumslaw.com/

操作

创建项目

  1. 任意目录创建项目, 假设文件名 project
  2. 在project下创建doc.go (可以是其他文件), doc.go 写入 “package main // import “a.b.c” (如果是goapth路径下创建, 就不需要这一次的操作)
  3. 执行 go mod init project
  4. 编写代码, 确实依赖的时候, 执行 go mod tidy.
  5. 准备打包编译的时候, 建议使用vendor, 命令: go mod vendor

govendor->go mod

  1. go mod init (因为govendor的项目, 大都是gopath下面的, 所以单独使用doc.go那种申明方式)
  2. go mod vendor, 实现将原来的vendor目录进行重写.

新增

官方出了相关资料: 略微提及规划和使用方式: https://blog.golang.org/modules2019 使用姿势: https://blog.golang.org/using-go-modules 起草go module的一个历程总述: 写了个原型, 然后写草案了, 然后成了 go module: https://blog.golang.org/versioning-proposal 官方的proposal: https://github.com/golang/go/issues/24301 ???? https://github.com/golang/proposal/blob/master/design/24301-versioned-go.md

新增 2020/05/07

go mod 已经发展了一段时间, 线上也已经运行了一年多, 这里总结一些经验以及新的文章

官方采坑: - https://github.com/golang/go/wiki/Modules - https://golang.org/cmd/go/#hdr-Module_configuration_for_non_public_modules

常用的姿势:

go get [email protected], 
go get foo@master (foo@default with mercurial), 
go get foo@e3702bed2

内部实现

最近突然对golang module 内部实现感兴趣, 通过搜索, 发现代码在 src/cmd/go/internal, 布局如下:

modcmd/...
modconv/...
modfetch/...
modget/...
modinfo/...
modload/...