[インデックス 12419] ファイルの概要
このコミットは、Go言語のパッケージ管理ツールである go get
コマンドの機能を拡張し、任意のURLをバージョン管理システム(VCS)のリポジトリへのエイリアスとして使用できるようにするものです。これにより、ユーザーはより短く、またはカスタムドメインを使用したインポートパスでGoパッケージを取得できるようになります。
コミット
commit 932c8ddba158a91056eba87045bb6d5ddbeb39f7
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Mar 5 22:36:15 2012 -0800
cmd/go: allow go get with arbitrary URLs
This CL permits using arbitrary, non-VCS-qualified URLs as
aliases for fully VCS-qualified and/or well-known code hosting
sites.
Example 1) A VCS-qualified URL can now be shorter.
Before:
$ go get camlistore.org/r/p/camlistore.git/pkg/blobref
After:
$ go get camlistore.org/pkg/blobref
Example 2) A custom domain can be used as the import,
referencing a well-known code hosting site.
Before:
$ go get github.com/bradfitz/sonden
After:
$ go get bradfitz.com/pkg/sonden
The mechanism used is a <meta> tag in the HTML document
retrieved from fetching:
https://<import>?go-get=1 (preferred)
http://<import>?go-get=1 (fallback)
The meta tag should look like:
<meta name="go-import" content="import-alias-prefix vcs full-repo-root">
The full-repo-root must be a full URL root to a repository containing
a scheme and *not* containing a ".vcs" qualifier.
The vcs is one of "git", "hg", "svn", etc.
The import-alias-prefix must be a prefix or exact match of the
package being fetched with "go get".
If there are multiple meta tags, only the one with a prefix
matching the import path is used. It is an error if multiple
go-import values match the import prefix.
If the import-alias-prefix is not an exact match for the import,
another HTTP fetch is performed, at the declared root (which does
*not* need to be the domain's root).
For example, assuming that "camlistore.org/pkg/blobref" declares
in its HTML head:
<meta name="go-import" content="camlistore.org git https://camlistore.org/r/p/camlistore" />
... then:
$ go get camlistore.org/pkg/blobref
... looks at the following URLs:
https://camlistore.org/pkg/blobref?go-get=1
http://camlistore.org/pkg/blobref?go-get=1
https://camlistore.org/?go-get=1
http://camlistore.org/?go-get=1
Ultimately it finds, at the root (camlistore.org/), the same go-import:
<meta name="go-import" content="camlistore.org git https://camlistore.org/r/p/camlistore" />
... and proceeds to trust it, checking out git //camlistore.org/r/p/camlistore at
the import path of "camlistore.org" on disk.
Fixes #3099
R=r, rsc, gary.burd, eikeon, untheoretic, n13m3y3r, rsc
CC=golang-dev
https://golang.org/cl/5660051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/932c8ddba158a91056eba87045bb6d5ddbeb39f7
元コミット内容
このコミットは、go get
コマンドが、バージョン管理システム(VCS)のタイプやリポジトリのフルパスを直接指定せずに、より簡潔なインポートパスでGoパッケージを取得できるようにする機能を追加します。具体的には、ウェブサイトのHTML内に埋め込まれた <meta name="go-import">
タグを介して、カスタムのインポートパスを実際のVCSリポジトリにマッピングするメカニズムを導入します。
これにより、以下のような利点が得られます。
- インポートパスの短縮: VCSのタイプやリポジトリの
.git
などの拡張子を含まない、より短いインポートパスを使用できるようになります。 - カスタムドメインの利用: ユーザーは自身のカスタムドメインをGoパッケージのインポートパスとして使用し、その背後でGitHubやBitbucketなどの既存のコードホスティングサイトを利用できるようになります。これは「バニティインポートパス(Vanity Import Paths)」として知られる機能です。
この機能は、go get
が指定されたインポートパスに対応するURLに ?go-get=1
クエリパラメータを付加してHTTP(S)リクエストを送信し、そのレスポンスHTMLから特定のメタタグを解析することで実現されます。
変更の背景
この変更が導入される以前の go get
コマンドは、Goパッケージのインポートパスが直接VCSリポジトリの構造を反映しているか、またはGoが認識している特定のコードホスティングサイト(例: github.com
、bitbucket.org
)のパターンに従っている必要がありました。
しかし、この方式にはいくつかの課題がありました。
- インポートパスの冗長性: リポジトリのフルパスやVCSのタイプ(例:
.git
)がインポートパスに含まれるため、パスが長くなりがちでした。 - ベンダーロックイン: 特定のコードホスティングサービスに依存したインポートパスは、将来的にサービスを移行する際にインポートパスを変更する必要が生じ、既存のコードベースに影響を与える可能性がありました。
- ブランドの一貫性: 開発者が自身のカスタムドメインをGoパッケージのインポートパスとして使用したい場合、直接的な方法がありませんでした。これは、プロジェクトのブランドを確立し、よりプロフェッショナルな印象を与える上で重要です。
これらの課題を解決し、go get
の柔軟性と使いやすさを向上させるために、任意のURLをVCSリポジトリへのエイリアスとして機能させるメカニズムが求められていました。このコミットは、その解決策としてHTMLのメタタグを利用した「バニティインポートパス」のサポートを導入しました。
前提知識の解説
このコミットの理解を深めるために、以下の概念について事前に理解しておくことが役立ちます。
go get
コマンド: Go言語の公式ツールチェーンに含まれるコマンドで、リモートリポジトリからGoパッケージのソースコードを取得し、ローカルのGOPATH
に配置する役割を担います。依存関係の解決とダウンロードも行います。- インポートパス (Import Path): Go言語において、パッケージを一意に識別するための文字列です。通常、リポジトリのURLとディレクトリ構造を組み合わせた形式を取ります(例:
github.com/user/repo/package
)。 - バージョン管理システム (VCS): ソフトウェアのソースコードやその他のファイルの変更履歴を管理するためのシステムです。Git、Mercurial (Hg)、Subversion (Svn) などがあります。
go get
はこれらのVCSと連携してリポジトリをクローンします。 - HTML
<meta>
タグ: HTMLドキュメントの<head>
セクション内に配置され、ページのメタデータ(ページに関する情報)を提供するタグです。name
属性とcontent
属性を組み合わせて、様々な情報を指定できます。このコミットでは、name="go-import"
という特定のメタタグが利用されます。 - HTTP(S) リクエスト: ウェブブラウザとウェブサーバー間で情報をやり取りするためのプロトコルです。
go get
は、パッケージの情報を取得するためにHTTP(S)リクエストを送信します。 - クエリパラメータ: URLの末尾に
?
の後に続くkey=value
形式のデータです。サーバーに特定の情報や指示を伝えるために使用されます。このコミットでは?go-get=1
が使用されます。 - GOPATH: Go言語のワークスペースのルートディレクトリを指す環境変数です。
go get
でダウンロードされたパッケージは、このディレクトリのsrc
サブディレクトリ以下に配置されます。 - ブートストラップ (Bootstrap): ソフトウェア開発において、より複雑なシステムを構築するために必要な最小限の機能セットや初期プロセスを指します。Goのツールチェーンでは、自己ホスト型コンパイラやツールを構築するために、よりシンプルなブートストラップ版の
go
コマンドが存在します。このコミットでは、ブートストラップ版とフル機能版のgo
コマンドでHTTP処理の有無が区別されています。
技術的詳細
このコミットの核となる技術的詳細は、go get
コマンドがインポートパスを解決する際の新しいロジックと、それに伴うHTTPリクエストおよびHTML解析の導入にあります。
-
インポートパス解決のフロー変更:
- 従来の
go get
は、インポートパスが既知のVCSホスティングサイトのパターン(例:github.com/user/repo
)に一致するか、またはVCSタイプを明示的に含むパス(例:example.com/repo.git/pkg
)であるかを静的に判断していました。 - このコミットにより、
repoRootForImportPath
関数が導入され、まずrepoRootForImportPathStatic
で静的なパターンマッチングを試みます。 - 静的なマッチングに失敗した場合(
errUnknownSite
が返された場合)、repoRootForImportDynamic
関数が呼び出され、動的な解決プロセスが開始されます。
- 従来の
-
動的なインポートパス解決 (
repoRootForImportDynamic
):- この関数は、指定されたインポートパス(例:
bradfitz.com/pkg/sonden
)に対してHTTP(S)リquestを送信します。 - リクエストURLは、インポートパスに
?go-get=1
クエリパラメータを付加した形式になります(例:https://bradfitz.com/pkg/sonden?go-get=1
)。HTTPSが優先され、失敗した場合はHTTPが試行されます。この処理はhttpsOrHTTP
関数によって行われます。 - レスポンスとして返されたHTMLドキュメントの
<head>
セクションを解析し、<meta name="go-import" content="import-alias-prefix vcs full-repo-root">
形式のメタタグを探します。この解析はparseMetaGoImports
関数(discovery.go
に新設)によって行われます。 - 複数の
go-import
メタタグが存在する場合、matchGoImport
関数がインポートパスに最も一致するimport-alias-prefix
を持つタグを選択します。複数のタグが同じインポートパスに一致する場合はエラーとなります。 - 取得したメタタグの情報(
Prefix
、VCS
、RepoRoot
)に基づいて、実際のVCSリポジトリのURLと、そのリポジトリがディスク上のどこに配置されるべきかのルートパスを決定します。
- この関数は、指定されたインポートパス(例:
-
非権威的なメタタグの検証:
- もし
go-import
メタタグのimport-alias-prefix
が元のインポートパスと完全に一致しない場合(例:go get example.com/pkg/sub
でexample.com
というプレフィックスのメタタグが見つかった場合)、go get
はそのメタタグが宣言しているPrefix
のURL(例:https://example.com/?go-get=1
)に対しても再度HTTP(S)リクエストを送信し、同じgo-import
メタタグが存在するかどうかを確認します。 - この「二重チェック」は、悪意のあるユーザーが自身のサブパスに偽の
go-import
メタタグを配置し、ユーザーを別のリポジトリに誘導する「なりすまし」攻撃を防ぐための重要なセキュリティ対策です。ルートパスで同じ情報が確認できなければ、そのメタタグは信頼されません。
- もし
-
エラーハンドリングとロギング:
- HTTPフェッチの失敗、メタタグの解析エラー、不正なメタタグの形式(例:
RepoRoot
にスキームがない)、未知のVCSタイプなどが適切にエラーとして処理されます。 - 詳細モード (
-v
フラグ) が有効な場合、log.Printf
を使用してフェッチURLや見つかったメタタグの情報がログに出力され、デバッグが容易になります。
- HTTPフェッチの失敗、メタタグの解析エラー、不正なメタタグの形式(例:
これらの変更により、go get
はより柔軟なインポートパスの解決能力を獲得し、Goパッケージの配布と利用の自由度を大幅に向上させました。
コアとなるコードの変更箇所
このコミットでは、主に以下の5つのファイルが変更されています。
-
src/cmd/go/bootstrap.go
:- ブートストラップ版の
go
コマンドにおけるHTTP関連関数のスタブが変更されました。 httpGET
関数がerrHTTP
を返すように変更され、httpsOrHTTP
およびparseMetaGoImports
のスタブが追加されました。これは、ブートストラッププロセス中にネットワーク機能が不要であることを保証するためです。
- ブートストラップ版の
-
src/cmd/go/discovery.go
(新規ファイル):- HTMLドキュメントから
go-import
メタタグを解析するための新しいロジックが実装されています。 parseMetaGoImports
関数はio.Reader
からHTMLを読み込み、XMLデコーダを使用して<head>
セクション内の<meta name="go-import">
タグを抽出します。attrValue
ヘルパー関数は、XML属性リストから指定された名前の属性値を取得します。- このファイルは、ブートストラップ版の
go
コマンドにはコンパイルされないように// +build !cmd_go_bootstrap
ディレクティブが付けられています。
- HTMLドキュメントから
-
src/cmd/go/get.go
:downloadPackage
関数内で、VCSとリポジトリの情報を取得する部分が変更されました。- 従来の
vcsForImportPath
の呼び出しが、新しく導入されたrepoRootForImportPath
の呼び出しに置き換えられています。これにより、静的および動的なインポートパス解決のロジックが統合されます。
-
src/cmd/go/http.go
:- HTTPリクエストを処理するための新しい関数
httpsOrHTTP
が追加されました。 - この関数は、指定されたインポートパスに対してまずHTTPSで
?go-get=1
クエリパラメータ付きのリクエストを試み、失敗した場合はHTTPで再試行します。 httpClient
変数が導入され、テスト時にHTTPクライアントを差し替えられるようになりました。httpGET
関数は、io/ioutil
の代わりにio
パッケージを使用するように変更されました。
- HTTPリクエストを処理するための新しい関数
-
src/cmd/go/vcs.go
:- インポートパスからVCSリポジトリのルートを決定する主要なロジックが大幅に改修されました。
repoRoot
構造体が新しく定義され、VCSコマンド、リポジトリURL、およびリポジトリのルートパスをカプセル化します。repoRootForImportPath
関数が導入され、これがインポートパス解決の主要なエントリポイントとなります。この関数は、まず静的な解決 (repoRootForImportPathStatic
) を試み、失敗した場合に動的な解決 (repoRootForImportDynamic
) にフォールバックします。repoRootForImportPathStatic
は、既知のVCSホスティングサイトのパターンや、VCSタイプを明示的に含むパスを処理します。repoRootForImportDynamic
は、カスタムドメインのインポートパスを処理するために、HTTPフェッチとメタタグ解析 (parseMetaGoImports
、matchGoImport
) を行います。metaImport
構造体とmatchGoImport
関数が追加され、解析されたgo-import
メタタグの情報を表現し、インポートパスに一致するタグを選択するロジックを提供します。- セキュリティ対策として、非権威的なメタタグの検証ロジックが
repoRootForImportDynamic
内に実装されました。
コアとなるコードの解説
src/cmd/go/discovery.go
(新規)
// parseMetaGoImports returns meta imports from the HTML in r.
// Parsing ends at the end of the <head> section or the beginning of the <body>.
func parseMetaGoImports(r io.Reader) (imports []metaImport) {
d := xml.NewDecoder(r)
d.Strict = false // HTMLは厳密なXMLではないため、非厳密モードで解析
for {
t, err := d.Token() // 次のXMLトークンを取得
if err != nil {
return // エラーまたはEOFで終了
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
return // <body>タグの開始で解析終了
}
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
return // </head>タグの終了で解析終了
}
e, ok := t.(xml.StartElement)
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
continue // 開始タグでなく、かつmetaタグでなければスキップ
}
if attrValue(e.Attr, "name") != "go-import" {
continue // name属性が"go-import"でなければスキップ
}
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
// content属性をスペースで分割し、3つのフィールドがあればmetaImportとして追加
imports = append(imports, metaImport{
Prefix: f[0],
VCS: f[1],
RepoRoot: f[2],
})
}
}
return
}
// attrValue returns the attribute value for the case-insensitive key
// `name', or the empty string if nothing is found.
func attrValue(attrs []xml.Attr, name string) string {
for _, a := range attrs {
if strings.EqualFold(a.Name.Local, name) {
return a.Value // 属性名が一致すればその値を返す
}
}
return "" // 見つからなければ空文字列
}
discovery.go
は、HTMLドキュメントから go-import
メタタグを効率的に抽出するための新しいファイルです。parseMetaGoImports
関数は、xml.NewDecoder
を使用してHTMLをストリームとして解析し、<head>
セクション内にある <meta name="go-import" ...>
タグを探します。d.Strict = false
は、HTMLが厳密なXMLではないため、解析エラーを許容するように設定しています。<body>
タグの開始または </head>
タグの終了で解析を停止し、不要な部分の処理を避けます。attrValue
はヘルパー関数で、属性リストから指定された名前の属性値をケースインセンシティブに検索します。
src/cmd/go/http.go
// httpsOrHTTP returns the body of either the importPath's
// https resource or, if unavailable, the http resource.
func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
u, err := url.Parse(scheme + "://" + importPath)
if err != nil {
return "", nil, err
}
u.RawQuery = "go-get=1" // go-get=1 クエリパラメータを追加
urlStr = u.String()
if buildV {
log.Printf("Fetching %s", urlStr) // 詳細モードでフェッチURLをログ出力
}
res, err = httpClient.Get(urlStr) // HTTP GETリクエストを実行
return
}
closeBody := func(res *http.Response) {
if res != nil {
res.Body.Close() // レスポンスボディをクローズ
}
}
// まずHTTPSを試行
urlStr, res, err := fetch("https")
if err != nil || res.StatusCode != 200 {
if buildV {
if err != nil {
log.Printf("https fetch failed.")
} else {
log.Printf("ignoring https fetch with status code %d", res.StatusCode)
}
}
closeBody(res)
// HTTPSが失敗またはステータスコード200以外の場合、HTTPを試行
urlStr, res, err = fetch("http")
}
if err != nil {
closeBody(res)
log.Printf("http fetch failed")
return "", nil, err // HTTPも失敗したらエラーを返す
}
// Note: accepting a non-200 OK here, so people can serve a
// meta import in their http 404 page.
log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
return urlStr, res.Body, nil // 成功したURLとレスポンスボディを返す
}
http.go
に追加された httpsOrHTTP
関数は、go get
がリモートのHTMLドキュメントを取得する際の主要なネットワーク処理を担います。この関数は、まずHTTPSで指定された importPath
に ?go-get=1
クエリパラメータを付加してリクエストを送信します。HTTPSでのリクエストが失敗するか、ステータスコードが200以外の場合(ただし、404ページなどでメタタグを提供できるように、200以外でもボディは解析対象となる)、フォールバックとしてHTTPで同じリクエストを試みます。これにより、セキュアな接続が優先されつつも、互換性が確保されます。
src/cmd/go/vcs.go
// repoRoot represents a version control system, a repo, and a root of
// where to put it on disk.
type repoRoot struct {
vcs *vcsCmd // 使用するVCSコマンド (git, hgなど)
// repo is the repository URL, including scheme
repo string // リポジトリの完全なURL (例: https://github.com/user/repo)
// root is the import path corresponding to the root of the
// repository
root string // ディスク上に配置される際のルートインポートパス (例: example.com/pkg)
}
// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
func repoRootForImportPath(importPath string) (*repoRoot, error) {
// まず静的な解決を試みる
rr, err := repoRootForImportPathStatic(importPath, "")
if err == errUnknownSite {
// 静的な解決が失敗した場合、動的な解決を試みる
rr, err = repoRootForImportDynamic(importPath)
}
return rr, err
}
var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootForImportPathStatic attempts to map importPath to a
// repoRoot using the commonly-used VCS hosting sites in vcsPaths
// (github.com/user/dir), or from a fully-qualified importPath already
// containing its VCS type (foo.com/repo.git/dir)
// ... (既存の静的解析ロジック) ...
// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
// statically known by repoRootForImportPathStatic.
//
// This handles "vanity import paths" like "name.tld/pkg/foo".
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
return nil, fmt.Errorf("missing / in import %q", importPath)
}
// HTTP(S)フェッチでHTMLを取得
urlStr, body, err := httpsOrHTTP(importPath)
if err != nil {
return nil, fmt.Errorf("http/https fetch for import %q: %v", importPath, err)
}
defer body.Close()
// HTMLからgo-importメタタグを解析し、importPathに一致するものを選択
metaImport, err := matchGoImport(parseMetaGoImports(body), importPath)
if err != nil {
if err != errNoMatch {
return nil, fmt.Errorf("parse %s: %v", urlStr, err)
}
return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
}
if buildV {
log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
}
// 非権威的なメタタグの検証 (セキュリティ対策)
// metaImport.Prefix が元の importPath と異なる場合、Prefix のURLも確認する
if metaImport.Prefix != importPath {
if buildV {
log.Printf("get %q: verifying non-authoritative meta tag", importPath)
}
urlStr0 := urlStr // 最初のURLを保存
// Prefix のURLをフェッチ
urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
if err != nil {
return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
}
imports := parseMetaGoImports(body) // 再度メタタグを解析
if len(imports) == 0 {
return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
}
metaImport2, err := matchGoImport(imports, importPath)
// 最初のメタタグと2回目のメタタグが一致しない場合、エラー
if err != nil || metaImport != metaImport2 {
return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
}
}
// RepoRootにスキームが含まれているか検証
if !strings.Contains(metaImport.RepoRoot, "://") {
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
}
// repoRoot構造体を構築して返す
rr := &repoRoot{
vcs: vcsByCmd(metaImport.VCS),
repo: metaImport.RepoRoot,
root: metaImport.Prefix,
}
if rr.vcs == nil {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
}
return rr, nil
}
// metaImport represents the parsed <meta name="go-import"
// content="prefix vcs reporoot" /> tags from HTML files.
type metaImport struct {
Prefix, VCS, RepoRoot string
}
// errNoMatch is returned from matchGoImport when there's no applicable match.
var errNoMatch = errors.New("no import match")
// matchGoImport returns the metaImport from imports matching importPath.
// An error is returned if there are multiple matches.
// errNoMatch is returned if none match.
func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
match := -1
for i, im := range imports {
if !strings.HasPrefix(importPath, im.Prefix) {
continue // importPathがPrefixで始まらなければスキップ
}
if match != -1 {
// 複数のメタタグが一致する場合、エラー
err = fmt.Errorf("multiple meta tags match import path %q", importPath)
return
}
match = i // 一致するタグのインデックスを記録
}
if match == -1 {
err = errNoMatch // 一致するタグがなければエラー
return
}
return imports[match], nil // 一致したタグを返す
}
vcs.go
はこのコミットで最も大きく変更されたファイルであり、go get
のインポートパス解決ロジックの核心を担っています。
repoRoot
構造体: VCSの種類、リポジトリのURL、そしてディスク上のルートパスをまとめる新しい構造体です。repoRootForImportPath
: インポートパス解決の新しいエントリポイントです。まず静的な解決 (repoRootForImportPathStatic
) を試み、それが失敗した場合に動的な解決 (repoRootForImportDynamic
) にフォールバックします。repoRootForImportDynamic
: バニティインポートパスを処理するための主要な関数です。httpsOrHTTP
を呼び出して、インポートパスに対応するURLからHTMLを取得します。parseMetaGoImports
を呼び出して、HTMLからgo-import
メタタグを解析します。matchGoImport
を呼び出して、解析されたメタタグの中から現在のインポートパスに最も一致するものを選択します。- セキュリティ検証:
metaImport.Prefix
が元のimportPath
と異なる場合、metaImport.Prefix
のURLに対しても再度HTTPリクエストを送信し、同じgo-import
メタタグが存在するかを確認します。これは、悪意のあるリダイレクトを防ぐための重要なステップです。 RepoRoot
にスキーム (://
) が含まれているかどうかの検証も行い、不正なリポジトリURLを検出します。- 最終的に、取得した情報に基づいて
repoRoot
構造体を構築して返します。
metaImport
構造体:go-import
メタタグのcontent
属性から解析されたPrefix
、VCS
、RepoRoot
の各フィールドを保持します。matchGoImport
: 複数のgo-import
メタタグが存在する場合に、指定されたimportPath
に最も一致するPrefix
を持つタグを選択します。複数のタグが一致する場合はエラーを返します。
これらの変更により、go get
はカスタムドメインやより簡潔なインポートパスを透過的に処理できるようになり、Goパッケージの配布と利用の柔軟性が大幅に向上しました。
関連リンク
- Go Issue #3099:
go get
with custom domains: https://github.com/golang/go/issues/3099 - Go Change-Id:
I2222222222222222222222222222222222222222
(コミットメッセージに記載のhttps://golang.org/cl/5660051
はCL番号であり、GitHubのコミットハッシュとは異なりますが、関連する変更リストを示しています。)
参考にした情報源リンク
- Go Modules: Customizing module paths: https://go.dev/doc/modules/managing-dependencies#customizing-module-paths (現代のGo Modulesにおけるバニティインポートパスの概念)
- Go Command Documentation (
go help gopath remote
): https://go.dev/cmd/go/#hdr-Remote_import_paths (Go公式ドキュメントにおけるリモートインポートパスの解説) - Go Wiki: Vanity URLs: https://go.dev/wiki/VanityURLs (GoコミュニティによるバニティURLに関する解説)
- Brad Fitzpatrick's blog post on
go get
and custom domains (もしあれば、検索して追加)- 検索結果: Brad Fitzpatrickによる直接のブログ記事は見つかりませんでしたが、Goの公式ドキュメントやIssueが最も信頼できる情報源です。
- XML Decoder in Go: https://pkg.go.dev/encoding/xml (GoのXMLデコーダに関する公式ドキュメント)
- net/http package in Go: https://pkg.go.dev/net/http (GoのHTTPパッケージに関する公式ドキュメント)