龙空技术网

Golang包管理详解

利哥AI实例探险 147

前言:

眼前大家对“golang 依赖包”大约比较关切,我们都想要了解一些“golang 依赖包”的相关知识。那么小编同时在网上搜集了一些关于“golang 依赖包””的相关知识,希望我们能喜欢,各位老铁们快快来学习一下吧!

1. 理解 go import

import 导入包,包名是从 GOPATH 开始计算的路径,使用 / 进行路径分隔;

在使用IDE时,不用手动import包,例如使用 fmt 包,在敲入 fmt. 时,编译器会警告,此时敲回车,包会被自动 import

 import (  常见操作:"fmt" //fmt是Go的标准库,去GOROOT/src下加载该模块  相对路径:"./model" //当前文件同一个目录的model目录,但不建议这种方式import  绝对路径:"shorturl/model" //加载GOPATH/src/shortul/model 模块  点操作:. "fmt" //点操作含义是这个包导入之后,在调用这个包函数时,可省略前缀的包名,如Println(12),不建议这样使用  _ 操作:_ "github.com/mattn/go-sqlite3" // _ 操作其实只是引入该包,当导入一个包时,它所有的 init() 函数就会被执行,但有些时候并非真的需要使用这些包,仅仅是希望它的 init() 函数被执行而已,这个时候就可以使用 _ 操作引用该包了。 )
 package main  import (   "fmt"   _ "golang_mainInit_Src/initmaintest1"   _ "golang_mainInit_Src/initmaintest2" ) 编译失败提示: c:/go/bin/go.exe build [C:/golang/src/golang_mainInit_Src] main.go:5:2: cannot find package "golang_mainInit_Src/initmaintest1" in any of:   c:\go\src\golang_mainInit_Src\initmaintest1 (from $GOROOT)   C:\Users\zhang\go\src\golang_mainInit_Src\initmaintest1 (from $GOPATH)

import 是用一个独一无二的字符串路径来指向包,而包的导入路径是基于工作目录的,因为 go 会在工作目录的 src 下查找包,即在 GOROOT(或GOAPTH)/src 下找。

 如果,F:/TestGo/ 是我的工作目录,则需要在 GOPATH 中添加此为工作目录 源码需要放在工作目录的 src 目录中,import 会搜索工作目录下的 src 的子目录  F:/TestGo/ F:/TestGo/src/thirdlib/lib1/hello.go  package hello1 F:/TestGo/src/thirdlib/lib2/world.go  package hello2 F:/TestGo/src/main.go {     package main     import (       "thirdlib/lib1"       "thirdlib/lib2"     )     func main() {         hello1.SayHello()         hello2.SayHello()     } } 1. import 导入的参数是路径,而非 “包名”; 2. 尽管习惯将“包名”和“目录名”保证一致,但这不是强制规定; 3. 在代码中引用包成员时,使用 “包名” 而非 “目录名”; 4. 至于“文件名”(扩展名为 .go),更没啥限制; 5. 同一目录下,所有源文件必须使用“相同的包名称”,因为导入时使用绝对路径,所以在搜索路径下,包必须有唯一路径,但无需是唯一名字;
2. 理解 vendor 特性

随着Go 1.5 release版本的发布,vendor目录被添加到除了GOPATHGOROOT之外的依赖目录查找的解决方案。在Go 1.6之前,你需要手动的设置环境变量GO15VENDOREXPERIMENT=1才可以使Go找到Vendor目录,然而在Go 1.6之后,这个功能已经不需要配置环境变量就可以实现了。

即使使用vendor,也必须在GOPATH中,无论是通过IDE设置项目目录的GOPATH还是通过go环境变量设置GOPATH(这与go module无关)

 在执行 go build 或 go run, 会按照一下规则顺序去查找包: GO111MODULE=off时,如果一个包在vendor和$GOPATH下都存在,那么使用顺序为: 1.优先使用 vendor 目录下的包; 2.如果未找到,则从上级目录的 vendor 路径下搜索,直到src的vendor路径下面搜索; 3.在 GOROOT/src 目录下查找; 4.在 GOPATH/src 下面查找依赖包; 5.要么完整使用 vendor 下面的包,要么完整使用 GoPATH/src 下面的包,不会混合使用;
3. Go包管理的发展

为了解决 Golang 依赖问题,类似于 Rust 的 Cargo、Node.js 的 NPM、Python 的 Pip、Ruby 的 Boundler 等,Golang 最原始的依赖管理是 go get,执行命令后会拉取代码放入 GOPATH/src 下面,但是它是作为 GOPATH 下全局的依赖,并且 go get 还不能版本控制,以及隔离项目的包依赖。

对于以上这些问题,在go mod出现之前,有dep,govendor等包管理工具的出现,但都多多少少存在缺陷。

从 Go 1.11 版本开始,官方已内置了更为强大的 Go modules 来一统多年来 Go 包依赖管理混乱的局面(Go 官方之前推出的 dep 工具也几乎胎死腹中),并且将在 1.13 版本中正式默认开启,目前已受到社区的看好和强烈推荐,建议新项目采用 Go modules。作为新入局go的同学,可以跳过旧的包管理,直接了解和使用go modules机制(即go mod系列命令)来管理包。

3.1 GO111MODULE

golang提供了一个环境变量“GO111MODULE”,默认值为auto,如果当前目录里有 go.mod 文件,就使用 go modules,否则使用旧的 GOPATH 和 vendor 机制,因为在modules机制下go get只会下载go modules。

modules和传统GOPATH不同,不需要包含src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为module,只要其中包含go.mod文件。

除了go.mod之外,go命令还维护一个名为go.sum的文件,其中包含特定模块版本内容的预期加密哈希,go命令使用go.sum文件确保这些模块的未来下载检索与第一次下载相同的位,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。 go.mod和go.sum都应检入版本控制。

go.sum不需要手工维护,所以可以不用太关注。

3.2 包查找顺序总结(精华!!!)

 如果GO111MODULE=off,那么go命令行将不会使用新的module功能,相反的,它将会在vendor目录下和GOPATH目录中查找依赖包。也把这种模式叫GOPATH模式。  如果GO111MODULE=on,那么go命令行就会使用modules功能,而不会访问GOPATH。也把这种模式称作module-aware模式,这种模式下,GOPATH不再在build时扮演导入的角色,但是尽管如此,它还是承担着存储下载依赖包的角色。它会将依赖包放在GOPATH/pkg/mod目录下。  如果GO111MODULE=auto,这种模式是默认的模式,也就是说在你不设置的情况下,就是auto。这种情况下,go命令行会根据当前目录来决定是否启用module功能。只有当当前目录在GOPATH/src目录之外而且当前目录包含go.mod文件或者其子目录包含go.mod文件才会启用。
 通俗的讲: GO111MODULE=auto,即默认情况,当然=on与=off也包含在下述情况中: 一、没go.mod文件时,属于GOPATH模式,则使用 vendor 特性,包查找顺序参考:2 理解 vendor 特性; 二、有go.mod文件时,此时默认启用 modules特性     1.只找当前目录,不找GOPATH/src目录     2.当前目录下有vendor目录,则查找当前目录下vendor是否有此包;     3.当前目录下没有vendor目录,则查找GOROOT/src下是否有此包;     4.如果未找到,则启动GOPROXY特性,到仓库下载此包;(详见3.3)     5.如果未下载到则提示包不存在;
3.3 GOPROXY与GoCenter
 C:\Users\zhang>go env set GONOPROXY= set GONOSUMDB= set GOPRIVATE=
3.3.1 GOPROXY 介绍

原文参考:,包括内容与图,特此声明。

GOPROXY控制Go Module下载的来源,有助于确保构建的确定性和安全性。

GOPROXY时代之前,在Golang开发时,模块依赖关系直接从版本控制(VCS)系统中的源存储库下载,如GitHub、Bitbucket、Bazaar、Mercurial或SVN。来自第三方的依赖项通常从公共源repos下载。这种形式缺乏确定性和安全性,以及开发中的两个基本需求:不变性和可用性。模块可以被作者删除,也可以编辑修改当前被发布的版本。

设置GOPROXY,将Go Module下载请求重定向到GOPROXY 指向的缓存库。使用GOPROXY进行模块依赖关系的管理的有助于开发构建不变性需求。另外GOPROXY的缓存还有助于确保模块始终可用,即使VCS repo中的原始模块已被销毁。

使用GOPROXY有不同的方法,这取决于你想使用的go模块依赖的来源,通常有公共的GOPROXY,私有Go Module,以及私有的GOPROXY。

3.3.2 公共GOPROXY

公共GOPROXY是一个集中式的存储库,全球各地的Golang开发者都可以使用它。它缓存了大量开源的Go模块,这些模块可以从第三方公开访问的VCS项目存储库中获得。大多数此类GOPROXY,比如JFrog GoCenter,Goproxy.cn都是免费提供给Golang开发者社区的。此类GOPROXY 的架构拓扑如下图,提供了Go Module 的一致性以及可用性能力:

 要使用公共GOPROXY,将Golang环境变量设置为其URL: go env -w GOPROXY= 以上设置将所有模块下载请求重定向到GoCenter,从公共GOPROXY下载要比直接从VCS下载快得多。  除了完成下载之外,一个公共的GOPROXY还可以为Golang开发者提供关于它所拥有的模块的更详细的信息。JFrog GoCenter提供了丰富的UI,支持搜索和访问模块的安全信息(如cve)、非安全元数据(如Star数量,下载统计数据以及License信息)和gosumdb支持。这些元数据有助于用户在选择开源Go模块时做出更好的决策。
3.3.3 私有Go Module

通常,Golang项目会同时使用开源和私有模块。一些用户使用GOPRIVATE环境变量来指定一个必须绕过GOPROXY和GOSUMDB的路径列表,并直接从VCS repos下载私有模块。例如,您可能希望使用GoCenter检索所有开源模块,但只从公司的服务器请求私有模块。如下图:

要使用GoCenter公共GOPROXY和私有模块,请设置Golang环境变量:$ export GOPROXY= export GOPRIVATE=*.这种对GOPRIVATE的使用也确保了你对这些私有模块的使用不会因为请求到一个开放网络上的公共GOPROXY & checksum数据库服务器而“泄露”。另一种替代方法是使用GONOSUMDB变量,该变量包含对私有go模块的引用。虽然这种配置使Go客户端能够同时解析公共模块和私有模块依赖,但它并不强制私有模块的不可变性或可用性要求。
3.3.4 私有GOPROXY

私有GOPROXY是一种在您自己的基础设施上存储公共和私有Go模块的工具。公共模块通过在二进制存储库管理器(如JFrog Artifactory)中代理一个公共GOPROXY缓存到企业内部网络。

私有模块也可以从VCS repos缓存到改存储库中。通过这种方式,可以保证公共和私有Go模块的不变性和可用性。在Artifactory中,您可以通过设置GoCenter的远程存储库(remote reposiroty),以及指向私有GitHub 仓库(用于私有模块)的远程Go模块存储库,以及本地Go模块存储库,将上述三个仓库组合到一个虚拟存储库中,作为用户统一单元进行访问,如下图:

在Artifactory中设置名为“go”的虚拟存储库的GOPROXY:$ export GOPROXY=" export GONOSUMDB="*,*"因为您的私有VCS repos中的模块在的公共校验和数据库中没有条目,所以它们必须被排除在go客户端的检查之外。将GONOSUMDB设置为您的私有VCS repos可以实现这一点,并将防止这些私有模块的go get命令由于校验和不匹配而失败。在这个配置中,您可以确保对私有模块的引用不会“泄漏”,同时还确保了公共模块和私有模块的不可变性和可用性。

综上,使用私有GOPROXY提供了最确定、最可靠和最安全的功能。您还可以通过您的私有GOPROXY到您的构建工具的网络接近度来加速模块依赖关系的解析。JFrog Artifactory可以安装在您最需要它的地方:本地数据中心部署或云中,或公共云提供商的SaaS版本。

这些好处不仅仅局限于Golang开发。大多数技术公司使用不止一种语言和多个包管理器。例如,如果代码是用Golang编写的,那么npm可能用于UI, Docker可能用于分发交付,Helm可能用于在k8上部署应用程序。通过支持超过27种包类型,Artifactory可以为所有应用程序提供确定性、稳定和安全的软件开发过程。

3.4 GOPROXY 配置

golang 配置 goproxy 几个可选的地址:1.阿里云:社区提供的::.基于athens的公共服务:.官方提供的(jfrog 与 golang): 与 .七牛云赞助支持的:可参考网站: 与 下配置命令(选一个即可):其他几个可以做为后备,以备不时之需。实际中,有时会出现某些库拉不下来,这时就需要换GOPROXY的配置go env -w GOPROXY= env -w GOPROXY= env -w GOPROXY=(我正在使用这个,可以在这个网站上查询各种Go Module Repository,很方便)...// go env -w GOPRIVATE=*.corp.example.com # 设置不走 proxy 的私有仓库,多个用逗号相隔
3.5 go mod命令介绍

自动下载依赖包

项目不必放在 &GOPATH/src 内了,modules和传统GOPATH不同,不需要包含src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为module,只要其中包含go.mod文件

项目内会生成一个 go.mod 文件,列出依赖包;所有来的第三方包会准确的指定版本号

对于已经转移的包,可以用 replace 申明替换,不需要改代码。

C:\Users\zhang>go modGo mod provides access to operations on modules.Note that support for modules is built into all the go commands,not just 'go mod'. For example, day-to-day adding, removing, upgrading,and downgrading of dependencies should be done using 'go get'. See 'go help modules' for an overview of module functionality.Usage:        go mod <command> [arguments]The commands are:        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(解释为什么需要依赖)Use "go help mod <command>" for more information about a command.download  //下载模块到本地缓存,具体可以通过命令go env查看,其中环境变量GOCACHE就是缓存的地址,如果该文件夹的内容太大,可以通过命令go clean -cacheedit      //从工具或脚本中编辑go.mod文件graph     //打印模块需求图init      //在当前目录下初始化新的模块            例如:在D:/gomodule_test 目录下通过命令行输入 go mod init gomodule_test            则生成 D:/gomodule_test/go.mod   文件,文件内容:            module gomodule_test            go 1.15tidy      //添加缺失的模块以及移除无用的模块verify    //验证依赖项是否达到预期的目的why       //解释为什么需要包或模块
go module使用流程

GOPROXY问题,由于国内的网络环境,我们可以通过配置GOPROXY避免DNS污染导致的模块拉取缓慢或失败的问题。

可参考:

配置方法,windows打开终端并执行:

//go env -w GOPROXY= env -w GOPROXY= env -w GOPRIVATE=*.corp.example.com # 设置不走 proxy 的私有仓库,多个用逗号相隔具体详情可参考:或
package mainimport (	"fmt"	_ "github.com/mattn/go-sqlite3")func main() {	fmt.Println("GO111MODULE go module--go mod的使用")}

按照过去的做法,要运行需要执行go get下载 第三方包 到 $GOPATH/src,但使用了go module就不需要这么做了。

现在,直接 go build/go test/go run... 即可,稍等片刻,go会自动查找代码中的包,下载依赖包,并且把具体依赖关系和版本写入到go.mod和go.sum文件中。

实际中具体使用步骤参考首先将你的版本更新到最新的Go版本(>=1.11);通过go命令行,进入到你当前的工程目录下,在命令行设置临时环境变量set GO111MODULE=on执行命令go mod init 文件夹名在当前目录下生成一个go.mod文件,执行这条命令时,当前目录不能存在go.mod文件。如果之前生成过,要先删除;如果你工程中存在一些不能确定版本的包,那么生成的go.mod文件可能就不完整,因此继续执行下面的命令;执行go mod tidy命令,它会添加缺失的模块以及移除不需要的模块。执行后会生成go.sum文件(模块下载条目)。添加参数-v,例如go mod tidy -v可以将执行的信息,即删除和添加的包打印到命令行;执行命令go mod verify来检查当前模块的依赖是否全部下载下来,是否下载下来被修改过。如果所有的模块都没有被修改过,那么执行这条命令之后,会打印all modules verified执行命令go mod vendor生成vendor文件夹,该文件夹下将会放置你go.mod文件描述的依赖包,文件夹下同时还有一个文件modules.txt,它是你整个工程的所有模块。在执行这条命令之前,如果你工程之前有vendor目录,应该先进行删除。同理go mod vendor -v会将添加到vendor中的模块打印出来;4. 项目中正规的使用步骤

参考链接:

标签: #golang 依赖包