Go 包管理历史以及 Go mod 使用
之前也写过 Go 管理依赖工具 godep 的使用,当时看 godep 使用起来还是挺方便,其原因主要在于有总比没有强。关于依赖管理工具其实还是想从头聊聊这个需求以及大家做这个功能的各种出发点。
GOPATH 和 GOROOT
GOROOT 这个变量的作用就是为了告诉当前运行的 Go 进程当前 Go 安装在哪里,当你想要运行的时候去哪里找 Go SDK相关的类。
GOPATH 这个设定其实从语言层面上来说就有点反设计模式。主要原因在于 Go 刚出生的时候没有自带包管理功能,默认所有的项目和引用的第三方包都下载到 src 目录下,第三方包对于 Go 而言也是一个可用的Go项目,这一点跟 Java 区别还是挺大。
那 GOPATH 是否可以设定多个呢?当让可以,并且人家就是这么让你用的。
比如你有项目A,设定的 GOPATH 是:/src/projA/
,那么A项目所有的依赖都会下载在这个目录。
比如你有项目B,设定的 GOPATH 是:/src/projB/
,那么B项目所有的依赖都会下载在这个目录。
而如果你使用同一个 GOPATH,那么你所有的项目 down 下来的依赖都在 src 目录下,这时候就有版本的问题,如果 A 项目想用 依赖 C 的 1.0.0 版本,B 项目想用依赖 C 的 1.0.1 版本,这时候该怎么指定呢?
正确的 GOPATH 就是一个项目一个。
包管理历史上的“恩怨情仇”
所以问题来了,一个项目一个 GOPATH,如果我有三个项目是个超级无敌大系统,可能会 down 下来整个 github 上的开源库,那这存储都是问题啊。
针对 Go 官方对包管理的乱象无动于衷,社区的同学们实在是忍无可忍,相继开源了各种包管理工具。
13 年的时候 Godep 诞生,原理很简单,跟 maven 一样,指定一个统一的包管理目录,将这个目录作为唯一的 GOPATH。也是在这一年 Docker 开始火起来了, Go 作为微服务开发“非官方指定语言”被广泛使用,同时矮子里面拔高子, dep 也绽放异彩。
15年 Go 官方被社区倒逼,1.5 版本同步带上了一个实验性质的功能 vendor 机制。由于默认情况下是关闭态,所以 normal 用户无感知,super 用户才会去体验。1.6 版本的时候该功能才打开为正常使用状态。
那么什么是 vendor 机制呢?简单说就是在你的项目中包含一个 vendor 的文件夹,它代替了通用的 GOPATH 目录,你项目中所有的依赖都会在这里存在。有了 vendor 好处显而易见,你再也不用手工修改 GOPATH 了,每个人运行环境的包也都统一了起来。
但是问题也随之而来,如果你依赖的一个项目也使用 vendor 管理依赖,那不就形成了嵌套依赖了吗?这种情况怎么处理。
当然还有别的各种问题,总之这也不是一个能拿得出手的成熟方案。
后面又出了 glide 等等社区的方案,但是到这里为止官方还是没有出一个能一统天下的方案。
当时 Google 官方的 Go 负责人 Russ 其实是有和 dep 的开发者 Sam 沟通让他修改一些设计以便将 dep 继承到 go 命令中去,但是由于一些观念上的原因 Sam 并没有接受,所以也因此错过一段良缘。
后面官方由于社区的压力在Go 1.11 版本的时候集成了新特性 Go modules。这是首次以官方名义开发的包管理工具。Go 命令直接支持 modules 相关用法。
Go modules
Go modules 是官方推出的依赖管理工具,Go modules 提供了3个重要的功能:
go.mod
文件,它与package.json
或Pipfile
文件的功能类似。- 机器生成的传递依赖项描述文件 :
go.sum
。 - 不再有 GOPATH 限制。模块可以位于任何路径中。
要想使用 Go modules 请升级到 1.11 及其以上版本,1.13 版本已经默认开启 Go modules,如果想体验这个功能建议将 Go 版本升级到 1.13。
另外,这个功能默认并不是开启的,需要手动设置环境变量开开启:
go env -w GO111MODULE=on
go env -w
是Go 1.13 新增的命令,用于写入环境变量。写入的地方是os.UserCOnfigDir
所在的目录。
GO111MUDULE
变量是 Go modules 的开关。 有以下几个参数:
- auto:如果项目包含了 go.mod 文件,则启用 Go modules 功能。在Go 1.13 中是默认值。
- on:始终开启 Go modules。
- off:禁用 Go modules。
使用
首先我们在 GOPATH外新建一个目录,比如 usr/local/mod-demo
,进入目录下,生成 go.mod
文件:
Go mod init mod-demo
打开我们刚生成的 go.mod 文件可以看到:
module mod-demo
go 1.13
go.mod 文件是开启 modules 的必备配置文件。它记录了当前项目引用的包数据信息。go.mod 文件中定义了以下关键词:
- module:用于定义当前项目的模块路径
- go:用于设置Go 版本信息
- require:用于设置一个特定的模块版本
- exclude:用于从使用中排除一个特定的模块版本
- replace:用于将一个模块版本替换为另一个模块版本
接下来添加项目外的依赖:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
d := gin.Default()
d.GET("/index", func(c *gin.Context) {
c.JSON(200, gin.H{"message":"hello world","data":""})
})
d.Run("127.0.0.1:8080")
}
上面我们添加了 gin 的依赖包,然后看 go.mod 的内容:
module mod-demo
go 1.15
require github.com/gin-gonic/gin v1.6.3
可以看到已经添加了依赖。
以下版本格式都是合法的:
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
gopkg.in/vmihailenco/msgpack.v2 v2.9.1
gopkg.in/yaml.v2 <=v2.2.1
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
latest
Go module 安装 package 的原則是先拉最新的 release tag,若无tag则拉最新的commit,详见 Modules官方介绍。 Go 会自动生成一个 go.sum 文件来记录 dependency tree:
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
......
......
......
这里会记录当前以来的依赖包所依赖的依赖。
另外,之前我们在 golang.org 上下载不下来的包,直接使用 github 上的镜像,使用 module 之后可以使用 replace 关键字来个替换:
比如你之前引用是这样的:
require (
golang.org/x/text v0.3.2
)
那么使用 replace 之后就是这样的:
require (
golang.org/x/text v0.3.2
)
replace golang.org/x/text v0.3.2 => github.com/golang.org/text v0.3.2
执行命令go list -m all
也可以查看当前所有依赖项。
Go modules 有如下常用命令:
download download modules to local cache (下载依赖的module到本地cache))
edit edit go.mod from tools or scripts (编辑go.mod文件)
graph print module requirement graph (打印模块依赖图))
init initialize new module in current directory (再当前文件夹下初始化一个新的module, 创建go.mod文件))
tidy add missing and remove unused modules (增加丢失的module,去掉未用的module)
vendor make vendored copy of dependencies (将依赖复制到vendor下)
verify verify dependencies have expected content (校验依赖)
why explain why packages or modules are needed (解释为什么需要依赖)
GOPROXY加速
Go 很多包都会被 GFW 墙掉,现在有了Go modules 就可以解决了。
Go modules 支持配置镜像源,从而更快更稳定的完成 go get 操作,大家只需要 export GOPROXY 配置一下即可,推荐的源地址:https://goproxy.io/。
Go 包管理历史以及 Go mod 使用的更多相关文章
- python包管理历史
1.标准库工具distutils,2000年发布,是包安装和发布工具 setup.python 程序,利用distutils 开发 示例: python setup.py install 安装一个包 ...
- 包管理神器-pipenv
一:前言 介绍一个包管理神器-pipenv,这个工具可以让我们在写代码.创建Python运行环境.package依赖关系以及项目合作的时候更有效率. 在pycon2018上,Kenneth Reitz ...
- Go包管理go mod使用
Go Modules介绍 为了解决Go包管理的问题,Go从1.11开始加入了Go Modules这一新特性.让包的依赖和版本管理更加容易. 一个module可以理解为一个单独的包或者模块,module ...
- 拜拜了,GOPATH君!新版本Golang的包管理入门教程
Go 1.11和1.12实现了对包管理的初步支持,Go的新依赖管理系统使依赖版本信息明确且易于管理.Using Go Modules - The Go Blog 新的包管理模式有什么不同? 作为Go语 ...
- Golang 包管理机制
Golang 包管理机制 1. 历史 在go1.11之前, 并没有官方的包管理机制(Godep算个半官方), 主流的包管理机制有: GoVendor Glide Godep 在go1.11之后, 官方 ...
- 层次分明井然有条,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang包管理机制(package)EP10
Go lang使用包(package)这种概念元素来统筹代码,所有代码功能上的可调用性都定义在包这个级别,如果我们需要调用依赖,那就"导包"就行了,无论是内部的还是外部的,使用im ...
- Helm包管理
Helm Kubernetes 包管理工具 Helm 可以帮助我们管理 Kubernetes 应用程序 - Helm Charts 可以定义.安装和升级复杂的 Kubernetes 应用程序,Char ...
- Linux程序包管理之rpm
rpm简介 rpm( Red Hat Package Manager )是一个开放的软件包管理系统.它工作于Red Hat Linux及其他Linux系统,成为Linux中公认的软件包管理标准. rp ...
- Linux程序包管理之yum及源代码安装
第十六章.Linux程序包管理之yum及源代码安装 目录 yum介绍 yum配置文件 yum的repo配置文件中可用的变量 yum命令的使用 使用光盘作为本地yum仓库 如何创建yum仓库 编译安装的 ...
随机推荐
- windows下搭建ElasticSearch
1.官网下载ElasticSearch,需要java环境支持 地址:https://www.elastic.co/products/elasticsearch 2.下载后解压到目录 ...
- python文档翻译之使用python解释器
Python解释器通常安装在/usr/local/bin/python3.6,把/usr/local/bin目录设置到UNIX shell的搜索路径就可以使用下面的命令运行python: python ...
- 《Java并发编程的艺术》笔记
第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...
- 刷题[WUSTCTF2020]CV Maker
解题思路 好家伙,打开一看像是cms,又看名字CV Maker.我以为直接要搜cve打了.搜了一会发现没什么啊.那先正常做把. 注册 注册成功后这里报错,猜测可能有注入点.先放在这里,继续登陆.发现是 ...
- MySQL分区 (分区介绍与实际使用)
分区介绍: 一.什么是分区? 所谓分区,就是将一个表分成多个区块进行操作和保存,从而降低每次操作的数据,提高性能.而对于应用来说则是透明的,从逻辑上看只有一张表,但在物理上这个表可能是由多个物理分区组 ...
- 工具请求接口参数为string类型的JSON字符串时需要加转义字符模拟测试
例如postMan传String类型的json字符串请后台接口时,需要\转义
- NIO 实现简单群聊功能
服务端: package com.yang.runnable; import java.io.IOException; import java.net.InetSocketAddress; impor ...
- spring BeanDefinition 继承结构图
ConfigurationClassBeanDefinition 是ConfigurationClassBeanDefinitionReader的静态内部类
- CTFweb方向小知识点
1)转义字符 \x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39 这玩意叫转义字符,在C.C++里直接用cout << "\x35\x2c\ ...
- 怎么写一个Activity
a.新建一个类继承Actitvity b.重写oncreate方法 setContentView(R.layout.XXX);//设置布局文件 c.注册activity <activity an ...