🧰

skeletonにgo.modを作らないモードを作った

2022/05/23に公開

skeletonとは?

skeletonはGoで静的解析ツールをサクッと作るためのスケルトンコードジェネレータです。詳しくはskeletonで始めるGoの静的解析を御覧ください。

次のようにインストールできます。

$ go install github.com/gostaticanalysis/skeleton/v2@latest

実行すると次のようなディレクトリを作ってくれます。

$ skeleton github.com/tenntenn/findId
$ tree findId
findId
├── cmd
│   └── findId
│       └── main.go
├── findId.go
├── findId_test.go
├── go.mod
└── testdata
    └── src
        └── a
            ├── a.go
            └── go.mod

5 directories, 6 files

ほとんどの雛形を作ってくれるので後は作りたい静的解析ツールにアルゴリズムに集中できます。生成されるコードや静的解析自体について知りたい場合はプログラミング言語Go完全入門の14章 静的解析とコード生成をご覧ください。

go.modが不要な場合

skeletonは作者も便利に使っているのですが、たまに不便だなと思う点がありました。その1つがすでにモジュールで管理されているコードベース以下でskeletonを使う場合です。

これまでのskeleton(v2)では、自動でgo.modファイルを生成していました。それ自体は非常に便利ですが、不要な場合もあります。例えば、zganeのような静的解析器をまとめたようなツールです。zaganeについてはこちらのブログをご参照ください。

そこでv2.2.0ではgomodフラグを導入し、trueの場合のみgo.modファイルを生成できるようにしました。たとえば、次のように実行するとカレントディレクトリの所属しているモジュールの情報を使ってスケルトンコードを生成してくれます。

$ cat go.mod
module example.com/example

go 1.18
$ skeleton -gomod=false mylinter
$ tree .
.
├── go.mod
└── mylinter
    ├── cmd
    │   └── mylinter
    │       └── main.go
    ├── mylinter.go
    ├── mylinter_test.go
    └── testdata
        └── src
            └── a
                ├── a.go
                └── go.mod

6 directories, 6 files

パッケージのインポートパスもモジュールパスからexample.com/example/mylinterのように自動で補足してくれます。そのため、テストコードは次のようになります。ちゃんとモジュールパスが付加されてインポートしていることがわかります。

package mylinter_test

import (
	"testing"

	"example.com/example/mylinter"
	"github.com/gostaticanalysis/testutil"
	"golang.org/x/tools/go/analysis/analysistest"
)

// TestAnalyzer is a test for Analyzer.
func TestAnalyzer(t *testing.T) {
	testdata := testutil.WithModules(t, analysistest.TestData(), nil)
	analysistest.Run(t, testdata, mylinter.Analyzer, "a")
}

ちなみに、Go Moduleで管理されていないディレクトリ以下ではgomodフラグはfalseにできません。

$ skeleton -gomod=false mylinter
Error: cannot find go.mod, . may not managed with Go Modules

少し便利になったskeletonをぜひ使ってみてください!GitHubスターもポチッとお願いします。

Discussion