logo

罕见的 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 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

此处 modulego 都属于标识,根据 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.golib.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 cleango mod edit 虽然用的不多,但 go work 却尤其罕见。关于 go work 官方有两个文档比较详细: