Go Wiki:解決已修改模組路徑的問題
意外的模組路徑
在專案 my-go-project
上工作的使用者可能會在 go get -u
期間遇到錯誤,如下所示
$ cd my-go-project
$ go get -u ./...
[...]
go: github.com/golang/lint@v0.0.0-20190313153728-d0100b6bd8b3: parsing go.mod: unexpected module path "golang.org/x/lint"
[...]
Exit code 1
golang.org/x/lint
是個模組,在遷移到 git 儲存庫 golang.org/x/lint
並將其模組名稱重新命名為 golang.org/x/lint
之前,其 git 儲存庫和模組名稱為 github.com/golang/lint
。Go 工具目前在嘗試了解新 git 儲存庫中的舊模組名稱時遇到困難:golang/go#30831。
這會出現在 my-go-project
中,因為 my-go-project
或其其中一個傳遞相依項在模組圖表中有一個路由到舊的 github.com/golang/lint
模組名稱。
例如,如果 my-go-project
本身依賴於舊的 github.com/golang/lint
模組名稱
$ GO111MODULE=on go mod graph
my-go-project github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
或者,my-go-project
可能依賴於舊版本的 google.golang.org/grpc
,而該版本依賴於舊的 github.com/golang/lint
模組名稱
$ GO111MODULE=on go mod graph
my-go-project google.golang.org/grpc@v1.16.0
google.golang.org/grpc@v1.16.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
最後,my-go-project
可能依賴於另一個相依項,而該相依項需要舊版本的 google.golang.org/grpc
,而該版本反過來又依賴於舊的 github.com/golang/lint
模組名稱
$ GO111MODULE=on go mod graph
my-go-project some/dep@v1.2.3
...
another/dep@v1.4.2 google.golang.org/grpc@v1.16.0
google.golang.org/grpc@v1.16.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
移除對名稱的參照
在 Go 工具更新為了解已變更其模組路徑的模組(追蹤於 golang/go#30831)之前,解決此問題的方法是更新圖表,以便不再有路徑指向舊的模組名稱。
使用上述範例,我們將探討如何更新圖表,以便不再有路徑指向 github.com/golang/lint
。
修正第一個範例很簡單,唯一的連結來自於 my-go-project
- 使用者可以控制!在 go.mod
中將舊位置替換為新位置 - github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
使用 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f
- 會從圖形中移除連結
$ GO111MODULE=on go mod graph
my-go-project golang.org/x/lint@v0.0.0-20190301231843-5614ed5bae6f
修正第二個範例涉及更多步驟,但基本上是相同的程序:google.golang.org/grpc@v1.16.0
提供連結至 github.com/golang/lint
,因此 google.golang.org/grpc
應將其 go.mod
從 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
更新為 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f
(很幸運地,這已在 v1.17.0
中發生)。然後,my-go-project
應更新其 go.mod
以包含 google.golang.org/grpc
的新版本,這樣我們現在有
$ GO111MODULE=on go mod graph
my-go-project google.golang.org/grpc@v1.17.0
google.golang.org/grpc@v1.17.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
修正第三個範例類似於第二個範例:更新為 another/dep
的較新版本,其中帶入 google.golang.org/grpc
的較新版本,而不包含對 github.com/golang/lint
的參照。
歡呼!問題解決 - 對於 Go 工具而言,不再有路徑可以通往 github.com/golang/lint
,因此它不會在 go get -u
期間遇到這個問題。
更困難的問題:移除尾隨記錄
這一切都很好,應該可以解決大多數使用者的問題。
但是,有一個情況最終會變得更加複雜:當模組相依圖形中有循環時。考慮這個模組相依圖形
並且,讓我們想像 some/lib
曾經依賴於 github.com/golang/lint
。
讓我們看看這個包含版本的模組相依圖形
$ go mod graph
my-go-lib some/lib@v1.7.0
some/lib@v1.7.0 some-other/lib@v2.5.3
some/lib@v1.7.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.3 some/lib@v1.6.0
some/lib@v1.6.0 some-other/lib@v2.5.0
some/lib@v1.6.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.0 some/lib@v1.3.1
some/lib@v1.3.1 some-other/lib@v2.4.8
some/lib@v1.3.1 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.4.8 some/lib@v1.3.0
some/lib@v1.3.0 some-other/lib@v2.4.7
some/lib@v1.3.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
使用 golang.org/x/exp/cmd/modgraphviz 視覺化
在此我們看到,儘管最後幾個版本的 some/lib
正確地依賴於 golang.org/x/lint
,但由於 some/lib
和 some-other/lib
共享一個循環,因此很可能會有一條路徑遠遠回溯到過去。
此類路徑會出現的原因在於,升級版本的程序通常是單獨原子的:當 some/lib
升級其 some-other/lib
版本並釋出其新版本時,some-other/lib
的最新版本仍依賴於 some/lib
的先前版本。也就是說,這兩個函式庫的任何個別升級都不足以移除歷史鏈。
若要移除歷史鏈並永久從圖表中移除舊的 github.com/golang/lint
參考,兩個函式庫都必須同時升級彼此的版本。
原子式升級兩個函式庫的版本
移除 github.com/golang/lint
的解決方案是,首先確保 some/lib
不依賴於 github.com/golang/lint
,然後將 some/lib
和 some-other/lib
都升級到彼此不存在的未來版本。我們需要這種圖表
my-go-lib some/lib@v1.7.1
some/lib@v1.7.1 some-other/lib@v2.5.4
some/lib@v1.7.1 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.4 some/lib@v1.7.1
由於 some/lib
和 some-other/lib
在同一個版本互相依賴,因此沒有路徑可以回溯到提供 github.com/golang/lint
的時間點。
以下是達成此原子式版本升級的步驟,假設 some/lib
位於 v1.7.0
,而 some-other/lib
位於 v2.5.3
- 驗證錯誤確實存在
- 在
some/lib
和some-other/lib
中執行GO111MODULE=on go get -u ./...
。 - 在兩個儲存庫中,您應該會看到錯誤 go:
github.com/golang/lint@v0.0.0-20190313153728-d0100b6bd8b3: parsing go.mod: unexpected module path "golang.org/x/lint"
。
- 在
- 驗證最新版本的
some/lib
依賴golang.org/x/lint
,而非github.com/golang/lint
。移除歷史軌跡很可惜,但保留對github.com/golang/lint
的損壞依賴性更糟! - 使用 alpha 標籤將兩個函式庫都升級到彼此不存在的未來版本(這比較安全,因為評估模組的最新發布版本時,go 模組不會將 alpha 版本視為較新版本)
some/lib
將其some-other/lib
依賴項從v2.5.3
變更為v2.5.4-alpha
。some/lib
標記提交v1.7.1-alpha
並推送提交和標籤。some-other/lib
將其some/lib
依賴項從v1.6.0
變更為v1.7.1-alpha
。some-other/lib
標記提交v2.5.4-alpha
並推送提交和標籤。
- 在所有內容仍處於 alpha 狀態時驗證結果
- 在
some/lib
中執行GO111MODULE=on go build ./...
和go test ./...
。 - 在
some-other/lib
中執行GO111MODULE=on go build ./...
和go test ./...
。 - 在兩個儲存庫中執行
GO111MODULE=on go mod graph
,並聲明沒有路徑可通往github.com/golang/lint
。 - 注意:
go get -u
仍然無法運作,因為如上所述,評估最新版本時不會考慮 alpha 版本。
- 在
- 如果一切看起來都不錯,請繼續再次將彼此升級到不存在的未來版本
some/lib
將其some-other/lib
依賴項從v2.5.4-alpha
變更為v2.5.4
some/lib
標記提交v1.7.1
並推送提交和標籤。some-other/lib
將其some/lib
依賴項從v1.7.1-alpha
變更為v1.7.1
。some-other/lib
標記提交v2.5.4
並推送提交和標籤。
- 驗證錯誤已不再存在
- 在
some/lib
和some-other/lib
中執行GO111MODULE=on go get -u ./...
。 - 不應出現解析錯誤
go.mod: unexpected module path "golang.org/x/lint"
。
- 在
- 目前,
some/lib
和some-other/lib
的go.sum
並不完整。這是因為我們依賴於模組的未來非存在版本,因此我們無法在程序完成之前產生 go.sum 項目。因此,我們來修正這個問題- 在
some/lib
中執行GO111MODULE=on go mod tidy
。 - 提交並標記提交
v1.7.2
,然後推播提交和標籤。 - 在
some-other/lib
中執行GO111MODULE=on go mod tidy
。 - 提交並標記提交
v2.5.5
,然後推播提交和標籤。
- 在
- 最後,我們確定
my-go-project
依賴於這些新版本的some/lib
和some-other/lib
,它們沒有很長的歷史記錄- 將
my-go-project
go.mod
項目從some/lib v1.7.0
變更為some/lib 1.7.2
。 - 在
my-go-project
中執行GO111MODULE=on go get -u ./...
來進行測試。
- 將
請注意,在步驟 5.b 和 5.d 之間,使用者會中斷:已發布依賴於 some-other/lib
非存在版本的 some/lib
版本。因此,這個程序理想上應即時執行,以便在步驟 5.b 之後儘快完成步驟 5.d,以盡可能縮小中斷的時段。
較大的循環
這個範例說明了在圖形中有兩個套件涉及循環時移除歷史記錄的程序,但如果循環涉及更多套件呢?例如,考慮以下圖形
這些圖形中的每個圖形都涉及循環(後面的範例)或相互連接的模組(前面的範例),涉及四個模組,而不是前面看到的簡單兩個模組範例。不過,程序大致相同,但這次在步驟 3 和 5 中,我們將所有四個模組升級到彼此的非存在未來版本,類似地,在步驟 4 和 6 中,我們將測試所有四個模組,並在步驟 7 修復所有四個模組的 go.sum。
更一般來說,上述流程適用於任何包含 n 個模組的互連模組群組:每個主要步驟僅涉及 n 個模組協調運作。
此內容是 Go Wiki 的一部分。