TR;DR
golang.org/x/tools
を 2018-10-13 以降のバージョン,具体的には 13ebad8
が含まれるバージョンまでアップデートしましょう.
発端
ある日,grapi で .go generate ./...` を実行したら突然死した.wire がすべて失敗しているようだった.
-: cannot find package "pattern=." in any of:
/usr/local/Cellar/go/1.11.1/libexec/src/pattern=. (from $GOROOT)
/Users/izumin/src/pattern=. (from $GOPATH)
wire: generate failed
cmd/grapi-gen-type/di/wire_gen.go:3: running "wire": exit status 1
pattern=.
とは
調査
当時の wire のバージョンは v0.2.0 を使っていた.
とりあえず pattern=
で grep する.
func load(ctx context.Context, wd string, env []string, patterns []string) ([]*packages.Package, []error) { cfg := &packages.Config{ Context: ctx, Mode: packages.LoadAllSyntax, Dir: wd, Env: env, BuildFlags: []string{"-tags=wireinject"}, // TODO(light): Use ParseFile to skip function bodies and comments in indirect packages. } escaped := make([]string, len(patterns)) for i := range patterns { escaped[i] = "pattern=" + patterns[i] } pkgs, err := packages.Load(cfg, escaped...) if err != nil { return nil, []error{err} }
internal/wire.load
はコード生成時の初っ端に呼ばれる関数.patterns
には引数 or .
が入っている.これの各要素に対して pattern=
という prefix をつけている.
packages
は golang.org/x/tools/go/packages
で, 静的解析まわりを使いやすくするためのラッパー.ここでもおもむろに "pattern"
とかで grep する.
// Extract file= and other [querytype]= patterns. Report an error if querytype // doesn't exist. extractQueries: for _, pattern := range patterns { eqidx := strings.Index(pattern, "=") if eqidx < 0 { restPatterns = append(restPatterns, pattern) } else { query, value := pattern[:eqidx], pattern[eqidx+len("="):] switch query { case "file": containFiles = append(containFiles, value) case "pattern": restPatterns = append(restPatterns, value) case "name": packagesNamed = append(packagesNamed, value) case "": // not a reserved query restPatterns = append(restPatterns, pattern) default: for _, rune := range query { if rune < 'a' || rune > 'z' { // not a reserved query restPatterns = append(restPatterns, pattern) continue extractQueries } } // Reject all other patterns containing "=" return nil, fmt.Errorf("invalid query type %q in query pattern %q", query, pattern) } } }
go/packages/golist.go#L55-L84 - github.com/golang/tools@3c39ce7
引数をパースしてる.おもむろに blame すると,10/13のコミット で追加されたことがわかる.
と,いうことで golang.org/x/tools
のバージョンを上げましょう.
余談
packages
は内部で go list
叩くんですね.
go list
の内部実装が internal
になってるのを export しないのはなんでなんだろう.
// golistDriverCurrent uses the "go list" command to expand the // pattern words and return metadata for the specified packages. // dir may be "" and env may be nil, as per os/exec.Command. func golistDriverCurrent(cfg *Config, words ...string) (*driverResponse, error) { // go list uses the following identifiers in ImportPath and Imports: // // "p" -- importable package or main (command) // "q.test" -- q's test executable // "p [q.test]" -- variant of p as built for q's test executable // "q_test [q.test]" -- q's external test package // // The packages p that are built differently for a test q.test // are q itself, plus any helpers used by the external test q_test, // typically including "testing" and all its dependencies. // Run "go list" for complete // information on the specified packages. buf, err := golist(cfg, golistargs(cfg, words)) if err != nil { return nil, err }
go/packages/golist.go#L185-L205@13ebad8 - github.com/golang/tools@13ebad8