go module详解——导入本地包(go.mod)

如何搭建Go语言开发环境

旧版本的GOROOT和GOPATH

GOROOT和GOPATH都是环境变量,其中GOROOT是安装go开发包的路径,而从Go 1.8版本开始,Go开发包在安装完成后会为GOPATH设置一个默认目录。

并且在Go1.14及之后的版本中启用了Go Module模式之后,不一定非要将代码写到GOPATH目录下,所以也就不需要再自己配置GOPATH了,使用默认的即可。

想要查看电脑上的GOPATH路径,只需要打开终端输入以下命令并回车:

go env

在终端输出的内容中找到GOPATH对应的具体路径。

新版本的go module

go module是Go1.11版本之后官方推出的版本管理工具,并且从Go1.13版本开始,go module将是Go语言默认的依赖管理工具。

GO111MODULE

要启用go module支持首先要设置环境变量GO111MODULE,通过它可以开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是auto。

  1. GO111MODULE=off禁用模块支持,编译时会从GOPATH和vendor文件夹中查找包。
  2. GO111MODULE=on启用模块支持,编译时会忽略GOPATH和vendor文件夹,只根据 go.mod下载依赖。
  3. GO111MODULE=auto,当项目在$GOPATH/src外且项目根目录有go.mod文件时,开启模块支持。

简单来说,设置GO111MODULE=on之后就可以使用go module了,以后就没有必要在GOPATH中创建项目了,并且还能够很好的管理项目依赖的第三方包信息。

使用 go module 管理依赖后会在项目根目录下生成两个文件go.mod和go.sum。

GOPROXY

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

GOPROXY时代之前,在Golang开发时,模块依赖关系直接从VCS系统中的源存储库下载,如GitHub、Bitbucket、Bazaar、Mercurial或SVN。来自第三方的依赖项通常从公共源repos下载。私有依赖项必须在存储它们以下载模块源文件的VCS系统中进行身份验证。

虽然上面的工作流得到了广泛的应用,但是它缺乏确定性和安全性构建,以及开发过程的两个基本需求:不变性和可用性。模块可以被作者删除,也可以编辑修改当前被发布的版本。虽然这些场景被认为是不好的实践,但它们确实经常发生,如下图:

在这里插入图片描述
使用GOPROXY进行模块依赖关系的管理的有助于开发构建不变性需求。通过从GOPROXY的缓存中返回模块包,它能够为用户请求的某模块版本提供相同的返回(Go module模块代码),即使模块最近在VCS repo中被不正确地修改过,从而保证多次构建结果一致。

另外GOPROXY的缓存还有助于确保模块始终可用,即使VCS repo中的原始模块已被销毁。

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

默认GoPROXY配置是:GOPROXY=https://proxy.golang.org,direct,由于国内访问不到https://proxy.golang.org,所以需要换一个PROXY,这里推荐使用https://goproxy.io或https://goproxy.cn。

可以执行下面的命令修改GOPROXY:

go env -w GOPROXY=https://goproxy.cn,direct

在这里插入图片描述

GOSUMDB

GOSUMDB(go checksum database)是Go官方为了go modules安全考虑,设定的module校验数据库,服务器地址为:sum.golang.org

在本地对依赖进行变动(更新/添加)操作时,Go 会自动去这个服务器进行数据校验,保证你下的这个代码库和世界上其他人下的代码库是一样的。

和go.mod一样,Go 会帮我们维护一个名为go.sum的文件,它包含了对依赖包进行计算得到的校验值

环境变量GOSUMDB可以用来配置你使用哪个校验服务器和公钥来做依赖包的校验

Go1.13 中当设置了 GOPROXY=“https://proxy.golang.org” 时 GOSUMDB 默认指向 “sum.golang.org”,其他情况默认都是关闭的状态。如果设置了 GOSUMDB 为 “off” 或者使用 go get 的时候启用了-insecure参数,Go 不会去对下载的依赖包做安全校验,存在一定的安全隐患。

如果你的代码仓库或者模块是私有的,那么它的校验值不应该出现在互联网的公有数据库里面,但是我们本地编译的时候默认所有的依赖下载都会去尝试做校验,这样不仅会校验失败,更会泄漏一些私有仓库的路径等信息。

我们可以使用GONOSUMDB这个环境变量来设置不做校验的代码仓库, 它可以设置多个匹配路径,用逗号相隔.

举个例子:

GONOSUMDB=*.corp.example.com,rsc.io/private

这样的话,像 “http://git.corp.example.com/xyzzy”, “http://rsc.io/private”, 和 "http://rsc.io/private/quux"这些公司和自己的私有仓库就都不会做校验了。

有的公司也会选择直接关闭gosumdb来避免对包进行校验。

go mod命令

常用的go mod命令如下:

go mod download 下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit 编辑go.mod文件
go mod graph 打印模块依赖图
go mod init 初始化当前文件夹, 创建go.mod文件
go mod tidy 增加缺少的module,删除无用的module
go mod vendor 将依赖复制到vendor下
go mod verify 校验依赖
go mod why 解释为什么需要依赖

go.mod文件记录了项目所有的依赖信息,其结构大致如下:

module blog

go 1.12

require (
	github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586
	github.com/gin-gonic/gin v1.4.0
	github.com/go-sql-driver/mysql v1.4.1
	github.com/jmoiron/sqlx v1.2.0
	github.com/satori/go.uuid v1.2.0
	google.golang.org/appengine v1.6.1 // indirect
)

