Go mod配置踩坑小记【依赖管理&本地仓库配置】
之前是在linux上面用vim写代码,感觉效率上有些欠佳,还是习惯在ide上编写。另外,之前图省事直接采用$GOPATH
作为工作目录,个人理解基本做不到包管理工具应有的功能,包括依赖管理、版本管理等等。go 1.11版本引入了go mod
作为官方的包管理工具,是目前go包管理工具的主流。于是花了一周的时间在mac上搭建了环境,期间踩了不少坑,在此记录供参考。
Go环境基本配置
现在mac上go的安装也十分方便了,直接在官网 (golang.google.cn/dl/) 下载pkg安装包即可。我这边下载的是1.15版本的安装包。安装后的安装内容会在/usr/local/go
这个路径下面,如果需要更新版本则在官网下载更新的版本即可,降级版本则删除/usr/local/go
然后重新下载即可。
另外还有Homebrew的安装方式也在这里记录一下:
# 安装go,默认安装最新的版本
$ brew install go
# 升级go
$ brew upgrade go
# 降级go,eg:1.17->1.15
$ brew install go@1.15
$ brew unlink go
$ brew link --force go@1.15
# 查看验证版本
$ go version
> go version go1.15.15 darwin/amd64
配置环境配置在~/.bashrc
下即可,如果是zsh则配置在~/.zshrc
,别忘了source ~/.bash_profile
生效。
#go env
export GOROOT=/usr/local/go
export GOPATH=~/gopath
export PATH=$PATH:$GOROOT/bin
export PATH=$PATH:$GOPATH/bin
其中GOROOT就是go的安装路径,GOPATH是go的工作空间,也就是项目和包的路径。
可以通过go env
来查看和验证go的环境信息,例如我的部分配置信息如下:
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/Janus/Library/Caches/go-build"
GOENV="/Users/Janus/Library/Application Support/go/env"
GOMODCACHE="/Users/Janus/gopath/pkg/mod"
GONOPROXY="github.com"
GONOSUMDB="github.com"
GOPATH="/Users/Janus/gopath"
GOPRIVATE="github.com"
GOPROXY="https://goproxy.cn,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOPATH管理依赖
上述提到的GOPATH也就是工作空间,里面包含了三个文件夹:
bin
:用于存放编译后生成的可执行文件,需要注意的是go install
和go build
的区别:
# 先编译导入的包,再编译主程序
# 编译后的包文件放在$GOPATH/pkg,主程序编译后的可执行文件放在$GOPATH/bin
$ go install
# 如果想要设置可执行文件的生成路径,则设置环境变量中的GOBIN即可
# 可在~/.bashrc添加环境变量
export GOBIN=$GOPATH/bin
# 检查编译是否有错误,如果是main文件则在被编译源码的文件夹下面生成可执行文件
$ go build
# go build可以通过-o来指定生成可执行文件路径
# 会在当前文件夹生成的同时在指定路径生成
$ go build -o ~/gopath/bin
pkg
:存放编译后生成的包文件,即go install
后生成的文件。并且,如果是通过go mod
管理包,那么包也会下载到这个文件夹。
src
:用于存放项目的源码。在不启用go mod
的情况下只能将源码放在该文件夹中。
可以写个简单的demo对GOPATH管理依赖进行实现验证:
// 路径$GOPATH/src/hello
package main
import "fmt"
func main() {
fmt.Print("hello")
}
# 验证代码
$ go build hello.go
$ ./hello
Go mod管理依赖
Go mod是Go 1.11引入的新特性,建议升级到1.12及以上进行使用。主要用于解决依赖的问题,可以记录和解析对其他模块的依赖性,从而替代原来的基于GOPATH的指定构建中使用哪些源文件。
简单一句话来说,可以使用go mod
在$GOPATH/src
以外的地址创建项目,同时可以为每个项目指定依赖版本。
GO111MODULE
要启用go mod首先需要了解一个环境配置GO111MODULE
:
GO111MODULE | 含义 |
---|---|
GO111MODULE=off | 不启用go mod ,直接从$GOPATH 获取依赖 |
GO111MODULE=on | 启用go mod ,需要通过go mod 的配置获取依赖(经本地测试,官方提供的标准库不配置go mod 也能获取得到) |
GO111MODULE=auto | 分两种情况:当前源代码路径在$GOPATH/src 外面或源代码文件夹下面存在go.mod 时,同GO111MODULE=on;当前源码在$GOPATH/src 下且文件夹下没有go.mod ,同GO111MODULE=off |
目前1.16版本之前的环境默认值GO111MODULE=auto
,在1.16及之后的版本默认值为GO111MODULE=on
,可以看到官方意图取缔掉$GOPATH
这种管理方式。可以通过更改配置文件或者输入命令进行配置:
#在~/.bashrc下或~/.zshrc下添加环境配置
export GO111MODULE=on
#或者采用命令进行环境配置
$ go env -w GO111MODULE=on
#如果想要恢复默认值
$ go env -u GO111MODULE
开启之后,即可使用go mod
命令来管理包了,不过在这之前,如果是在国内网络建议还有一步配置模块代理要做。
GOPROXY
go env
环境变量中有个变量GOPROXY
允许对下载源进行控制,设置了这个变量,就会开启Go模块代理,可以提高下载依赖的稳定性和速度。
如果GOPROXY
设置为空或为设置为direct,表示去目标模块的源地址进行下载(如github.com),如果是设置为off
则表示不使用代理。由于golang.org
的模块在国内无法访问的问题,所以国内可以采用七牛云提供的代理goproxy.cn
。
$ go env -w GOPROXY=https://goproxy.cn,direct
https://goproxy.cn,direct
逗号后的direct
表示如果通过代理拉取模块遇到错误,则通过direct
的方式拉取模块。该功能在1.13版本后上线,所以在1.13版本之前只能配置为GOPROXY=https://goproxy.cn
。
更多可查看goproxy.cn/ 和 github.com/goproxy/gop…
GO MOD
可以通过go mod help
查看一下go mod
的命令:
command | explanation |
---|---|
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 |
接下来讲解一下如何使用go mod
,以mit6.824这个课程的项目(github.com/Januslll/mi…) 来举例:
该项目原来没有采用Go mod
进行配置,它的目录结构为:
mit-go
└─src
├─main
│ ├─mrsequential.go
│ ├─mrmaster.go
│ ├─mrworker.go
│ └─...
├─ mr
│ ├─master.go
│ ├─worker.go
│ └─rpc.go
└─...
首先,我们在mit-go文件夹下面输入命令:
# 初始化go mod,mit-go表示包名
$ go mod init mit-go
会在当前文件夹下面看到生成了一个go.mod
文件,这个时候go.mod
文件只会包含有包名信息和go的版本信息。
接下来我们在mit-go/src/main/mrmaster.go
中引入mit-go/src/mr
这个包,引入方式就是在mrmaster.go
中加入import github.com/Januslll/mit-go/src/mr
。其中的github.com/Januslll/mit-go/src/mr
是mr
这个包在github的项目上的路径。
接着可以通过go mod
进行下载或者通过go get
进行下载包都可以。
# go mod 下载包
# go mod tidy会自动下载需要的包,并把没有用的包移除
$ go mod tidy
# go mod download下载依赖的包到本地cache,和go mod tidy相比不会移除包
$ go mod download
# go get命令在没有go.mod文件的情况下也能下载包
# 如果有go.mod则会同时更新go.mod的内容
go get -u # 表示升级所有依赖
go get -u -v # -v表示打印详细日志
# 下面这语句表示下载https://github.com/Januslll/mit-go这个路径地址下的包
go get -u -v github.com/Januslll/mit-go
这个时候可以查看go.mod中的内容:
# module名称
module mit-go
# go 版本
go 1.15
# require 用来定义依赖包的版本
# 后面的// indirect表示间接依赖,通常如果有间接依赖说明import写的有问题或者依赖的包存在问题
require github.com/Januslll/mit-go v0.0.0-20200827115747-2ab09a53eea2// indirect
这个时候就表示已经拉取到依赖了,依赖的格式通常为版本号+时间戳+hash,例如我这里就是v0.0.0-20200827115747-2ab09a53eea2
。
其中版本号是v0.0.0,这就表示没有版本的控制,官方建议通过git tag
加上版本号,如下所示:
git tag v1.0.0
git push --tags
加上后就会变成v1.0.0版本。
时间戳和hash分别表示commit提交的时间戳和commit记录的hash值取前12位,输入git log
可查看,如下所示:
commit 2ab09a53eea24dcbb01307b77bb5ed08080ababc (HEAD -> master, tag: v1.0.0, origin/master, origin/HEAD)
Author: Janus <274123369@qq.com>
Date: Thu Aug 27 19:57:47 2020 +0800
可以通过修改版本号、时间戳、hash来实现依赖版本的管理。同样,go mod还提供了依赖添加和删除的语句:
# 添加依赖
go mod edit -require=github.com/Januslll/mit-go
# 移除依赖
go mod edit -droprequire=github.com/Januslll/mit-go
另外还会看到一个文件go.sum
文件,里面记录了每个依赖包的hash值,防止下载的依赖包有被篡改的可能性,如果篡改了则拒绝构建,对里面的实现感兴趣的可以移步go.dev/blog/module… 。
到此,go mod配置基本完成。
使用本地仓库
上述配置好之后,github.com/Januslll/mit-go/src/mr
引用的依赖包就是从github下载下来的依赖包,但是如果有bug你想要本地调试修改,就得使用本地的包来进行调试。
有两个解决办法,第一个就是改import
依赖路径,第二种方法就是使用go mod
的replace。
# 方法一,修改依赖(不够优雅,不建议)
import mit-go/src/mr
# 方法二,使用go mod的replace,使用go mod edit -replace对go.mod进行修改
# 命令格式:go mod edit -replace [old git package]@[version]=[new git package]@[version]
# 如果new git package是本地仓库则输入本地仓库路径即可,无须带version
go mod edit -replace github.com/Januslll/mit-go@v0.0.0-20200827115747-2ab09a53eea2=/Users/Janus/my_project/mit-go
使用go mod edit -replace
后,会看到go.mod
中新增了一条记录如下所示,表示已经用本地仓库替换了github上下载下来的依赖。
replace github.com/Januslll/mit-go v0.0.0-20200827115747-2ab09a53eea2 => /Users/Janus/my_project/mit-go
至此,可以愉快地本地调试写代码了。
使用私有仓库
公司内部往往会使用公司私有仓库,这个时候只配置了GOPROXY
是无法获取得到依赖的。
在go 1.13版本后,提供了GOPRIVATE
环境变量来配置私有仓库。
# 在~/.bashrc下或~/.zshrc下添加环境配置,例如gitlab.com/xxx是公司私有仓库
# 该配置可以用逗号分开配置多个仓库
export GOPRIVATE=gitlab.com/xxx
#或者采用命令进行环境配置
$ go env -w GOPRIVATE=gitlab.com/xxx
配置了之后,还需要配置私有仓库的访问权限设置,我这里采用ssh
进行配置。由于我需要将个人用户和工作用户隔离开故需要配置不同的ssh,这里记录下如何配置。
# 分别生成ssh key
ssh-keygen -t rsa -C "your_email@example.com" -f ~/.ssh/id_rsa_gitlab
ssh-keygen -t rsa -C "your_email@example.com" -f ~/.ssh/id_rsa_github
# 添加私钥
ssh-add ~/.ssh/id_rsa_gitlab
ssh-add ~/.ssh/id_rsa_github
# ssh配置
vim ~/.ssh/config
# ~/.ssh/config配置内容
# Host:别名
# Hostname:git服务器名字 一般都是github.com 或者公司自己的gitlab
# User:用户名
# IdentityFile:ssh key的文件
# 个人ssh
Host github
Hostname github.com
User Janus
IdentityFile ~/.ssh/id_rsa_github
# 工作ssh
Host gitlab
Hostname gitlab.com
User Janus
IdentityFile ~/.ssh/id_rsa_gitlab
#测试配置,其中temp为上面的HOST,如果Host为github,则为git@github
ssh -T git@temp
# 分别配置用户信息
cd my_project
git config --local user.name "yourName"
git config --local user.email "your_email@example.com"
cd work_project
git config --local user.name "yourName"
git config --local user.email "your_email@example.com"
跟着上面的步骤即可配置完成,有个坑点是如果你原本是https的需要更改为ssh,例如:
git config --global url."git@github.com:Januslll/mit-go.git".insteadOf "https://github.com/Januslll/mit-go.git"
最后把ssh添加到账户的github.com/gitlab.com页面的SSH keys上面去即可。
综上,Go的整个配置环境完成,如有疑问欢迎交流。
参考
转载自:https://juejin.cn/post/7044908192882524196