詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

go get gobin.cc/PROGNAME でプログラムをゲットできる URL shortener っぽいサイトを作った

夏休みの自由研究です。

ghr を go get したいんだけど作者の e の数って何個だったっけ……と悩んでいたらそもそも違う ID でした、けどそれも思い出せない! って経験ありませんか? たいていの場合、プログラム名だけは覚えていて、その正確なパスまでは覚えていないものです。

そこでその名前だけから欲しいプログラムを go get できる gobin.cc というサイトを作りました。一種の URL shortener サービスだと思ってもらえればよさそうです。

go get gobin.cc/gore

などとすると、github.com/motemen/gore と同じものが go get されます。おー、便利!

実装

プログラム名からその完全なパッケージパスを自動的に再現するのは難しいのもあり、対応しているプログラムは手動管理のファイルである SOURCES に記載されています。そういう観点では、一種の curated list であるとも言えます。

gobin.cc のソースリポジトリは https://github.com/motemen/gobin.cc です。go get gobin.cc/gorego get github.com/motemen/gobin.cc/gore をしたのと同じソースコードをダウンロードします。

gobin.cc サイト自体は Cloudflare + GitHub Pages で構成されていて、404.html にあとで触れるメタタグを埋め込むことでどのようなリクエストでも github.com を参照するように設定しています。

リポジトリ直下に main パッケージがある場合

github.com/motemen/gore など。

このような場合、GitHub のリポジトリ側で行っているのは、それぞれのプログラムを git submodule として追加することだけです。go get は submodule も含めて clone するので、このように外部リポジトリの内容を取り込むことができるのでした。そのぶん、初回の go get は重くなってしまいますが。

リポジトリのサブディレクトリ以下に main パッケージがある場合

github.com/golang/lint/golint など。

この場合はやや面倒です。Git に外部リポジトリのサブディレクトリを取り込む標準的な方法はないので、git read-tree などを使って gobin.cc のリポジトリに当該プログラムの main パッケージに相当するコードを直接コミットしてしまっています。依存パッケージは go get がダウンロードしてくれるので、main だけ考えておけばよいです。

この際、特別にリポジトリ直下の LICENSE ファイルもあわせてコミットしています。

どちらの場合も本体の更新に自動で追随はしないので、リポジトリを更新していく必要はあります(CI でできる予定)。

その他に検討した実装

go get は、VCS を利用してソースコードをダウンロードします。パッケージの示す先が github.com などの有名なホストでない場合、一旦 HTTP(S) でアクセスし、以下の形の meta タグから利用すべき VCS や URL を判別します(Remote import paths)。

<meta name="go-import" content="import-prefix vcs repo-root">

golang.org/x/ 以下のパッケージが有名ですね。gobin.cc 自体もこの仕組みを使っています。

最初は git submodule など使わずに、すべて go-import メタタグによる一種のリダイレクトのみで実現するつもりで、一見、以下のような方法でうまく行ったのですが、

<meta name="go-import" content="gobin.cc/gore git github.com/motemen/gore">

この仕組みはあくまでリポジトリのホストを go に指し示すもので、パッケージパスを指すものではなく、パッケージ直下にないプログラムへの対応を以下のように実現することはできません。

<!-- github.com/golang/lint/golint はリポジトリの URL ではないので意図通りに動かない -->
<meta name="go-import" content="gobin.cc/golint git github.com/golang/lint/golint">

なのでパッケージ直下にないプログラムの対応をするには結局自前のリポジトリを用意するほかなく、そうすると手元の GOPATH ではリポジトリがネスト(例えば $GOPATH/src/gobin.cc$GOPATH/src/gobin.cc/gore)してしまうことになり、取り回しが困難なので諦めました。

ライセンスについて

MIT、Apache、Go 本体のライセンス(BSD 3-clause)のソースコードにおいてはこの配布方法は問題ないという認識ですが、詳しい人の指摘はウェルカムです。

おわりに

PoC 的に gobin.cc という go-gettable な shoturl/curated サイトを作りました。

SOURCES にはさしあたり自分がよく使うものをリストしてますが、ほかに追加したらいいものがあったら教えてくださいね。

はてなで一緒に働きませんか?