Go modules

Golang具有相当长的包管理工具的变迁史,由于官方没有实现足够好用的包管理工具,各种包管理工具层出不穷。

GOPATH

  • 使用GOPATH管理依赖

Golang的包管理方式最初采用的是monorepo模式,即所有包都放在GOPATH下,使用类似命名空间的包路径来区分包。

几乎所有的包管理工具在Golang1.11版本之前都绕不开GOPATH环境变量,GOPATH主要用来放置项目依赖包的源代码。由于GOPATH不区分项目,代码中任何import的路径都需要从GOPATH为根目录的位置开始查找。

$ go env | grep GOPATH
set GOPATH=F:\Go\workspce

GOPATH目录下包含三个子目录分别是bin、pkg、src

子目录 描述
bin 存储编译后生成的二进制文件
pkg 存储预编译的目标文件,以加快程序后续编译速度。
src 存储源代码

使用GOPATH方式管理项目依赖时,编写Go应用程序时,程序包和库文件会以$GOPATH/src/github.com/foo/bar的路径形式进行存放。因此就必须将项目源代码固定存放在$GOPATH/src目录下,若执行go get拉取外部依赖时会自动下载并安装到GOPATH目录下。

使用GOPATH环境变量管理项目依赖包的缺点

  • 由于依赖包可能会引入破坏性的更新,会产生生产环境和测试环境不一致的问题。
  • 不区分依赖项的版本
    多个项目时不同项目对于依赖库的版本需求经常是不一致的,然后却无法在一个GOPATH路径下放置不同版本的依赖项。因此只能通过人工判断更新,使用非常不便。
  • 依赖项列表无法数据化
    Go Modules之前是没有任何语义化的数据可以知道当前项目的所有依赖项,因此需要手工找出所有依赖。对项目而言,需要将所有依赖项全部放入到源代码控制中。若剔除某个依赖则需在源码中手工确认某个依赖是否被剔除。

为解决GOPATH的缺陷,Go官方和社区推出了许多解决方案,比如godep、govendor、glide等。但这些工具要么无法彻底解决GOPATH存在的问题,要么使用起来繁冗。

Go Modules

  • Go Modules是语义化版本管理依赖项的包管理工具,解决GOPATH存在的缺陷。
  • Go Modules的前身是vgo,于Golang v1.11新增特性。

使用Go Modules后无需再将代码放置到GOPATH下的src目录中,Go Modules替换旧的基于GOPATH来指定在给定构件中使用的源文件。Go Modules可将项目文件夹下所有依赖整理后写入名为go.mod的项目依赖管理文件中。

使用Go Modules管理项目依赖包时会在项目根目录下生成两个文件,分别是go.modgo.sum

  • go.mod文件中会记录当前项目的所有依赖项
  • go.sum文件中会记录每个依赖包的版本和对应哈希值

go env

查看当前Go版本

$ go version
go version go1.15.6 windows/amd64

查看环境变量中Go模块的配置项,查看是否已开启Go Modules功能。

配置项 默认值 描述
GO111Modules off 是否开启Go Modules功能
GOPROXY https://proxy.golang.org,direct 设置Golang代理商为用户提供包下载的地址
$ go env
set GO111MODULE=on
set GOPROXY=https://goproxy.io

GO111MODULE

  • GO111MODULE这个命名代表着Golang于1.11版本时添加对Go Modules的支持。
  • GO111MODULE具有三个可选值onoffauto(默认)
描述
auto 默认值,根据当前目录来决定是否启用Go Modules功能。
off 禁用Go Modules功能
on 启用Go Modules功能
  • auto默认值,go命令根据当前目录来决定是否启用Go Modules功能。
    只有在当前目录位于GOPATH/src之外且该目录包含go.mod文件,或者当前文件在包含go.mod文件的目录下时才会自动开启。
  • off表示go命令禁用Go Modules功能,寻找依赖包时将会沿用旧版本通过vendor目录或GOPATH模式来查找。
  • on表示go命令启用Go Modules功能,因此不会去GOPATH目录下查找依赖。

命令行开启Go Modules功能

$ export GO111MODULE = on

当Go Modules模块功能开启后,依赖包的存放位置将会变更为$GOPATH/pkg,同时会允许同一个package包多个版本共存,且多个项目可以共享缓存的模块。

GOPROXY

  • GOPROXY的值会以一个英文逗号,作为分隔符来分割多个Go依赖包代理商列表。
  • GOPROXY中的direct是一个特殊的标识符,用于指示Golang回溯到依赖项的源地址去抓取。
$ go env | grep GOPROXY
set GOPROXY=https://goproxy.cn,direct

中国Golang中间代理商包下载地址

代理商 地址
Golang中国 https://goproxy.io
阿里云 https://mirrors.aliyun.com/proxy/
七牛云 https://goproxy.cn

设置Golang代理商为七牛云

$ go env -w GOPROXY=https://goproxy.cn,direct
$ go env|grep GOPROXY
set GOPROXY=https://goproxy.cn,direct

go mod

Go Modules包管理器提供了go mod命令用于管理项目依赖项。

  • go mod命令支持记录和解析对模块的依赖性
  • go mod管理项目依赖无需再将项目放到GOPATH/src指定目录下,可在磁盘的任何位置新建项目。
