From 4374be38e9a75ff5957c3922adb155d32086fe14 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 23 Oct 2017 10:52:14 -0400 Subject: [PATCH] Gazelle: fix import resolution for vendored WKT protos (#945) * When resolving proto_library dependencies, a vendor/ prefix will no longer be added in any case. These rules can't build because the protoc import paths are not modified (and can't be right now). * go_proto_library dependencies for Well Known Types will be resolved to something in //vendor/github.com/golang/protobuf. This will change in the future when we have better support for alternative proto toolchains. * There is now a special case for google/protobuf/descriptor.proto. Fixes #888 Related #940 --- go/tools/gazelle/resolve/resolve.go | 46 ++++++++++++----- go/tools/gazelle/resolve/resolve_test.go | 66 ++++++++++++++---------- 2 files changed, 72 insertions(+), 40 deletions(-) diff --git a/go/tools/gazelle/resolve/resolve.go b/go/tools/gazelle/resolve/resolve.go index bf41ea5d25..0e78929a1b 100644 --- a/go/tools/gazelle/resolve/resolve.go +++ b/go/tools/gazelle/resolve/resolve.go @@ -18,6 +18,7 @@ package resolve import ( "fmt" "go/build" + "log" "path" "strings" @@ -85,6 +86,7 @@ func (r *Resolver) ResolveGo(imp, pkgRel string) (Label, error) { const ( wellKnownPrefix = "google/protobuf/" wellKnownGoProtoPkg = "ptypes" + descriptorPkg = "protoc-gen-go/descriptor" ) // ResolveProto resolves an import statement in a .proto file to a label @@ -101,14 +103,6 @@ func (r *Resolver) ResolveProto(imp, pkgRel string) (Label, error) { return Label{Repo: config.WellKnownTypesProtoRepo, Name: name}, nil } - // Temporary hack: guess the label based on the proto file name. We assume - // all proto files in a directory belong to the same package, and the - // package name matches the directory base name. We also assume that protos - // in the vendor directory must refer to something else in vendor. - // TODO(#859): use dependency table to resolve once it exists. - if pkgRel == "vendor" || strings.HasPrefix(pkgRel, "vendor/") { - imp = path.Join("vendor", imp) - } rel := path.Dir(imp) if rel == "." { rel = "" @@ -127,12 +121,38 @@ func (r *Resolver) ResolveGoProto(imp, pkgRel string) (Label, error) { if isWellKnown(imp) { // Well Known Type - pkg := path.Join(wellKnownGoProtoPkg, path.Base(imp)) - label := r.l.LibraryLabel(pkg) - if r.c.GoPrefix != config.WellKnownTypesGoPrefix { - label.Repo = config.WellKnownTypesGoProtoRepo + base := path.Base(imp) + if base == "descriptor" { + switch r.c.DepMode { + case config.ExternalMode: + label := r.l.LibraryLabel(descriptorPkg) + if r.c.GoPrefix != config.WellKnownTypesGoPrefix { + label.Repo = config.WellKnownTypesGoProtoRepo + } + return label, nil + case config.VendorMode: + pkg := path.Join("vendor", config.WellKnownTypesGoPrefix, descriptorPkg) + label := r.l.LibraryLabel(pkg) + return label, nil + default: + log.Panicf("unknown external mode: %v", r.c.DepMode) + } + } + + switch r.c.DepMode { + case config.ExternalMode: + pkg := path.Join(wellKnownGoProtoPkg, base) + label := r.l.LibraryLabel(pkg) + if r.c.GoPrefix != config.WellKnownTypesGoPrefix { + label.Repo = config.WellKnownTypesGoProtoRepo + } + return label, nil + case config.VendorMode: + pkg := path.Join("vendor", config.WellKnownTypesGoPrefix, wellKnownGoProtoPkg, base) + return r.l.LibraryLabel(pkg), nil + default: + log.Panicf("unknown external mode: %v", r.c.DepMode) } - return label, nil } // Temporary hack: guess the label based on the proto file name. We assume diff --git a/go/tools/gazelle/resolve/resolve_test.go b/go/tools/gazelle/resolve/resolve_test.go index e3705bb8bf..c327e3575c 100644 --- a/go/tools/gazelle/resolve/resolve_test.go +++ b/go/tools/gazelle/resolve/resolve_test.go @@ -147,7 +147,8 @@ func TestResolveProto(t *testing.T) { prefix := "example.com/repo" for _, tc := range []struct { desc, imp, pkgRel string - mode config.StructureMode + structureMode config.StructureMode + depMode config.DependencyMode wantProto, wantGoProto Label }{ { @@ -162,50 +163,61 @@ func TestResolveProto(t *testing.T) { wantGoProto: Label{Pkg: "foo/bar", Name: config.DefaultLibName}, }, { desc: "vendor", + depMode: config.VendorMode, imp: "foo/bar/bar.proto", pkgRel: "vendor", - wantProto: Label{Pkg: "vendor/foo/bar", Name: "bar_proto"}, + wantProto: Label{Pkg: "foo/bar", Name: "bar_proto"}, wantGoProto: Label{Pkg: "vendor/foo/bar", Name: config.DefaultLibName}, }, { - desc: "vendor sub", - imp: "foo/bar/bar.proto", - pkgRel: "vendor/baz", - wantProto: Label{Pkg: "vendor/foo/bar", Name: "bar_proto"}, - wantGoProto: Label{Pkg: "vendor/foo/bar", Name: config.DefaultLibName}, + desc: "flat sub", + structureMode: config.FlatMode, + imp: "foo/bar/bar.proto", + wantProto: Label{Name: "foo/bar/bar_proto"}, + wantGoProto: Label{Name: "foo/bar"}, }, { - desc: "flat sub", - mode: config.FlatMode, - imp: "foo/bar/bar.proto", - wantProto: Label{Name: "foo/bar/bar_proto"}, - wantGoProto: Label{Name: "foo/bar"}, - }, { - desc: "flat vendor", - mode: config.FlatMode, - imp: "foo/bar/bar.proto", - pkgRel: "vendor", - wantProto: Label{Name: "vendor/foo/bar/bar_proto"}, - wantGoProto: Label{Name: "vendor/foo/bar"}, + desc: "flat vendor", + structureMode: config.FlatMode, + depMode: config.VendorMode, + imp: "foo/bar/bar.proto", + pkgRel: "vendor", + wantProto: Label{Name: "foo/bar/bar_proto"}, + wantGoProto: Label{Name: "vendor/foo/bar"}, }, { desc: "well known", imp: "google/protobuf/any.proto", wantProto: Label{Repo: "com_google_protobuf", Name: "any_proto"}, wantGoProto: Label{Repo: "com_github_golang_protobuf", Pkg: "ptypes/any", Name: config.DefaultLibName}, }, { - desc: "well known flat", - mode: config.FlatMode, - imp: "google/protobuf/any.proto", - wantProto: Label{Repo: "com_google_protobuf", Name: "any_proto"}, - wantGoProto: Label{Repo: "com_github_golang_protobuf", Name: "ptypes/any"}, + desc: "well known flat", + structureMode: config.FlatMode, + imp: "google/protobuf/any.proto", + wantProto: Label{Repo: "com_google_protobuf", Name: "any_proto"}, + wantGoProto: Label{Repo: "com_github_golang_protobuf", Name: "ptypes/any"}, }, { desc: "well known vendor", + depMode: config.VendorMode, imp: "google/protobuf/any.proto", - pkgRel: "vendor", wantProto: Label{Repo: "com_google_protobuf", Name: "any_proto"}, - wantGoProto: Label{Repo: "com_github_golang_protobuf", Pkg: "ptypes/any", Name: config.DefaultLibName}, + wantGoProto: Label{Pkg: "vendor/github.com/golang/protobuf/ptypes/any", Name: config.DefaultLibName}, + }, { + desc: "descriptor", + imp: "google/protobuf/descriptor.proto", + wantProto: Label{Repo: "com_google_protobuf", Name: "descriptor_proto"}, + wantGoProto: Label{Repo: "com_github_golang_protobuf", Pkg: "protoc-gen-go/descriptor", Name: config.DefaultLibName}, + }, { + desc: "descriptor vendor", + depMode: config.VendorMode, + imp: "google/protobuf/descriptor.proto", + wantProto: Label{Repo: "com_google_protobuf", Name: "descriptor_proto"}, + wantGoProto: Label{Pkg: "vendor/github.com/golang/protobuf/protoc-gen-go/descriptor", Name: config.DefaultLibName}, }, } { t.Run(tc.desc, func(t *testing.T) { - c := &config.Config{GoPrefix: prefix, StructureMode: tc.mode} + c := &config.Config{ + GoPrefix: prefix, + DepMode: tc.depMode, + StructureMode: tc.structureMode, + } l := NewLabeler(c) r := NewResolver(c, l)