go modules 基础

引言

go 语言支持 go modules 特性已经快两年了,但很多项目由于种种原因还没有实施迁移。这几天想写一篇文章,全面的阐述一下 go modules 特性,使得读者快速掌握其要点,从而低成本的将项目的包管理迁移到 go modules。

考虑到实战部分的内容较多,将计划的一篇文章拆分为多篇来呈现,一层层的慢慢揭开 go modules 的神秘面纱。本文为开篇,主要介绍 go modules 的基础知识。

go modules 背景

在 go1.5 发布后的若干年,gophers 把注意力都集中在如何利用 vendor 机制来解决包依赖问题,从手工添加依赖到 vendor、手工更新依赖,到一众包依赖管理工具的诞生,比如: govendorglide 以及号称准官方工具的 dep,都在努力地尝试着按照当时的主流思路来解决诸如“钻石型依赖”等难题。

正当 gophers 认为 dep 将“顺理成章”地转正为 go toolchain 一部分的时候,vgo 横空出世,并通过对 “Semantic Import Versioning” 和 ”Minimal Version Selected” 的设定,在原 go tools上简单快速地实现了 go 原生的包依赖管理方案 这个 vgo 就是 go modules 的前身。

go modules 定义

通常,我们会在一个 go 代码库中创建一组包,而代码库的路径会作为包的导入路径,比如 github.com/agiledragon/gomonkey。在 go1.11 版本中,给在同一代码库下面的这样一组包定义了一个新的概念叫 modulemodule 根目录一般叫 module root 目录。

一个代码库只有一个 module 吗?一般情况是这样,但也可以有多个 module

go mod可以看作是 go modules 的简称。

go mod 配置

go1.11 在引入 go modules 特性时,增加了一个特性开关(环境变量)GO111MODULE,对应的值有三个:auto,on,off。

下面详细解释一下这三个值的含义:

  • 当 GO111MODULE 的值为 off 时,go modules 机制关闭,go 编译器会始终使用 GOPATH mode,即无论要构建的源码目录是否在 GOPATH 路径下,go 编译器都会在传统的 GOPATH 和 vendor 目录下搜索目标程序依赖的包;
  • 当 GO111MODULE 的值为 on 时,go modules 机制始终开启,与off 相反,go 编译器会始终使用 module-aware mode,即无论要构建的源码目录是否在 GOPATH 路径下,go 编译器都不会在传统的 GOPATH 和 vendor 目录下搜索目标程序依赖的包,而是在 go mod 命令的缓存目录($GOPATH/pkg/mod)下搜索对应版本的依赖包;
  • 当 GO111MODULE 的值为 auto 时(默认值),使用 GOPATH mode还是 module-aware mode,取决于要构建的源码目录所在位置以及是否包含 go.mod 文件:a. 对于 go1.11 和 go1.12 版本,如果要构建的源码目录不在以 GOPATH/src 为根的目录体系下,且包含go.mod文件(两个条件缺一不可),那么使用 module-aware mode,否则使用传统的 GOPATH mode;b. 对于 go1.13及以上版本,如果要构建的源码目录包含 go.mod 文件,那么使用 module-aware mode,否则使用传统的 GOPATH mode。

GOPATH mode & GOPATH 环境变量

使用 module-aware mode 后,用户可以不用再配置 GOPATH 环境变量了,但细心的读者可能已经发现 go mod 命令的缓存目录为 $GOPATH/pkg/mod

那到底还要不要配置GOPATH 环境变量了?

从 go1.8 版本开始,GOPATH 有了默认值,即 $HOME/go。如果用户配置了 GOPATH 环境变量,则覆盖默认值。所以,在 module-aware mode 下,不管用户是否配置了 GOPATH 环境配置,$GOPATH 都有确定的值,无非是否为默认值的问题,所以 go mod 命令的缓存目录 $GOPATH/pkg/mod 是有效的。

综上,使用 go modules 机制管理依赖包后,我们弃用的是 GOPATH mode,而不是 GOPATH 环境变量,当然你也可以不设置 GOPATH 环境变量,go 编译器直接使用 GOPATH 默认值也 OK。

go mod 命令

go 编译器提供了 go mod 命令来管理依赖包。

go mod 主要包括下命令:

命令 说明
download download modules to local cache(下载依赖包)
edit edit go.mod from tools or scripts(编辑go.mod)
graph print module requirement graph (打印模块依赖图)
init initialize new module in current directory(在当前目录初始化mod)
tidy add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
vendor make vendored copy of dependencies(将依赖复制到vendor下)
verify verify dependencies have expected content (验证依赖是否正确)
why explain why packages or modules are needed(解释为什么需要依赖)

go mod 文件

go mod 文件主要包括 go.mod 和 go.sum,这两个文件在 module root 目录下,都要提交到代码库。

使用 go mod 管理依赖后,在 module root 目录下:

  • 运行 go mod init 命令会自动生成 go.mod 文件,该文件记录当前代码工程的所有依赖库及版本,可以通过 go 的命令来维护
  • 运行 go build 或 go run 命令会自动生成 go.sum 文件,该文件记录每个依赖库特定版的哈希值,可以确保下次获取的第三方依赖与本次相同

go.mod 文件提供了 module,require,replace 和 exclude 等命令:

  • module 语句指定包的名字(路径)
  • require 语句指定依赖的模块列表
  • replace 语句可以替换某个 require 指定的模块
  • exclude 语句可以忽略某个 require 指定的模块

goconvey 测试框架的 go.mod 文件:

module github.com/smartystreets/goconvey

require (
    github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
    github.com/jtolds/gls v4.20.0+incompatible
    github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d
    golang.org/x/tools v0.0.0-20190328211700-ab21143f2384
)

goconvey 测试框架的 go.sum 文件:

github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

go proxy

顾名思义,go proxy 是 go 语言的代理,一般是配合 go modules 使用,可以使用户方便且快速的获取第三方包,尤其是 go 官方的一些包。

作者本机配置的 go proxy 为:

bogon:~ zhangxiaolong$ echo $GOPROXY
https://goproxy.cn,direct

go 团队包管理从传统 GOPATH mode 迁移到 module-aware mode 后,代码库中没有了 vendor 目录,而增加了 go.mod 文件和 go.sum 文件。在 CI 流水线上编译版本时,需要实时获取依赖,但从外网下载所有依赖的第三方包有一些问题:

  • 很慢(外网速度比内网速度慢太多)
  • 不方便(有的环境无法上外网)
  • 下载失败(墙的原因)

此时,在公司内网搭建一个私有的 go proxy 就使得这些问题迎刃而解。

小结

本文主要介绍了 go modules 的基础知识,包括背景、定义、配置、模式、命令、文件和代理等内容,希望对读者感性认识 go modules 特性有一定的帮助。

下一篇文章将开启实战部分,作者将使用 go1.14 版本,通过一些小案例来初步解析 go modules 机制,名字叫啥好呢?
“什么天长地久,只是随便说说,你爱我那一点,你也说不出口......”。突然,听到了张震岳的成名曲《爱的初体验》,要不下一篇文章就叫 《go modules 初体验》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352