$ go help mod 
Usage:

        go mod <command> [arguments]

The commands are:

        download    download modules to local cache
        edit        edit go.mod from tools or scripts
        graph       print module requirement graph
        init        initialize new module in current directory
        tidy        add missing and remove unused modules
        vendor      make vendored copy of dependencies
        verify      verify dependencies have expected content
        why         explain why packages or modules are needed

Use "go help mod <command>" for more information about a command.
命令 描述
go mod download 下载依赖包
go mod edit 编辑go.mod文件
go mod graph 打印模块依赖图
go mod init 当前目录下初始化模块
go mod tidy 拉取缺少的依赖项或移除无用的依赖项
go mod vendor 将依赖复制到项目根目录下的vendor目录中
go mod verify 验证依赖项的哈希值是否正确
go mod why 解释为什么需要依赖

go mod init

初始化Go Modules,首先需要进入项目根目录,执行Go Modules初始化命令,生成go.mod项目依赖管理文件。

$ mkdir projname && cd projname
$ go mod init projname

使用go mod init初始化项目依赖后会生成两个文件

文件 描述
go.mod 项目依赖包管理文件
go.sum 项目依赖包的版本控制文件

go.mod

$ vim go.mod
module ginv

go 1.15

require (
    github.com/allegro/bigcache/v2 v2.2.5 // indirect
    github.com/allegro/bigcache/v3 v3.0.0
    github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
)

go.mod文件只能存在于模块(包)的根目录下,子目录中的导入路径会使用“模块的导入路径+子目录路径”的形式。

Go命令行工具会自动处理go.mod中指定的模块版本,当在源代码中使用import导入指定的依赖项不存在于go.mod文件中时,Go命令行工具会自动搜索这个依赖项,并会将最新的版本(最后一个tag且非预发布的稳定版本)添加到go.mod文件中。

github.com/allegro/bigcache/v3 v3.0.0

若依赖项没有tag,则会使用伪版本(专门的版本语法,用于标记没有tag的提交)。

github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

go.mod文件是面向行的,当前模块或主模块通常会位于第一行,接下来根据路径依次排序需要加载的依赖项。go.mod文件中每一行会包含一个指令,该指令由一个前导动词后跟参数组成。

前导动词 描述
module 指定当前模块的名字或路径
go 设置预期Golang语言的版本号
require 指定给定版本或更高版本的特定依赖项
exclude 指定忽略或排除的特定版本的依赖项
replace 指定可替换的依赖项
  • 前导动词可以按块的方式来使用,使用圆括号()包裹。
  • 注释仅能使用//单行注释,禁止使用/*多行注释*/
  • indirect注释表示当前依赖项不是被当前模块直接导入的,是间接引用的。

go mod vendor

  • Golang v1.5开始Golang引入了vendor包模式

当内部构建系统处于无网环境,依赖项需要纳入内部版本控制时,Go Modules提供go mod vendor工具。

$ go mod vendor

go mod vendor命令会在当前项目根目录下创建vendor目录,然后将项目所有依赖缓存到此,另外vendor目录可直接进入内部版本控制。使用go mod vendor的好处在于不依赖网络上游的版本,在本地内部自由地使用稳定可控的版本进行构建,因此也成为了非开源项目的主要构建方式。

默认情况下go build构建时会主动忽略vendor目录,若希望从本地vendor目录下开始构建则需使用go build -mod vendor命令。

$ go build -mod vendor

若项目目录下存在vendor目录,Go工具链会优先使用vendor内的包进行编译、测试等。之后第三方的管理方式都通过此种方式来实现。

go mod download

go mod download命令用于下载依赖到文本,而非使用go get。若GOPROXY设置镜像地址,此时会将依赖全部下载依赖到本地缓存GOPATH文件夹,依赖项版本数据均会缓存在$GOPATH/pkg/mod$GOPATH/pkg/sum文件夹下。同时会在项目根目录下生成go.sum文件。

go mod edit

编辑go.mod文件,格式化该文件。

$ go mod edit -fmt

添加依赖

$ go mod edit -require=golang.org/x/text

go list

  • 使用命令行查看项目依赖文件
$ go list -m all

go list -m

显示所有import库信息,-json表示使用JSON格式显示,all表示全部库。

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

推荐阅读更多精彩内容

  • Go Module是Go用来进行模块(模块是Go里面最小的源代码依赖管理单元)依赖管理,对所有引入的模块标记版本号...
    taj3991阅读 1,067评论 0 1
  • Go语言的依赖管理随着版本的更迭正逐渐完善起来。 windows开启go module:set GO111MODU...
    雪上霜阅读 367评论 0 0
  • go modules 是 golang 1.11 新加的特性。 1、设置go mod GO111MODULE GO...
    Bug2Coder阅读 1,926评论 0 1
  • 一、背景 事情是这样的,因为小马本次要写一个go项目。但是因为一些权限问题,一些依赖包在内网小马获取不到,于是只能...
    小马过河R阅读 14,869评论 45 6
  • 夜莺2517阅读 127,718评论 1 9