Plan 9とGo言語のブログ

主にPlan 9やGo言語の日々気づいたことを書きます。

パッケージのimport pathを好みのURLにする

この記事はQiitaで公開されていました

Goのパッケージ名は、リポジトリのURLをそのまま使うことが多いと思いますが、リポジトリはそのままで、別のURLをパッケージ名にすることもできます。

例えば、あるパッケージのリポジトリGitHubに置いていて、リポジトリのURLは github.com/lufia/ken_all だとします。 (現在、上記URLは存在しません)

通常は、

import (
    "github.com/lufia/ken_all"
)

のようにパッケージをimportします。

ですが、

  • ホスティング先が変わってもパッケージパスを変えたくない
  • 名前に '_' が含まれていて気に入らない

などの場合に、go-import というmeta要素を含むHTMLを作成して、HTMLが置かれたURLを、パッケージ名として使うことができます。今後、ホスティングGitHubから他のサービスへ移すことがあったとしても、パッケージをimportしているコードは変更する必要がありませんし、階層で付加情報を表現することもできます。

代わりに、HTMLを置いたURLは変えない努力が必要です。

go-importの書き方

go-import という名前の付いたmeta要素は、空白で区切った3つのパラメータが、以下の順番で必要です。

  1. パッケージ名(import path)プリフィックス
  2. VCS
  3. リポジトリルートURL

簡単なところから、VCS名はバージョン管理ツール名です。hg, git, svn, bzr からひとつ選びます。

リポジトリルートURLはそのまま、リポジトリのURLです。パッケージ名ではないため、https://等から始まっていなければなりません。パッケージ名プリフィックスは、パッケージ名のうち、リポジトリルートURLまでに該当する部分となります。

ひとつ例を紹介します。

github.com/lufia/ken_all というパッケージ名をexample.com/japanese/postal からアクセスできるようにしたい、と仮定します。

VCS名はホスティングGitHubなので git ですね。リポジトリルートURLはパッケージ名からわかるように、https://github.com/lufia/ken_all.git です。

このリポジトリには、

など、いくつかパッケージが含まれているかもしれませんが、パッケージ名プリフィックスは、リポジトリルートURLまでに該当する部分となります。この例で言えば example.com/japanese/postal まで、です。

完成したmeta要素は以下の通り。

<meta name="go-import" 
      content="example.com/japanese/postal git https://github.com/lufia/ken_all.git">

これを含むHTMLを、パッケージ名から参照できるURLに置いておけば、example.com/japanese/postalパッケージとして参照ができるようになります。最終的にHTMLへ到達できれば、リダイレクトしても構いません。また、httpsが推奨されていますが、httpでも動作します。

正式なURLのみ許可する

上記のmeta要素を含むHTMLを使うことで、1つのパッケージに対して、複数のパッケージ名でアクセスされる可能性が出てきます。上記の例で言えば、

の2つが、パッケージ名として有効です。この動作が困る場合、package 宣言のどこか1か所に// import "canonical import path" というマジックコメントを入れておくことで、コメントのパッケージ名以外でimportした場合はビルドエラーにできます。

package postal // import "example.com/japanese/postal"

上記の場合、import "github.com/lufia/ken_all"でimportしているコードはエラーとなるためビルドできません。

go-sourceの書き方

go-import の他に、go-source という名前のmeta要素もあります。go-source は、存在しなくてもビルドに影響はありません。 この要素は、以下の順番にパラメータを要求します。

  1. パッケージ名プリフィックス
  2. リポジトリのホームページ
  3. ディレクトリパスのテンプレート
  4. ファイルパスのテンプレート

パッケージ名プリフィックスgo-import と同じです。リポジトリのホームページも名前の通り、ブラウザで表示可能なリポジトリのTOPをあらわすURLを記述します。

ディレクトリパスのテンプレートは、ディレクトリに含まれるファイルを表示するためのURLを定義します。テンプレートには {dir} または {/dir} を含むことができ、これらはパッケージ名プリフィックスから後のパスに置換されます。{dir}{/dir} の違いは、前者は先頭の'/'を含みません。後者は含みます。

プリフィックスexample.com/japanese/postal の場合

パッケージ名 {dir} {/dir}
example.com/japanese/postal (空) (空)
example.com/japanese/postal/cmd cmd /cmd

同様に、ファイルパスのテンプレートはソースファイルの内容を表示するためのURLを定義します。このテンプレートには {dir}, {/dir} の他に、{file}, {line} も含めることができます。それぞれ、{file} はファイル名に、{line} はファイル中の行番号に置換されます。

完成したmeta要素は以下の通り。

<meta name="go-source"
      content="example.com/japanese/postal
               https://github.com/lufia/ken_all
               https://github.com/lufia/ken_all/tree/master{/dir}
               https://github.com/lufia/ken_all/tree/master{/dir}/{file}#L{line}">

ディレクトリURLとファイルURLのテンプレートはホスティングサービスによって異なるため、お使いのサービスを確認してください。

まとめ

すべて含めると、以下のようになります。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="go-import" content="example.com/japanese/postal git https://github.com/lufia/ken_all.git">
<meta name="go-source" content="example.com/japanese/postal https://github.com/lufia/ken_all https://github.com/lufia/ken_all/tree/master{/dir} https://github.com/lufia/ken_all/tree/master{/dir}/{file}#L{line}">
<meta http-equiv="refresh" content="0; url=https://godoc.org/example.com/japanese/postal">
</head>

<body>
</body>

</html>