goimportsを高速化するdragon-importsコマンドをつくった
goimports
はコードのフォーマットに加えてインポート行の追加・削除を行ってくれる便利なコマンドですが、GOPATH配下に大量のリポジトリが存在するとインポートの解決に時間がかかるようになってしまいます。いつでも素早くインポートしたい!ということでdragon-importsというコマンドをつくってみました。
使い方
インストールしてdragon-imports
コマンドを実行するだけです。
$ go get github.com/monochromegane/dragon-imports/...
$ dragon-imports
コマンド実行後、goimports
コマンドが高速化されます。GOPATH/src
に230リポジトリある環境での実行時間の差は以下の通りです。
goimports の実行時間(秒)
before | after |
---|---|
0.893 | 0.019 |
体感では全く結果を待つ必要がなくなりました!
どうやって高速化するのか
goimportsの動作
goimports
は標準パッケージのシンボルとインポートパスのマッピングを内部に保持しているため、それらに対するインポートパスの解決は即座に行われます。
ここで解決できなかった場合は、GOPATH/src
配下に対する探査が発生してしまうため、GOPATH配下に大量にリポジトリがある場合は、時間がかかるようになります(複数回インポートパスを追加する場合でも探査自体は一度しかしないようです)。
dragon-importsはどう解決するか
dragon-imports
は既存のgoimports
コマンドを上書きします。
dragon-imports
はGOPATH/src
配下にあるエクスポートされた関数や型を上述のマッピングに追加して、時間のかかる探査自体を発生させないようにします。具体的には
-
GOROOT/api
配下の定義から標準パッケージのマッピングを取得
-
GOPATH/src
配下のパッケージからエクスポートされた関数や型のマッピングを生成
-
- 上記1.と2.をあわせて
goimports
のマッピング定義を上書き(zstdlib.go)
- 上記1.と2.をあわせて
-
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"
でもう少し速度向上を実感できるようにする