[Golang] Go Mod My-Practice
Go在1.11版本后开始支持modules,以go mod
来实现包管理,那么该如何使用呢?
UPDATED 2020/04/10:
- 增加
GOPROXY
设置,应对可能存在的网络连接问题 - 增加仓库发布实践操作部分,有效避坑指南
- 调整了文章结构
Before
本文前提你已经有了如下环境:
- VS Code
- Golang v1.11 or later
- 已正确设置
GOROOT
GOPATH
- Git
Quick Start
如果需要,可以直接查看官方文档,体验更佳。
开启Go Mod
不说废话,直接开始,首先需要开启Go mod。
- [Go 1.13 及以上(推荐)](https://goproxy.cn/#Go 1.13 及以上(推荐))
打开你的终端并执行
1 | $ go env -w GO111MODULE=on |
完成。
- [macOS 或 Linux](https://goproxy.cn/#macOS 或 Linux)
打开你的终端并执行
1 | $ export GO111MODULE=on |
或者
1 | $ echo "export GO111MODULE=on" >> ~/.profile |
1 | go env -w GO111MODULE=on |
- Windows
打开你的 PowerShell 并执行
1 | C:\> $env:GO111MODULE = "on" |
初试Go Mod
开启go mod后,在GOPATH目录之外的地方创建项目文件,使用VCS (可选)
1 | mkdir -p /tmp/scratchpad/repo |
初始化module
1 | go mod init github.com/my/repo |
demo:
1 | cat <<EOF > hello.go |
之后使用第三方库,都不再需要使用go get
了,build的同时会自动将需要的包导入:
1 | go build -o hello |
go.mod:
1 | $ cat go.mod |
日常使用
- 在你的
.go
文件中加入需要的声明 (import) - 使用
go build
或者go test
自动导入依赖,go.mod
也会自动更新,并且包的校验文件go.sum
也会一起更新 - 当需要的时候,可以用如
go get foo@v1.1.3
,go get foo@master
来选择合适的依赖
Command | Usage |
---|---|
go list -m all | 查看直接或间接依赖库的最终版本 |
go list -u -m all | 查看直接或间接依赖库的可用更新(minor和patch) |
go get -u ./… or go get -u=path ./… | 安装所有直接或间接依赖库的更新(minor和patch) |
go build ./… or go test ./… | build或test模块中的所有包 |
go mod tidy | 从go.mod 中清除不再使用的依赖 |
replace or gohack |
使用通过fork、本地复制、解压等方法安装的 |
go mod vendor | Optinal step to create a vendor directory |
如何使用本地包
使用本地包:在 go.mod
中末行加入:
1 | replace example.com/banana => example.com/hugebanana |
更新 Go Module
Go Modules 更新:
Command | Usage |
---|---|
go get -u | 查看直接或间接依赖库的最终版本 |
go get -u ./… | 查看直接或间接依赖库的可用更新(minor和patch) |
go get -u -t | 安装所有直接或间接依赖库的更新(minor和patch) |
go get -u -t ./… | build或test模块中的所有包 |
go get -u all | 推荐,更新所有模块 |
- 注意:除了
v0
和v1
外的主版本号必须显式地出现在模块路径的尾部 - 注意:
example.com/foo/bar
和example.com/foo/bar/v2
被视为两个完全不同的模块 go get -u
不会更新主版本号,需要手动指定
发布go module
前文中已经介绍了日常开发中,如何使用go mod,确实它也给我们带来了很多的便利。
但在发布自己包的过程中,确实存在一些小坑,接下来介绍如何“优雅”地发布自己的 go module.
以 github.com 为例,如何将代码发布到该平台上,并在本地调用 github 上自己发布的仓库?
发布第一个版本
构建一个项目,结构如下:
1 | . |
hello.go
:
1 | package pkg |
在/release-go/
路径下执行:go mod init github.com/fusidic/release-go
可以看到生成go.mod
文件如下:
1 | module github.com/fusidice/release-go |
查看发布的库
如果你还没有修改代理 GOPROXY
的话,不妨打开 https://pkg.go.dev
,这是Go社区官方开源的Go软件包和模块的信息资源中心,在上面搜索自己的包 github.com/fusidic/release-go
,你会发现什么都找不到!
其实在 go.dev/about 中已经说明了:
- Making a request to proxy.golang.org for the module version, to any endpoint specified by the Module proxy protocol. For example:
https://proxy.golang.org/example.com/my/module/@v/v1.0.0.info
- Downloading the package via the go command. For example:
1 GOPROXY=“https://proxy.golang.org GO111MODULE=on go get example.com/my/module@v1.0.0
只有从 https://proxy.golang.org/
中拉取过对应的仓库之后,仓库才会从 Module list
中缓存这个包,当然,这需要一定的时间。
所以当我们碰到无法检索到自己发布的包的时候,一个简单粗暴的方法就是:
1 | $ go get -u example.com@package |
这条命令会从代理仓库 (pkg.go.dev
或 goproxy.cn
) 中拉取指定的包,如果代理仓库中暂时没有更新你的包,这条命令就会代理仓库更新它的缓存,从而达到“手动更新”的目的。
说来惭愧,笔者在使用过程中碰到一个很怪的问题,由于自己操作不慎,导致使用
go get -u
拉取包时会出现解析错误的情况,在修复这个问题之后。由于使用go get -u
出现错误,导致pkg.go.dev
上的包无法更新到包修复之后的状态。如何解决?
本地:
git tag v1.0.0
上传GitHub:
git push origin v1.0.0
通过请求更新
pkg.go.dev
,指定版本:go get example.com@package@v1.0.0
通过指定版本,可以很快拉取更新。
语义化控制版本
值得注意的是,go官方使用语义化控制版本 Semantic Import Version ,是官方关于版本控制的最佳实践,go官方提供了两个方案针对大版本升级和 breaking changes
:
- Major branch 即通过创建version分支和tag进行版本升级
- Major subdirectory 即通过创建version子目录来区分不同版本
构建私有Go模块代理
你的代码永远只属于你自己,因此我们向你提供目前世界上最炫酷的自托管 Go 模块代理搭建方案。通过使用 Goproxy 这个极简主义项目,你可以在现有的任意 Web 服务中轻松地加入 Go 模块代理支持,要知道 goproxy.cn 就是基于它搭建的。
创建一个名为 goproxy.go
的文件
1 | package main |
并且运行它
1 | $ go run goproxy.go |
然后通过把 GOPROXY
设置为 http://localhost:8080
来试用它。另外,我们也建议你把 GO111MODULE
设置为 on
。
就这么简单,一个功能完备的 Go 模块代理就搭建成功了。事实上,你可以将 Goproxy 结合着你钟爱的 Web 框架一起使用,比如 Gin 和 Echo,你所需要做的只是多添加一条路由而已。更高级的用法请查看文档。
LSP
如果您并非使用 VS Code 进行开发,那么以下内容对您帮助不大。
LSP (Language Server Protocol) 即语言服务器协议,目的是为了让不同的编辑器或集成开发环境方便使用各种程序语言,支持包括语法检查、自动补全、跳转、引用查询等功能。
将这些功能放入独立的进程中,可以同时对不同编辑器生效,避免了资源的浪费,同时也可以将语言服务器部署在服务器上,释放本地因扫描语言而带来的CPU负担。
LSP 安装
安装gopls:打开VS Code,command+,
打开设置,搜索go.useLanguageServer
勾选。
默认情况下,这时Go扩展就会自动提示你安装gopls,或者手动安装
1 | go get golang.org/x/tools/gopls@latest |
gopls会安装到GOPATH目录下的bin中,如果存在网络问题,可以将goproxy
设置为goproxy.cn
,是一个国内的大学生和七牛云合作提供的一个开源CDN,安全性自己判断了:
1 | export GOPROXY=https://goproxy.cn |
导入配置到settings.json
中:
1 | { |
Q1: 如何打开
settings.json
?A1:
command + ,
右上角图标open settings(JSON)
Q2:
.vscode
是什么?A2: 通常在你的项目文件下有一个
.vscode
的文件,里面包含了如系统路径、配置信息、调试参数等信息。项目下的
.vscode
文件的作用域只包含着整个项目目录,所以当一台服务器同时支持多个用户进行远程开发的时候,每个用户都可以通过修改.vscode/settings.json
,来完成一些自定义(如字体、终端、环境配置等)。更多配置可以参考:https://code.visualstudio.com/docs/getstarted/settings
(Optional) 开启调试信息,在settings中加入:
1 | "go.languageServerFlags": [ |
Reference
- https://github.com/golang/go/wiki/Modules#how-to-install-and-activate-module-support
- https://go.dev/about
- https://juejin.im/post/5e4ccabf6fb9a07ca24f49d4 “如何优雅地发布go module模块”
- https://github.com/golang/go/wiki/Modules#how-to-prepare-for-a-release
- https://code.visualstudio.com/docs/getstarted/settings