使用 go run 來管理工具依賴

我是一隻可愛的土撥鼠,專注於分享 Go 職場、招聘和求職,解 Gopher 之憂!歡迎關注我。

歡迎大家加入 Go 招聘交流羣,來這裏找志同道合的小夥伴!跟土撥鼠們一起交流學習。

當你在開發一個項目時,通常都會有一些咱們開發人員依賴的工具。開發、測試、構建或部署過程中運行的工具。

例如,你可以將golang.org/x/text/cmd/gotext結合使用go:generate來生成需要翻譯的消息目錄,或者 honnef.co/go/tools/cmd/staticcheck[1] 在提交更改之前對你的代碼執行靜態分析。

這其中就有幾個有趣的問題——尤其是在開發團隊環境中。你如何保證每個人的機器上都安裝了必要的工具?而且他們使用的工具都是同一個版本呢?

在 Go 1.17 之前,管理它的慣例是tools.go在項目中創建一個文件,其中包含import不同工具和//go:build tools構建約束的語句。如果您還不太熟悉這種用法,請參閱官方 Go Wiki[2] 中的描述。

但是從 Go 1.17 開始,你就可以採用另一種方法。 與該方法相比,它有利有弊tools.go,但很值得了解,並且可能非常適合某些項目。

現在允許你可以直接go run執行特定版本的遠程包。從 1.17 發佈說明 [3] 可以看出:

go run 現在接受帶有版本後綴的參數(例如,go run example.com/cmd@v1.0.0 )。這會導致 go run 以模塊感知模式構建和運行包,忽略當前目錄或任何父目錄中的 go.mod 文件(如果有的話)。

換句話說,當你在模塊之外或在模塊內部時,您可以使用它go run package@version來執行遠程包,即使該包不在go.mod文件中。

作爲無需安裝即可運行可執行包的快速方法,它也很有用。而不是這樣:

$ go install honnef.co/go/tools/cmd/staticcheck@v0.3.1 $ staticcheck ./...

你現在可以這樣做 (記得只有在 1.17 之後纔可使用):

$ go run honnef.co/go/tools/cmd/staticcheck@v0.3.1 ./...

重要提示: 當在執行go run package@version必要的模塊時,會將下載並緩存在您機器上的_模塊緩存_中。因此,當在稍後執行相同的go run命令時,將會使用緩存(而不是再次下載所有內容)並且它會更快地編譯執行完成。

使用 go:generate

讓我們看一個例子,我們將 golang.org/x/tools/cmd/stringer[4] 工具與某些iota常量結合使用go:generate生成String()方法。

運行以下命令:

$ mkdir tools 
$ go mod init example.com/tools 
$ touch main.go

然後將以下代碼添加到main.go

文件:main.go

File: main.go
package main

import "fmt"

//go:generate go run golang.org/x/tools/cmd/stringer@v0.1.10 -type=Level

type Level int

const (
    Info Level = iota
    Error
    Fatal
)

func main() {
    fmt.Printf("%s: Hello world!\n", Info)
}

這裏重要的是//go:generate這一行。當你執行go generate在此文件上時,它將會依次使用go run來執行v0.1.10版本的golang.org/x/tools/cmd/stringer

讓我們試一試:

$ go generate . 
go: downloading golang.org/x/tools v0.1.10 
go: downloading golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 
go: downloading golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 
go: downloading golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3

這裏看到下載了必要的模塊,然後go:generate命令成功完成執行——生成一個新level_string.go文件和一個應用程序。像這樣:

$ ls  
go.mod  level_string.go  main.go 
$ go run . 
Info: Hello world!

在 Makefile 中使用

還可以使用該go run package@version模式在您的腳本或 Makefile 中執行。來讓我們創建一個 Makefile,其中包含執行特定版本staticcheck工具的任務。

$ touch Makefile
.PHONY: audit
audit:
    go vet ./...
    go run honnef.co/go/tools/cmd/staticcheck@v0.3.1 ./...

如果運行make audit,將會下載必要的模塊,並且該staticcheck工具會成功地完成其檢查。

$ make audit
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@v0.3.1 ./...
go: downloading honnef.co/go/tools v0.3.1
go: downloading golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a
go: downloading golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e
go: downloading github.com/BurntSushi/toml v0.4.1

如果你第二次運行它,你會看到模塊緩存被使用了,所以會更快地運行完成。

$ make audit
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@v0.3.1 ./...

優點和缺點

優點

就積極方面而言,go run package@versiontools.go該方法相比有幾個很好的優勢

缺點

本文由小土翻譯自 Using go run to manage tool dependencies[5],翻譯不當之處,煩請指出。

參考資料

[1] honnef.co/go/tools/cmd/staticcheck: https://staticcheck.io/

[2] Go Wiki: https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module

[3] 1.17 發佈說明: https://go.dev/doc/go1.17

[4] golang.org/x/tools/cmd/stringer: https://pkg.go.dev/golang.org/x/tools/cmd/stringer

[5] Using go run to manage tool dependencies: https://www.alexedwards.net/blog/using-go-run-to-manage-tool-dependencies

Go 招聘 Golang 相關求職和招聘,以及面試題、經驗分享,Go 語言其他知識和職場也是值得分享的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/TQB5n06VYPy0iA8x5me8bA