Go Modules使用教程

来源:https://www.cnblogs.com/klsw/archive/2019/09/17/11537850.html
-Advertisement-
Play Games

Go Modules 不完全教程 文章轉載自公眾號 Golang 成神之路 , 作者 L Go Modules 是 Golang 官方最近幾個版本推出的原生的包管理方式,在此之前,社區也不乏多種包管理方案。在討論 Go Modules 之前,我們先回顧一下 Golang 的包管理歷史的發展。然後討論 ...


Go Modules 不完全教程

文章轉載自公眾號 Golang 成神之路 , 作者 L

Go Modules 是 Golang 官方最近幾個版本推出的原生的包管理方式,在此之前,社區也不乏多種包管理方案。在討論 Go Modules 之前,我們先回顧一下 Golang 的包管理歷史的發展。然後討論一下 Go Modules 的使用以及一些特性,篇幅有限,有些地方不方便展開,後面有時間再深入。行文倉促,不當之處,多多指教。

 

0. 包管理的歷史

Golang 的包管理一直被大眾所詬病的一個點,但是我們可以看到現在確實是在往好的方向進行發展。下麵是官方的包管理工具的發展歷史:

  • 在 1.5 版本之前,所有的依賴包都是存放在 GOPATH 下,沒有版本控制。這個類似 Google 使用單一倉庫來管理代碼的方式。這種方式的最大的弊端就是無法實現包的多版本控制,比如項目 A 和項目 B 依賴於不同版本的 package,如果 package 沒有做到完全的向前相容,往往會導致一些問題。

  • 1.5 版本推出了 vendor 機制。所謂 vendor 機制,就是每個項目的根目錄下可以有一個 vendor 目錄,裡面存放了該項目的依賴的 package。go build 的時候會先去 vendor 目錄查找依賴,如果沒有找到會再去 GOPATH 目錄下查找。

  • 1.9 版本推出了實驗性質的包管理工具 dep,這裡把 dep 歸結為 Golang 官方的包管理方式可能有一些不太準確。關於 dep 的爭議頗多,比如為什麼官方後來沒有直接使用 dep 而是弄了一個新的 modules,具體細節這裡不太方便展開。

  • 1.11 版本推出 modules 機制,簡稱 mod,也就是本文要討論的重點。modules 的原型其實是 vgo,關於 vgo,可以參考文章末尾的參考鏈接。

除此之外,社區也一直在有幾個活躍的包管理工具,使用廣泛且具有代表性的主要有下麵幾個:

  • godep

  • glide

  • govendor

關於這幾種包管理工具的使用這裡就不再詳述了。

 

1. modules 簡單使用方式


下麵看一下 modules 的簡單使用方式。

1.1 準備工作

Golang 版本:1.12.3。在 1.12 版本之前,使用 Go modules 之前需要環境變數 GO111MODULE:

  • GO111MODULE=off: 不使用 modules 功能。

  • GO111MODULE=on: 使用 modules 功能,不會去 GOPATH 下麵查找依賴包。

  • GO111MODULE=auto: Golang 自己檢測是不是使用 modules 功能。

在 GOPATH 之外創建一個項目 mod-demo,包含一個 main.go 文件,內容如下:

packagemain
import("github.com/astaxie/beego")
funcmain() { beego.Run()}

1.2 初始化

初始化很簡單,在項目根目錄執行命令 go mod init mod-demo ,然後會生成一個 go.mod 文件如下。

➜ mod-demo $ gomod init mod-demogo: creating new go.mod: module .➜ mod-demo $ lsgo.mod     main.go➜ mod-demo $ catgo.modmodule .
go 1.12

 

這裡比較關鍵的就是這個 go.mod 文件,這個文件中標識了我們的項目的依賴的 package 的版本。執行 init 暫時還沒有將所有的依賴管理起來。我們需要將程式 run 起來(比如執行 go run/test),或者 build(執行命令 go build)的時候,才會觸發依賴的解析。

比如使用 go run 即可觸發 modules 工作。

➜ mod-demo $ gorun main.gogo: extracting github.com/astaxie/beego v1.12.02019/09/08 23:23:03.507 [I] http server Running on http://:8080

這個時候我們再查看 go.mod 文件:

➜ mod-demo $ catgo.modmodule mod-demo
go 1.12
require (github.com/astaxie/beego v1.12.0github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect)

同時我們發現項目目錄下多了一個 go.sum 用來記錄每個 package 的版本和哈希值。go.mod 文件正常情況會包含 module 和 require 模塊,除此之外還可以包含 replace 和 exclude 模塊。

這些 package 並不是直接存儲到 $GOPATH/src,而是存儲到 $GOPATH/pkg/mod 下麵,不同版本並存的方式。

➜ mod-demo $ ls$GOPATH/pkg/mod/github.com/astaxiebeego@v1.11.0 beego@v1.11.1 beego@v1.12.0

1.3 依賴升級(降級)

可以使用如下命令來查看當前項目依賴的所有的包。

➜ mod-demo $ golist -m-uallgo: finding github.com/beego/x2j latestgo: finding github.com/cloudflare/golz4 latestgo: finding github.com/siddontang/go latestgo: finding github.com/shiena/ansicolor latestgo: finding github.com/couchbase/go-couchbase latestgo: finding github.com/siddontang/rdb latestgo: finding gopkg.in/check.v1 latestgo: finding github.com/siddontang/ledisdb latestgo: finding github.com/ssdb/gossdb latestgo: finding github.com/couchbase/gomemcached latestgo: finding github.com/wendal/errors latestgo: finding github.com/couchbase/goutils latestgo: finding golang.org/x/net latestgo: finding github.com/cupcake/rdb latestgo: finding github.com/beego/goyaml2 latestgo: finding golang.org/x/crypto latestgo: finding github.com/bradfitz/gomemcache latestgithub.com/Knetic/govaluate v3.0.0+incompatiblegithub.com/OwnLocal/goes v1.0.0github.com/astaxie/beego v1.12.0...

如果我想要升級(降級)某個 package 則只需要 go get 即可,比如:

go get package@version

 

需要註意的是,在 modules 模式開啟和關閉的情況下,go get 的使用方式不是完全相同的。在 modules 模式開啟的情況下,可以通過在 package 後面添加 @version 來表明要升級(降級)到某個版本。如果沒有指明 version 的情況下,則預設先下載打了 tag 的 release 版本,比如 v0.4.5 或者 v1.2.3;如果沒有 release 版本,則下載最新的 pre release 版本,比如 v0.0.1-pre1。如果還沒有則下載最新的 commit。這個地方給我們的一個啟示是如果我們不按規範的方式來命名我們的 package 的 tag,則 modules 是無法管理的。version 的格式為 v(major).(minor).(patch) ,更多信息可以參考:https://semver.org/ 。

比如我們現在想將我們依賴中的 beego 項目的版本改為 v1.11.1,則可以像如下操作。我們發現執行完 go get 之後, go.mod 中的項目的版本也相應改變了。

➜ mod-demo $ gogetgithub.com/astaxie/beego@v1.11.1go: finding github.com/astaxie/beego v1.11.1go: downloading github.com/astaxie/beego v1.11.1go: extracting github.com/astaxie/beego v1.11.1➜ mod-demo $ catgo.modmodule .
go 1.12
require (github.com/OwnLocal/goes v1.0.0 // indirectgithub.com/astaxie/beego v1.11.1 // indirectgithub.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect)

在 modules 開啟的模式下,go get 還支持 version 模糊查詢,比如 > v1.0.0 表示大於 v1.0.0 的可使用版本;< v1.12.0 表示小於 v1.12.0  版本下最近可用的版本。version 的比較規則按照 version 的各個欄位來展開。

除了指定版本,我們還可以使用如下命名使用最近的可行的版本:

  • go get -u 使用最新的 minor 或者 patch 版本

  • go get -u=patch 使用最新的 patch 版本

1.4 vendor

我們知道 Go 1.5 推出了 vendor 機制,go mod 也可以支持 vendor 機制,將依賴包拷貝到 vendor 目錄。但是像一些 test case 裡面的依賴包並不會拷貝的 vendor 目錄中。

➜ mod-demo $ gohelp mod vendorusage: go mod vendor [-v]
Vendor resets the main module's vendor directory to include all packagesneeded to build and test all the main module's packages.It does not include test code forvendored packages.

 

2. modules 特性


上面介紹了 go modules 的簡單使用方法,但是 modules 的一些更高級的特性沒有介紹,將在下麵進行展開。

2.1 GoProxy

proxy 顧名思義,代理伺服器。眾所周知,有些 Golang 的 package 在國內是無法直接 go get 的。在之前,我們解決這個問題,一般都是通過設置 http_proxy/https_proxy 來解決。GoProxy 相當於官方提供了一種 proxy 的方式讓用戶來進行包下載。要使用 GoProxy 只需要設置環境變數 GOPROXY 即可。目前公開的 GOPROXY 有:

  • goproxy.io

  • goproxy.cn: 由七牛雲提供,參考 github repo

當然你也可以實現自己的 GoProxy 服務,比如項目中的依賴包含外部依賴和內部依賴的時候,那麼只需要實現 module proxy protocal 協議即可。

值得註意的是,在最新 release 的 Go 1.13 版本中預設將 GOPROXY 設置為 https://proxy.golang.org,這個對於國內的開發者是無法直接使用的。所以如果升級了 Go 1.13 版本一定要把 GOPROXY 手動改掉。

2.2 Replace

replace 主要為瞭解決某些包發生改名的問題。

對於另外一種場景有的時候也是有用的,比如對於有些 golang.org/x/ 下麵的包由於某些原因在國內是下載不了的,但是對應的包在 github 上面是有一份拷貝的,這個時候我們就可以將 go.mod 中的包進行 replace 操作。

下麵是一個 Beego 項目的 go.mod 的 replace 的示例。

replace golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 => github.com/golang/crypto v0.0.0-20181127143415-eb0de9b17e85
replace gopkg.in/yaml.v2 v2.2.1 => github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d

2.3 SubCommand

modules 支持的 subcommand 如下。

mod-demo $ gohelp modGo mod provides access to operations on modules.
Note that support formodules is built into all the go commands,not just 'go mod'. For example, day-to-day adding, removing, upgrading,and downgrading of dependencies should be doneusing 'go get'.See 'go help modules'foran overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cacheedit edit go.mod from tools or scriptsgraph print module requirement graphinit initialize new module incurrent directorytidy add missing and remove unused modulesvendor makevendored copy of dependenciesverify verify dependencies have expected contentwhy explain why packages or modules are needed
Use "go help mod <command>"formore information about a command.

每個 subcommand 的含義如下:

  • download: 下載 modules 到本地緩存

  • edit: 提供一種命令行交互修改 go.mod 的方式

  • graph: 將 module 的依賴圖在命令行列印出來,其實並不是很直觀

  • init: 初始化 modules,會生成一個 go.mod 文件

  • tidy: 清理 go.mod 中的依賴,會添加缺失的依賴,同時移除沒有用到的依賴

  • vendor: 將依賴包打包拷貝到項目的 vendor 目錄下,值得註意的是並不會將 test code 中的依賴包打包到 vendor 中。這種設計在社區也引起過幾次爭論,但是並沒有達成一致。

  • verify: verify 用來檢測依賴包自下載之後是否被改動過。

  • why: 解釋為什麼 package 或者 module 是需要,但是看上去解釋的理由並不是非常的直觀。

➜ mod-demo $ gomod why github.com/astaxie/beego# github.com/astaxie/beegomod-demogithub.com/astaxie/beego

 

3. Go 1.13 對 modules 的改動


上面在討論 GoProxy 的時候提到了 Go 1.13 預設設置環境變數 GOPROXY 的值,除此之外 Go 1.13 對 modules 還有哪些值得註意的改動呢?

3.1 預設開啟

modules 在 Go 1.13 的版本下是預設開啟的。

3.2 GOPRIVATE

前面也說到對於一些內部的 package,GoProxy 並不能很好的處理,Go 1.13 推出了 GOPRIVATE 機制。只需要設置這個環境變數,然後標識出哪些 package 是 private 的,那麼對於這個 package 的處理將不會從 proxy 下載。GOPRIVATE 的值是一個以逗號分隔的列表,支持正則(正則語法遵守 Golang 的 包 path.Match)。下麵是一個 GOPRIVATE 的示例:

GOPRIVATE=*.corp.example.com,rsc.io/private

上面的 GOPRIVATE 表示以 *.corp.example.com 或者 rsc.io/private 開頭的 package 都是私有的。

3.3 GOSUMDB

GOSUMDB 的全稱為 Go CheckSum Database,用來下載的包的安全性校驗問題。包的安全性在使用 GoProxy 之後更容易出現,比如我們引用了一個不安全的 GoProxy 之後然後下載了一個不安全的包,這個時候就出現了安全性問題。對於這種情況,可以通過 GOSUMDB 來對包的哈希值進行校驗。當然如果想要關閉哈希校驗,可以將 GOSUMDB 設置為 off;如果要對部分包關閉哈希校驗,則可以將包的首碼設置到環境變數中 GONOSUMDB 中,設置規則類似 GOPRIVATE。

關於 GOSUMDB 的配置格式為:<db_name>+<publickey>+<url>。

GOSUMDB="sum.golang.org"GOSUMDB="sum.golang.org+<publickey>"GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"

上面三種配置都是合理的,因為對於 sum.golang.org,Go 自己知道其對應的 publickey 和 url,所以我們只要配置一個名字即可,對於另外一個 sum.golang.google.cn 也是一樣。除此之外的,都需要指明 publickey,url 預設是 https://<db_name>。

關於 GOSUMDB 更多的詳細信息可以參考:https://golang.org/cmd/go/#hdr-Module_authentication_failures

 

4. 總結


Golang 包管理歷經多個版本,目前來看並沒有一個完全讓開發者滿意的方案,比如類似 Java 的 maven 的包管理方式。很多開發者也表示 modules 的管理方式也不是很直觀。其實 Golang 的 package 使用 git 的管理方式來管理其實是一個很好的管理方式,我們最需要的其實如何能讓普通開發者獲取到任何 package 的心智負擔降到最低。值得欣慰的是我們確實有看到大家在這個方向上的努力,比如 modules 的 GoProxy。

放眼未來,希望會有一種令大部分普通開發者滿意的包管理方式吧。

 

5. Reference


  1. https://research.swtch.com/vgo

  2. https://github.com/golang/go/wiki/Modules

  3. https://roberto.selbach.ca/intro-to-go-modules/

  4. https://roberto.selbach.ca/playing-with-go-modules/

  5. https://semver.org/

  6. https://golang.org/cmd/go/#hdr-Module_authentication_failures

  7. https://golang.org/doc/go1.13#modules

  8. https://goproxy.io

  9. https://github.com/goproxy/goproxy.cn

  10. https://codeengineered.com/blog/2018/golang-godep-to-vgo/

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題目一: 思路:當n=1的時候很明顯只有一種跳法; 當n>1的時候,那麼總共的跳法應該就是第一次跳一級臺階還剩下n-1個臺階、第一次跳兩級臺階還剩下n-2個臺階,這兩種情況的總和,而至於這裡的n-1和n-2個臺階,同理可以繼續拆分,是不是覺得很熟悉,還是斐波那契數列,這裡用的還是分治的思想,代碼跟上 ...
  • 個人學習筆記! 1)分散式鎖的實現?①資料庫實現單點、非重入、非阻塞、無失效時間、依賴資料庫(要自己設置,可結合排它鎖、樂觀鎖、悲觀鎖等混合使用)②緩存(Redis等)集群部署解決單點問題、分散式鎖方法直接調用即可(redis的setnx方法)、設置超時時間控制鎖的釋放③zka.集群部署(解決單點問 ...
  • 1 變數 賦值:變數可以是字元串、序列、元組、 輸出效果: 2019 9 17-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*name subjet soce year moth dayali english 65 2019 9 17-*-*-*-*-*-*-*-*- ...
  • Python Flask高級編程之從0到1開發《魚書》精品項目 部分課程截圖: 點擊鏈接或搜索QQ號直接加群獲取其它資料: 鏈接:https://pan.baidu.com/s/1uwU9rUdXw7THg5yEozYeoA 提取碼:l4gz 免費分享,如若鏈接失效請加群 其它資源在群里,私聊管理員 ...
  • 簡單整理常用演算法,記錄在此。 package com.demo.sort; import java.util.Arrays; public class Sort { public static void main(String[] args) { int size = 10; int[] arr = ...
  • 2019-09-17-23:09:48 今天學的內容是有關小數據池的,學的有點懵逼,感覺越來越難學了,但是得堅持下去 明天學習下一個課程時,感覺要跟不上,看來明天得先看好幾遍今天的內容 不然肯定會聽的懵逼 今天看見嗶哩嗶哩很多這樣的視頻,內容和我網上買的一樣的,心塞啊!!!!!!!!!!!! 今天的 ...
  • 本文源碼: "GitHub·點這裡" || "GitEE·點這裡" 一、生活場景 1、場景描述 在移動互聯網沒有普及之前,去飯店吃飯的流程大致如下:選座位,排隊,點菜,結賬。後來移動互聯網普及,通過手機APP就可以操作這些流程,非常的方便快捷:通過手機可以知道某飯店是不是還有空位,到了飯店之後直接入 ...
  • Dockerfile是一個文本文件,按順序包含構建給定鏡像所需的所有命令Docker通過讀取Dockerfile中的指令自動構建圖像 。 Dockerfile遵循特定的格式和指令集,您可以在Dockerfile引用中找到它們。 Docker鏡像由只讀層組成,每個層都代表一個Dockerfile指令。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...