【轉】Go Module:私有不合規庫怎麼解決引用問題

 

原文:https://mp.weixin.qq.com/s/Q28LwtYfU7KH_Zy0VbHvOA

https://zhuanlan.zhihu.com/p/420764860

 

----------------------

大家好,我是 polarisxu。

有一個朋友諮詢一個問題:

圖片

網友諮詢

實際項目中,使用 Go Module 難免會有一些自己的庫要引用,這些庫使用自建的 Git 服務管理,比如 GitLab 等。針對這樣的情況,不少教程都是讓設置 GOPRIVATE,即不走 GOPROXY。

然而,有些時候,不僅庫是私有的,而且地址很可能不是「合規」的。什麼是「不合規」的?

  • 不是 HTTPS
  • 非 443 或 80 端口
  • 直接使用 IP 地址

不是 HTTPS 問題不大,主要是非 443 或 80,以及直接 IP 地址的問題比較大。因爲 Go 不支持下面的語法:

import "studygolang.com:8081/polarisxu/util"
import "192.168.1.1:80/polarisxu/util"

一般地,我們應該避免出現這樣的情況,畢竟太噁心,而且沒必要自討苦喫。

但萬一遇到了,怎麼辦?本文就探討這個問題。

01 模擬環境

因爲之前沒遇到這樣的問題,爲了我更好的解決,這位朋友直接提供了他的環境供我試驗。我註冊了賬號,並創建了一個倉庫 testgo:http://vitogo.tpddns.cn:9000/polarisxu/testgo。(爲了方便,這個倉庫是 public)

提示:你想試驗,可以自己註冊一個賬號試試。當然,也可以通過 gitlab 本地搭建一個。

倉庫中創建文件 testgo.go,內容如下:

package testgo

func MyName() string {
 return "polarisxu"
}

關鍵是這個庫的 go.mod 如何寫?

很顯然,我們不能直接用 vitogo.tpddns.cn:9000/polarisxu/testgo 這樣的 module 名稱。

02 module 名稱

那怎麼辦?

我們可以藉助 git 的功能,將 vitogo.tpddns.cn:9000 替換掉:(也可以直接修改 ~/.gitconfig 文件)

git config --global url."http://vitogo.tpddns.cn:9000/".insteadof "https://{{gitlab_url}}/"

這裏有兩點需要注意:

1)url 後面的內容,具體什麼值,需要根據你的情況定。

可以通過你的自建倉庫查看:

圖片

查看 clone

這裏選擇 HTTP 方式(因爲我創建了一個 public 倉庫)。也可以選擇使用 ssh 方式,這樣即使私有倉庫,你配置上自己的 SSH KEY 也可正常 Pull。(如何配置 SSH KEY,網上很容易查到教程,GitHub 上就有)

我們這裏使用了 http://vitogo.tpddns.cn:9000/,表示這個域名下所有的內容。

2)insteadOf 後面的內容,表示訪問這個鏈接時,將替換爲上面 url 後的鏈接。

這個值寫什麼?很顯然,必須是合規的域名。我們任意使用一個域名試試,比如使用 https://studygolang.com/

這時,我們嘗試執行如下命令:

$ git config --global url."http://vitogo.tpddns.cn:9000/".insteadof "https://studygolang.com/"
# 讓 studygolang.com 不走 GOPROXY
$ go env -w GOPRIVATE=studygolang.com
$ go get -v studygolang.com/polarisxu/testgo
go get: unrecognized import path "studygolang.com/polarisxu/testgo": parsing studygolang.com/polarisxu/testgo: XML syntax error on line 15: unescaped < inside quoted string

很好理解,go get 最終需要將代碼下載下來,怎麼下載?這張圖很好的說明了:

圖片

go get 過程

那 go get 怎麼知道當前倉庫使用 VCS 託管的呢?對於 studygolang.com 這種域名,它會嘗試請求,判斷 CVS 類型。很顯然,studygolang.com 沒有做任何處理,不是 CVS 類型,所以報錯。

關於這個過程感興趣的,可以參考該文:https://studygolang.com/articles/35235

網友希望使用 vitogo.tpddns.cn 這個他的域名,但同樣有這個問題。如果要讓它正常,需要做特殊處理,具體參考上面的文章。

所以,我們使用一個非常用的現成 Git 公開託管服務,比如 gitea.com。(polarisxu/testgo 我打了一個 tag:v0.0.1)

$ git config --global url."http://vitogo.tpddns.cn:9000/".insteadof "https://gitea.com/"
$ go env -w GOPRIVATE=gitea.com
$ go get -v gitea.com/polarisxu/testgo
get "gitea.com/polarisxu/testgo": found meta tag vcs.metaImport{Prefix:"gitea.com/polarisxu/testgo", VCS:"git", RepoRoot:"https://gitea.com/polarisxu/testgo.git"} at //gitea.com/polarisxu/testgo?go-get=1
go: downloading gitea.com/polarisxu/testgo v0.0.1
gitea.com/polarisxu/testgo

成功了!你可以到 $GOPATH/pkg/mod 下面看是否有對應的包。

注意其中 ?go-get=1 這個參數,你可以瀏覽器訪問 https://gitea.com/polarisxu/testgo?go-get=1,然後查看源碼,看看裏面是什麼內容:

<!doctype html>
<html>
 <head>
  <meta name="go-import" content="gitea.com/polarisxu/testgo git https://gitea.com/polarisxu/testgo.git">
  <meta name="go-source" content="gitea.com/polarisxu/testgo _ https://gitea.com/polarisxu/testgo/src/branch/master{/dir} https://gitea.com/polarisxu/testgo/src/branch/master{/dir}/{file}#L{line}">
 </head>
 <body>
  go get gitea.com/polarisxu/testgo
 </body>
</html>

因此,我們可以在 polarisxu/testgo 中增加 go.mod 文件:

go mod init gitea.com/polarisxu/testgo

然後打上第二個 tag:v0.0.2,再次獲取:

$ go get -v gitea.com/polarisxu/testgo
get "gitea.com/polarisxu/testgo": found meta tag vcs.metaImport{Prefix:"gitea.com/polarisxu/testgo", VCS:"git", RepoRoot:"https://gitea.com/polarisxu/testgo.git"} at //gitea.com/polarisxu/testgo?go-get=1
go: downloading gitea.com/polarisxu/testgo v0.0.2
gitea.com/polarisxu/testgo

03 使用該包

本地創建一個項目,引用上面定義的包:

$ mkdir ~/testprivate
$ cd ~/testprivate
$ go mod init testprivate
$ touch main.go

在 main.go 中輸入如下內容:

package main

import (
    "fmt"
    "gitea.com/polarisxu/testgo"
)

func main() {
    fmt.Println("Hello", testgo.MyName())
}

執行 go mod tidy 後,運行:

$ go run main.go
Hello polarisxu

正常輸出我們期望的結果。

04 總結

通過了解 go get 的基本原理,知曉 git 的一些處理方式,以及 GOPRIVATE 的作用。我相信遇到類似的問題,你自己也能夠解決了。

注意,如果 gitea.com 你有實際使用,可以選擇 gitee.com、try.gogs.io 等。

另外,關於本文的問題,Go 有幾個相關 issue 討論:

  • https://github.com/golang/go/issues/34436
  • https://github.com/golang/go/issues/38213

參考文章

  • 私有化倉庫的 GO 模塊使用實踐:https://studygolang.com/articles/35235
  • go modules 使用本地庫、合規庫、私有庫:https://studygolang.com/articles/35234
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章