THINKING MEGANE

goimportsを高速化するdragon-importsコマンドをつくった

goimportsはコードのフォーマットに加えてインポート行の追加・削除を行ってくれる便利なコマンドですが、GOPATH配下に大量のリポジトリが存在するとインポートの解決に時間がかかるようになってしまいます。いつでも素早くインポートしたい!ということでdragon-importsというコマンドをつくってみました。

使い方

インストールしてdragon-importsコマンドを実行するだけです。

$ go get github.com/monochromegane/dragon-imports/...
$ dragon-imports

コマンド実行後、goimportsコマンドが高速化されます。GOPATH/srcに230リポジトリある環境での実行時間の差は以下の通りです。


goimports の実行時間(秒)

beforeafter
0.8930.019

体感では全く結果を待つ必要がなくなりました!

どうやって高速化するのか

goimportsの動作

goimportsは標準パッケージのシンボルとインポートパスのマッピングを内部に保持しているため、それらに対するインポートパスの解決は即座に行われます。

ここで解決できなかった場合は、GOPATH/src配下に対する探査が発生してしまうため、GOPATH配下に大量にリポジトリがある場合は、時間がかかるようになります(複数回インポートパスを追加する場合でも探査自体は一度しかしないようです)。

dragon-importsはどう解決するか

dragon-importsは既存のgoimportsコマンドを上書きします。

dragon-importsGOPATH/src配下にあるエクスポートされた関数や型を上述のマッピングに追加して、時間のかかる探査自体を発生させないようにします。具体的には

  • 1. GOROOT/api配下の定義から標準パッケージのマッピングを取得
  • 2. GOPATH/src配下のパッケージからエクスポートされた関数や型のマッピングを生成
  • 3. 上記1.と2.をあわせてgoimportsのマッピング定義を上書き(zstdlib.go)
  • 4. goimportsを再度インストール(go install -a)

を行っています。


以上、GOPATH爆発問題をちょっと強気に解決するdragon-importsを紹介させていただきました。 現状使っている分には特に困っていないですが、やり方がやり方なだけにご利用は自己責任でお願いします。

それでも普段使うGOPATH配下のパッケージがストレスなくインポートされるのはやはり気持ちがよいですね。

やっぱりコワいんですけど

安心してください、戻せますよ。

$ cd $GOPATH/src/golang.org/x/tools
$ git checkout imports/zstdlib.go
$ cd $GOPATH/src/golang.org/x/tools/cmd/goimports
$ go install -a .

TODO

  • パッケージの変更を検知してdragon-importsをバックグラウンドで実行する仕組み
  • dragon-importsの対象から除外するオプション
  • vim-goのg:go_fmt_command = "goimports"でもう少し速度向上を実感できるようにする
このエントリーをはてなブックマークに追加