罕见的 Go CLI 命令 (4/5):有点专业的项目管理方式
Go 提供的对项目目录的管理命令也并非不值得说道。本文主要看一下三个方面:清理项目目录、自动化 go.mod
管理、自动化 go.work
管理。
1. 清理项目目录
假设我们有这样一个程序,在项目目录内进行构建、测试等会生成一些文件或缓存,我们并不想把这些文件上传到 Git 或其他版本控制系统中,那么在使用 git add .
之前就需要使用 rm
命令。
go build . # 生成 demo 可执行文件
go test -c # 生成 demo.test 文件
rm demo*
go test -c
将测试代码打包为可执行文件,-c
即 compile。使用go help test
可以查看详细解释。
但我们并不必这样做。Go 提供了 go clean
命令用于清理和删除与构建相关的文件和缓存。具体来说,它可以执行以下操作:
- 删除包源目录中的对象文件和测试文件。
- 删除由其他工具或手动调用
go build
命令留下的对象文件。 - 删除与指定包对应的源目录中的特定文件,如旧的对象目录、测试目录、测试日志文件等。
- 删除
go install
安装的相关二进制文件 (使用-i
)。 - 打印将要执行的删除命令,然后执行删除命令 (使用
-x
)。 - 打印将要执行的删除命令,但并不执行删除命令 (使用
-n
)。 - 递归删除 (使用
-r
)。
参考
go help clean
:另有-cache
,-testcache
等标识。
上面我们使用了 rm demo*
来清理目录,而如果有很多文件且文件名之间互不关联,那么可能就需要使用 rm a b c d
之类的命令。但现在我们知道,只需要执行 go clean
(或 go clean -x
) 就行了。
2. 自动化 go.mod
管理
go.mod
就是一个普通的文本文件,有时候我们在本地写代码时希望更改 Go 的版本,大概率打开 go.mod
就修改了 (即便本地也建议使用命令而不是手动修改)。但如果是自动化环境如 CI/CD中有类似需求,手动操作就比较业余了。
Go 提供了使用工具或者脚本操作 go.mod
文件的便捷方式,执行 go help mod
命令可以看到以下 go mod
提供了 edit
子命令:
edit edit go.mod from tools or scripts
这里是一个简单的 go.mod
文件:
module demo
go 1.22.3
此处 module,go 都属于标识,根据 go help mod edit
的解释,我们可以使用标识进行修改操作,下面是一些例子:
# 修改 go 版本
go mod edit -go=1.18
# 修改 mod 名
go mod edit -module=github.com/demo/demo
# 不允许 go get 某个包
go mod edit -exclude=github.com/gorilla/mux@v1.7.2
# exclude 之后 go get 会报错
go get github.com/gorilla/mux@v1.7.2 # go: github.com/gorilla/mux@v1.7.2: excluded by go.mod
# 甚至还可以把 go.mod 文件输出为 json
go mod edit -json
如上所述,这些用法的目的主要是为了自动化的需要。
3. 自动化 go.work
管理
工作空间 (workspace) 是 Go 1.18 引入的一个新概念,用于支持在多个模块之间进行并行开发和构建。它允许我们在同一个目录下管理多个模块,并通过 go.work
文件指定相关的配置信息。这个概念为 Go 项目的组织和构建提供了更灵活和高效的方式。
在 这个 commit 中的 03-go-work 目录下有两个 Go 模块,目录结构如下:
tree .
.
├── app
│ ├── go.mod
│ └── main.go
└── lib
├── go.mod
└── lib.go
main.go
和 lib.go
的代码分别如下:
// app/main.go
package main
import "lib"
func main() {
lib.SayHello()
}
// lib/lib.go
package lib
import "fmt"
func SayHello() {
fmt.Println("Hello, World!")
}
可以料想到,编译器会报错:could not import lib (no required module provides package "lib")
,因为两个代码属于不同的模块,无法互相引用。工作空间就是解决这个问题的:
# 初始化工作空间,在当前目录创建一个 go.work 文件,并把 app 模块添加到工作空间
go work init ./app
# 把 lib 模块添加到工作空间
# 其实可以直接使用 `go work init ./app ./lib` 一次性添加,此处为了说明 `use` 命令
go work use ./lib
可以看到此时编译器不再报错,而执行 go run ./app
也会正确输出 Hello, World!
,说明 app 模块成功调用了 lib 模块的代码。
出于自动化的目的,go work
也提供了 edit
子命令:
# 添加 lib 模块到工作空间
go work edit -use ./lib
# 帮助命令
go work help
go help work edit
# 将 lib 模块从工作空间移除
go work edit -dropuse ./lib
总结
go clean
和 go mod edit
虽然用的不多,但 go work
却尤其罕见。关于 go work
官方有两个文档比较详细: