面試題:如何更新 Go Module 項目的依賴 — 解決問題的方法很重要

2022-01-28 Go招聘

這篇文章來自知識星球球友的問題:

關於 Go 語言的 mod 引用問題,比如一個主項目,裡面引用了其他人寫的 lib1,lib2,lib3 等等,lib1 中又被lib2,lib3 引用,也可能互相引用,這樣,當我更新 lib1 後,影響的 lib 就會很多,有沒有辦法在主項目中直接 go mod tidy 將所有 lib 都升級到最新版

問題描述可能不嚴謹,但大概意思是希望能夠將項目的所有依賴都升級到最新版本(兼容的)。這裡我引申一下,有如下 3 個問題:

這裡不想直接給出答案,而是想和大家一起探討下遇到類似這樣的問題怎麼找到答案,以及藉此對相關知識點有一個更全面、深入的了解。

怎麼尋找答案

對於 Go 來說,遇到問題(特別基礎的問題除外),我認為應該優先去 golang-nuts 郵件組搜索。比如這個問題通過關鍵詞 go mod update direct dependencies` 搜索。(此外,還可以嘗試在 go 倉庫的 issue 中搜索)

第 1、2 個就是相關的。查看這兩個帖子,總結解決該問題大概的方法如下:

1)查看有更新的直接依賴項的方法

go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}{{end}}' -m all

該方法還有變種,比如查看更新的版本信息:

go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}: {{.Version}} -> {{.Update.Version}}{{end}}' -m all

你可以找一個倉庫試試,比如 https://github.com/studygolang/studygolang 項目,結果如下:

code.gitea.io/sdk/gitea: v0.0.0-20191106151626-e4082d89cc3b -> v0.12.0
github.com/PuerkitoBio/goquery: v1.5.0 -> v1.5.1
github.com/go-sql-driver/mysql: v1.4.1 -> v1.5.0
github.com/go-validator/validator: v0.0.0-20180514200540-135c24b11c19 -> v0.0.0-20200605151824-2b28d334fa05
github.com/jaytaylor/html2text: v0.0.0-20190408195923-01ec452cbe43 -> v0.0.0-20200412013138-3577fbdbcff7
github.com/labstack/echo/v4: v4.1.8 -> v4.1.16
github.com/polaris1119/config: v0.0.0-20160609095218-06a751e884f3 -> v0.0.0-20160628025248-e4f8b7e9e2ef
github.com/sundy-li/html2article: v0.0.0-20170724020440-d0b6c083441f -> v0.0.0-20180131134645-09ac198090c2
github.com/tidwall/gjson: v1.3.2 -> v1.6.0
golang.org/x/net: v0.0.0-20190607181551-461777fb6f67 -> v0.0.0-20200625001655-4c5254603344
golang.org/x/oauth2: v0.0.0-20190226205417-e64efc72b421 -> v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/text: v0.3.2 -> v0.3.3
xorm.io/core: v0.7.2 -> v0.7.3
xorm.io/xorm: v0.8.0 -> v1.0.2

2)更新它們

已經找出了哪些需要更新,具體更新是通過 go get 命令,這也有兩種方式:

go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}{{end}}' -m all | xargs go get -u

go get -u $(go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}{{end}}' -m all)

回到我們開頭的問題,根據 .Indirect 來進行分別處理即可。不過,對於更新項目所有的依賴,有一個更簡便的方法,那就是直接 go get -u ./…。

當然,其實大部分問題,官方文檔都會有相關的說明,只是可能你對文檔不熟悉。

知識點學習

以上涉及到的知識點主要是 go list 命令的使用。Go 命令的學習,最權威的文檔自然是官方文檔。

$ go help list

以上命令可以查看 go list 的官方文檔,命令使用方式:

go list [-f format] [-json] [-m] [list flags] [build flags] [packages]

該命令對於 GOPATH 和 Module 有些不同,這裡忽略 GOPATH,只關注 Module 相關的內容,上面使用的幾個命令行選項說明下:

選項說明-m針對使用了 Module 的項目,Module 項目必須的選項-u加上可用升級的信息-f進行格式化輸出,使用 text/template 語法-json通過 json 格式輸出

最後的 packages,可以指定多個 package,還有兩個特殊的:

all:表示當前項目所有的活躍(當前項目使用的)模塊…:匹配特定模式的模塊,比如 github.com/… 表示匹配所有 github.com 開頭的模塊

註:Go 命令中,all、... 和 std 一般有特殊用途

針對我們的問題,重點在於 -f ,因此需要了解一個結構:Module

type Module struct {
    Path      string       // module path
    Version   string       // module version
    Versions  []string     // available module versions (with -versions)
    Replace   *Module      // replaced by this module
    Time      *time.Time   // time version was created
    Update    *Module      // available update, if any (with -u)
    Main      bool         // is this the main module?
    Indirect  bool         // is this module only an indirect dependency of main module?
    Dir       string       // directory holding files for this module, if any
    GoMod     string       // path to go.mod file used when loading this module, if any
    GoVersion string       // go version used in module
    Error     *ModuleError // error loading module
}

通過命令 go list -m -json all 可以通過 json 格式查看依賴信息,類似這樣:

...
{
 "Path": "xorm.io/core",
 "Version": "v0.7.2",
 "Time": "2019-09-28T05:59:35Z",
 "Dir": "/Users/xuxinhua/go/pkg/mod/xorm.io/core@v0.7.2",
 "GoMod": "/Users/xuxinhua/go/pkg/mod/cache/download/xorm.io/core/@v/v0.7.2.mod"
}
{
 "Path": "xorm.io/xorm",
 "Version": "v0.8.0",
 "Time": "2019-10-16T06:55:10Z",
 "Dir": "/Users/xuxinhua/go/pkg/mod/xorm.io/xorm@v0.8.0",
 "GoMod": "/Users/xuxinhua/go/pkg/mod/cache/download/xorm.io/xorm/@v/v0.8.0.mod",
 "GoVersion": "1.11"
}
...

因此如果需要更新所有直接依賴的版本,需要先找出所有的直接依賴,根據以上結構加上 text/template 模板的語法,可以寫出如下命令:

go list -m -f '{{if not (or .Main .Indirect)}}{{.Path}}{{end}}' all

但結果包含了沒有更新的依賴。有沒有可用更新可以通過 Module 結構的 Update 欄位判斷,但需要加上 -u 選項:

go list -m -u -f '{{if and (not (or .Main .Indirect)) .Update}}{{.Path}}{{end}}' all

找到了需要更新的依賴,然後就是更新了。這就需要使用到 go get 命令。關於這個命令,我留幾個問題希望你能找到答案。以 github.com/tidwall/gjson 包為例,比如 studygolang 項目目前依賴的版本是 v1.3.2,而 v1.3.x 最新版本是 v1.3.6,v1.x.x 最新版本是 v1.6.0。

1)如何更新到 v1.3.6?

2)go get -u github.com/tidwall/gjson@none 是什麼意思?

3)在 module 項目中,go get -u 和 go get -u ./... 有什麼區別?

補充

通過這個問題和尋找答案的過程,還有其他收穫:

1)有人建議 go get 可以將直接依賴和間接依賴分開更新。見 issue 28424。

2)有一個庫用於更新依賴,它通過交互的方式進行,該庫叫 go-mod-upgrade。

簡單介紹下這個庫。

交互式更新過期依賴

請注意,目前只支持補丁(patch)和次要版本更新(minor updates)。

為什麼開發此庫?

Go Wiki 在 如何升級和降級依賴關係 文檔中,介紹了一個命令:

go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}: {{.Version}} -> {{.Update.Version}}{{end}}' -m all 2> /dev/null

它查看直接依賴項的可用升級。然而,過程不可控,即我們不能通過它方便的更新某些依賴項。

此工具旨在通過交互的方式,使更新多個依賴項變得更加容易。這類似於 yarn upgrade-interactive ,但適用於 Go。

安裝
$ go get -u github.com/oligot/go-mod-upgrade

使用

在使用模塊的 Go 項目中,你現在可以運行:

$ go-mod-upgrade

這樣就會出現類似上圖的界面。其中顏色有助於標識更新類型:

交互界面中,通過空格鍵選中某個包,上下箭頭移動待選擇包,還支持直接輸入進行包的過濾,比如下圖的 gjson 就是輸入的。選中後回車,就會開始更新。

不過這個工具沒法控制升級 patch 還是 minor update。

相關焦點

  • 跳出Go module的泥潭
    Go 1.11 前天已經正式發布了,這個版本包含了兩個最重要的feature就是 module和web assembly。假設你已經有了一個go 項目, 比如在$GOPATH/github.com/smallnest/rpcx下, 你可以使用go mod init github.com/smallnest/rpcx在這個文件夾下創建一個空的go.mod (只有第一行 module github.com/smallnest/rpcx)。
  • 為什麼要使用 Go module proxy
    (不)使用 vendor 文件夾的問題 使用 vendor 文件夾的問題在模塊感知模式[1]開啟時,使用 go 命令,默認不再使用 vendor 文件夾。如果你不附加 -mod=vendor 參數,這個文件夾將不會被啟用。
  • 從此再無包下載的任何煩惱:看高手是如何參透 Go Module 的?
    本次分享將討論如何使用模塊和模塊代理,以及在它們的使用中會常遇見的坑,還會講解如何快速搭建自己的私有模塊代理,並簡單地介紹一下七牛雲推出的 goproxy.cn 以及它的出現對於中國 Go 語言開發者來說重要在何處。
  • 如何面試.NET/ASP.NET工程師?
    ,能夠運用腳本等方法對開發流程、持續集成和部署等步驟進行自動化積極了解其他社區的典型實踐與工具,並擇優吸收運用到團隊中,以改善產品質量、提升開發效率等=========== 2013年的原回答如下 ============題主應該是希望了解一些面試 http://ASP.NET 程式設計師的一些考察方法和方向。
  • Vue面試中,經常會被問到的面試題
    看看面試題,只是為了查漏補缺,看看自己那些方面還不懂。
  • 【每日一題】(39題)關於script標籤,你可能不知道的地方?
    script,同時也會忽略傳統script中不認識的nomodule屬性,進而執行傳統的bundle.js代碼 module script以及其依賴所有文件(源文件中通過import聲明導入的文件)都會被下載,一旦整個依賴的模塊樹都被導入,頁面文檔也完成解析,app.js將會被執行 但是如果module script裡有async屬性,比如,module script及其所有依賴都會異步下載,待整個依賴的模塊樹都被導入時會立即執行
  • Go 項目推薦之喜歡 yarn 交互模式更新依賴的 gopher 有福了
    項目地址:https://github.com/oligot/go-mod-upgrade請注意,目前只支持補丁(patch)和次要更新(minor updates)。設計該庫的目的 Go Wiki 在 如何升級和降級依賴關係: https://github.com/golang/go/wiki/Modules#how-to-upgrade-and-downgrade-dependencies 文檔中,介紹了一個命令:go list -u -f
  • 項目改用GoModules管理依賴的方法和經驗總結
    GoLand配置截圖Replace完成版本替換replace指令的本意是在go.mod文件裡完成用一個模塊版本替換已經require的模塊版本的功能,比如:module code.lazycorp.com/buzz/practice // 這名是我瞎起的go 1.13
  • Go Module 有漏洞?免費的 Go 漏洞掃描 VSCode 插件
    它是為 JFrog Xray 客戶提供的針對流行 IDE[2] 的幾種 JFrog 集成之一,使開發人員更容易理解開源依賴的風險,並有助於保持對安全的警惕。為了幫助實現使軟體開發和交付更快、更安全和更可靠的使命,JFrog 將 VSCode 擴展提高到了一個新水平。
  • 面試必看!41道SpringBoot面試題
    來源:阿凱的帽子反戴原:blog.csdn.net/Kevin_Gu6/article/details/88547424今天跟大家分享下SpringBoot 常見面試題的知識
  • 運行Scrapy程序時出現No module named win32api問題的解決思路和方法
    ,但是在執行Scrapy爬蟲程序的時候卻出現下列報錯:「No module named win32api」,如下圖所示,但是不知道怎麼破,今天就這個問題講解一下解決方案。很多小夥伴看到「No module named win32api」,於是乎便想著直接輸入安裝命令「pip install win32api」,結果系統給出下圖提示:
  • 2018年最常見的Python面試題&答案(上篇)
    編程網站DataFlair的技術團隊分享了一份2018年最常見Python面試題合集,既有基本的Python面試題,也有高階版試題來指導你準備面試,試題均附有答案。面試題內容包括編碼、數據結構、腳本撰寫等話題。本文為上篇。Q 1:Python有哪些特點和優點?
  • Facebook 面試題全解析
    在這篇文章中,我來介紹一下你在面試Facebook的前端工程師職位時可能會遇到的面試題。本題中,「展平」的數組指的是所有元素均為基本類型的數組。示例輸入:[1, [2, [3], 4], [5]]輸出:[1, 2, 3, 4, 5]
  • 一套北京上市公司的Python面試題解答, 讓你明白基礎紮實是多重要
    既有基本的Python面試題,也有高階版試題來指導你準備面試,試題均附有答案。面試題內容包括編碼、數據結構、腳本撰寫等話題。1:Python有哪些特點和優點?2:深拷貝和淺拷貝之間的區別是什麼?另外,使用isupper()和islower()方法檢查字符春是否全為大寫或小寫。
  • 尚矽谷Java視頻教程_Java面試題第一季
    網際網路寒冬來臨,打鐵還需自身硬,嘟嘟這裡分享一套最新Java面試題視頻,祝你更上一層樓。
  • 【每日一題】(41題)JS代碼到底是如何被壓縮的?
    大家通常都會認為,現在在網絡時代,動不動就是10M光纖,100M光纖,撥號上網讓人感覺是上個世紀的事情,說法是沒有問題,但是,我們今天討論的並不是終端下載速度,而是前端壓縮對伺服器有何好處和如何被壓縮的?一、前言前端不斷發展,特別是 React,Vue 等框架構造單頁應用的興起,項目的複雜度越來越大。
  • Go 問題集 - cannot find main module; packages.Load error
    If you believe this is a mistake, please file an issue: https://github.com/golang/go/issues/new. go [-e -json -compiled=true -test=true -export=false -deps=true -find=false -- ./]: exit status 1: go: cannot
  • Go1.16 重磅發布,新版本特性一覽
    春節假期的最後一天,千呼萬喚始出來,Go1.16 終於正式發布馬上又要上班了,譁譁譁首先看看如何更新到都1202年了,也該學學go modules怎麼用了。go build不再更改mod相關文件以前的教程裡我提到過go build會自動下載依賴,這會更新mod文件。現在這一行為被禁止了。想要安裝、更新依賴只能使用go get命令,go build和go test將不會再做這類工作。
  • golang 依賴管理之 mod
    ,也仍然支持放到 $GOPATH 下,通過 GO111MODULE 環境變量控制GO111MODULE=off: 關閉 mod,查找 vendor 目錄和 $GOPATH 路徑下的依賴GO111MODULE=on: 開啟 mod, 僅根據 go.mod 下載和查找依賴GO111MODULE=auto: 默認值,在非 $GOPATH 路徑並且包含 go.mod 的項目中才開啟 mod
  • 圖解Spring循環依賴,看過之後再也不怕面試被問到了!
    ,是近兩年流行起來的一道Java面試題。如果筆者作為面試官,可能會問一些諸如「如果注入的屬性為null,你會從哪幾個方向去排查」這些場景題。那麼既然寫了這篇文章,閒話少說,發車看看Spring是如何解決的循環依賴,以及帶大家看清循環依賴的本質是什麼。