其中,

  • module用来定义包名
  • require用来定义依赖包及版本
  • indirect表示间接引用

依赖的版本

go mod支持语义化版本号,比如go get foo@v1.2.3,也可以跟git的分支或tag,比如go get foo@master,当然也可以跟git提交哈希,比如go get foo@e3702bed2。关于依赖的版本支持以下几种格式:

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

replace

在国内访问golang.org/x的各个包都需要翻墙,可以在go.mod中使用replace替换成github上对应的库。

replace (
	golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
	golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d
	golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)

go get

在项目中执行go get命令可以下载依赖包,并且还可以指定下载的版本。

  • 运行go get -u将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
  • 运行go get -u=patch将会升级到最新的修订版本
  • 运行go get package@version将会升级到指定的版本号version

如果下载所有依赖可以使用go mod download 命令。

扩展

公共GOPROXY

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

在这里插入图片描述
要使用公共GOPROXY,将Golang环境变量设置为其URL:

$ export GOPROXY=https://gocenter.io

以上设置将所有模块下载请求重定向到GoCenter。从公共GOPROXY下载要比直接从VCS下载快得多。

除了完成下载之外,一个公共的GOPROXY还可以为GoLang开发者提供关于它所拥有的模块的更详细的信息。JFrog GoCenter提供了丰富的UI,支持搜索和访问模块的安全信息(如cve)、非安全元数据(如Star数量,下载统计数据以及License信息)和gosumdb支持。这些元数据有助于用户在选择开源Go模块时做出更好的决策。

私有Go Module

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

在这里插入图片描述
要使用GoCenter公共GOPROXY和私有模块,请设置Golang环境变量:

$ export GOPROXY=https://gocenter.io,direct

$ export GOPRIVATE=*.http://internal.mycompany.com

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

私有GOPROXY

私有GOPROXY是一种在您自己的基础设施上存储公共和私有Go模块的工具。

公共模块通过在二进制存储库管理器(如JFrog,Artifactory)中代理一个公共GOPROXY缓存到企业内部网络。

私有模块也可以从VCS repos缓存到改存储库中。通过这种方式,可以保证公共和私有Go模块的不变性和可用性。

在Artifactory中,您可以通过设置GoCenter的远程存储库(remote reposiroty),以及指向私有GitHub 仓库(用于私有模块)的远程Go模块存储库,以及本地Go模块存储库,将上述三个仓库组合到一个虚拟存储库中,作为用户统一单元进行访问,如下图:

在这里插入图片描述
在Artifactory中设置名为“go”的虚拟存储库的GOPROXY:

$ export GOPROXY="https://:@my.artifactory.server/artifactory/api/go/go
$ export GONOSUMDB="http://github.com/mycompany/*,http://github.com/mypersonal/*"

因为您的私有VCS repos中的模块在http://sum.golang.org的公共校验和数据库中没有条目,所以它们必须被排除在go客户端的检查之外。将GONOSUMDB设置为您的私有VCS repos可以实现这一点,并将防止这些私有模块的go get命令由于校验和不匹配而失败。

在这个配置中,您可以确保对私有模块的引用不会“泄漏”,同时还确保了公共模块和私有模块的不可变性和可用性。

如何使用go module导入本地包

前言

目前流行的项目目录:
在这里插入图片描述

问题

论导入第三方包,QAQ:

go mod init
go mod tidy
go build

一套行云流水。

再导入自己的包:

mkdir project
vim project/project.go

mkdir demo
vim demo/main.go

go mod inti demo
import "github.com/xxx/project

炸了!

  • 不是github.com/xxx下没有project这个包
  • 就是导入飘红

解决方法

在同一个项目下

moduledemo
├── go.mod
├── main.go
└── mypackage
    └── mypackage.go

直接导入,简单省事

package main

import (
	"fmt"
	"moduledemo/mypackage"  // 导入同一项目下的mypackage包
)
func main() {
	mypackage.New()
	fmt.Println("main")
}

不在同一个项目下

├── moduledemo
│   ├── go.mod
│   └── main.go
└── mypackage
    ├── go.mod
    └── mypackage.go

因为这两个包不在同一个项目路径下,你想要导入本地包,并且这些包也没有发布到远程的github或其他代码仓库地址。这个时候我们就需要在go.mod文件中使用replace指令。

在调用方也就是moduledemo/go.mod中按如下方式指定使用相对路径来寻找mypackage这个包。

module moduledemo

go 1.14


require "mypackage" v0.0.0
replace "mypackage" => "../mypackage"

举个"栗子"

一个hello的grpc项目
在这里插入图片描述
从hello/client和hello/server导入proto/hello的包

import (
	pb "github.com/helloProject/proto/hello" // 引入proto包
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

mod

module github.com/helloProject/hello/client

go 1.17

require (
	golang.org/x/net v0.0.0-20220526153639-5463443f8c37
	google.golang.org/grpc v1.46.2
)

require (
	github.com/golang/protobuf v1.5.2 // indirect
	golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
	golang.org/x/text v0.3.7 // indirect
	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
	google.golang.org/protobuf v1.28.0 // indirect
)

require github.com/helloProject/proto/hello v0.0.0

replace github.com/helloProject/proto/hello => ../../proto/hello

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Generalzy

文章对您有帮助,倍感荣幸

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值