オレオレgoimportsを作ってみた
やりたいこと、作ったもの
goimports
最高
goimports
はGoのCLIツールで、*.go
ファイルに対して↓を実行してくれます。
-
import
していない外部パッケージをimport
してくれる - 使っていない
import
は削除してくれる - 最後に
gofmt
もかけてくれる
goimports
は変な空行を入れてくる
でもgithub.com/golang/go/issues/20818 のIssueにある通り、goimports
は変な空行を入れてきます。
こうなっている理由は単に「仕様が決まっていないから」で、Issueでも5年以上(2022年8月現在)議論され続けています。
goimports
を作った
空行を最低限にするこういう状況ならオレオレgoimports
を自作するしかないだろうと思って作ってみました。
どれだけ空行を入れていようが順番をバラバラにしていようが、問答無用で空行の数を最低限にしちゃいます。
つまり標準パッケージとそれ以外の間に空行を1つだけ入れます(本家と同じく-local
オプションを使えばプロジェクト内のパッケージの前にも空行を入れることができます)。
import
ブロック内にBasic comment(// hoge
)やBlock comment(/* hoge */
)を書いていた場合も問答無用で削除しちゃいます。
Trailing Inline comment(import "fuga" // hoge
)はBlank importしている意図などをコメントで示すユースケースを考え、保持するようにしました。
作り方
今回作ったgosimports
は本家のgoimports
のコードを改変する形で実装しました。
goimportsの処理は大きく分けると3つ
1. importするパッケージを整理する
*.go
ファイルの中身を見て使用しているパッケージを静的解析しています。
本家のソースコードでいうと このあたり ですね。
今回の自作ツールではここはまったく改変していません。
2. グループごとに空行を入れる(gosimportsはここを変えた)
gofmt
はimport
ブロック内の空行で区切られたパッケージ群をそれぞれAlphabetical orderにソートします。
なので本家goimports
は出来るだけキレイにするために(?)、標準パッケージとそれ以外の間に空行を入れる処理をgofmt
の前段に行っています。
ソースコードでいうと このあたり ですね。
3. gofmtを実行する
最後にgofmt
をかけて終了です。
2番の処理を改変した
今回自作したほうのgosimports
では、↑の2番の処理を改変しています。
ソースコードでいうと このあたり です。
本家の方にあったaddImportSpaces
関数をseparateImportsIntoGroups
関数に変更しています。
import
のグループ分け(標準パッケージとそれ以外とか)はすでに本家のほうに 分類機能 が実装されていたのでそれを使いまわしました。
余談
派生OSSはオリジナルのライセンスを保持する
Goのツール群は多分だいたいBSDライセンスというライセンスのもとでOSSとして公開されていて、goimports
もそうです。
BSDライセンスで公開されているプロジェクトは、ライセンスをそのまま保持しつつオリジナル著者の名前をプロモーションとかで使ったりすることをしなければ、自由にソースを改変・再配布してもオーケーです。
今回作ったgosimports
でもオリジナルのライセンスをそのまま保持しています。 OSS最高。
コード生成などにgofmtは特に便利
今回作ったgosimports
はコード生成をしている部分がかなり適当に作っています。
タブ文字がなかったり無駄な空行とかが入りまくったりしています。
でもその後段で実行しているgofmt
がすべてをキレイにしてくれるので、実装するのがとても楽でした。
普段からgofmt
にはお世話になっていますが、コード生成とかを実装するときには特に便利だなと思いました。
Renovateとrelease-drafterがとても便利
gosimports
が依存しているパッケージはgolang.org/x/mod
とgolang.org/x/tools
だけですが、golang.org/x/tools
はgitのタグが切られておらずリリースは最新のコミットハッシュが更新されるだけです。
Renovate はタグのリリースだけではなくコミットハッシュの更新にも対応しているので、ちゃんと最新に追従することができます。
あと、masterブランチにPRがマージされるたびにリリースノートに追記してくれる release-drafter もとても便利でした。
gosimportsという命名は割と気に入っている
gosimports = simpler + goimports
です。
結構気に入っています。
Discussion