Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hard code dependency resolution bindings for @go_googleapis and WKTs #251

Merged
merged 1 commit into from
Jul 3, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Hard code dependency resolution bindings for @go_googleapis and WKTs
* proto.csv is a table that lists Well Known .proto files and all
  .proto files in @go_googleapis. For each proto import string, it
  lists the proto_library label, the Go import path, and the
  go_proto_library label. This was generated using an ad hoc Python
  script (not included).
* Maps are generated from this file and incorporated into the
  dependency resolution logic in the proto and go extensions.

When #12 is implemented, we can index rules in external repositories,
and we won't need this. We need it for now because there's no clear
correspondence between proto and Go import strings and the libraries
that should be included.

Related bazel-contrib/rules_go#1548
Jay Conrod committed Jul 3, 2018
commit 17301f18516a7223c62bd1da726c35aeb0a99fd6
12 changes: 0 additions & 12 deletions internal/config/constants.go
Original file line number Diff line number Diff line change
@@ -39,18 +39,6 @@ const (
// "compilers" attribute of go_proto_library rules.
GrpcCompilerLabel = "@io_bazel_rules_go//proto:go_grpc"

// WellKnownTypesProtoRepo is the repository containing proto_library rules
// for the Well Known Types.
WellKnownTypesProtoRepo = "com_google_protobuf"
// WellKnownTypeProtoPrefix is the proto import path prefix for the
// Well Known Types.
WellKnownTypesProtoPrefix = "google/protobuf"
// WellKnownTypesGoPrefix is the import path for the Go repository containing
// pre-generated code for the Well Known Types.
WellKnownTypesGoPrefix = "github.com/golang/protobuf"
// WellKnownTypesPkg is the package name for the predefined WKTs in rules_go.
WellKnownTypesPkg = "proto/wkt"

// GazelleImportsKey is an internal attribute that lists imported packages
// on generated rules. It is replaced with "deps" during import resolution.
GazelleImportsKey = "_gazelle_imports"
18 changes: 18 additions & 0 deletions internal/language/go/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -15,6 +15,22 @@ genrule(
tools = ["//internal/language/go/gen_std_package_list"],
)

genrule(
name = "known_proto_imports",
srcs = ["//internal/language/proto:proto.csv"],
outs = ["known_proto_imports.go"],
cmd = "$(location //internal/language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package golang -var knownProtoImports -key 0 -value 3",
tools = ["//internal/language/proto/gen:gen_known_imports"],
)

genrule(
name = "known_go_imports",
srcs = ["//internal/language/proto:proto.csv"],
outs = ["known_go_imports.go"],
cmd = "$(location //internal/language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package golang -var knownGoProtoImports -key 2 -value 3",
tools = ["//internal/language/proto/gen:gen_known_imports"],
)

go_library(
name = "go_default_library",
srcs = [
@@ -24,6 +40,8 @@ go_library(
"fix.go",
"generate.go",
"kinds.go",
"known_go_imports.go",
"known_proto_imports.go",
"lang.go",
"package.go",
"resolve.go",
136 changes: 136 additions & 0 deletions internal/language/go/known_go_imports.go

Large diffs are not rendered by default.

300 changes: 300 additions & 0 deletions internal/language/go/known_proto_imports.go

Large diffs are not rendered by default.

87 changes: 25 additions & 62 deletions internal/language/go/resolve.go
Original file line number Diff line number Diff line change
@@ -113,7 +113,7 @@ func resolveGo(gc *goConfig, ix *resolve.RuleIndex, rc *repos.RemoteCache, r *ru
return label.NoLabel, skipImportError
}

if l := resolveWellKnownGo(imp); !l.Equal(label.NoLabel) {
if l, ok := knownGoProtoImports[imp]; ok {
return l, nil
}

@@ -140,42 +140,6 @@ func isStandard(imp string) bool {
return stdPackages[imp]
}

func resolveWellKnownGo(imp string) label.Label {
// keep in sync with @io_bazel_rules_go//proto/wkt:well_known_types.bzl
// TODO(jayconrod): in well_known_types.bzl, write the import paths and
// targets in a public dict. Import it here, and use it to generate this code.
switch imp {
case "github.com/golang/protobuf/ptypes/any",
"github.com/golang/protobuf/ptypes/api",
"github.com/golang/protobuf/protoc-gen-go/descriptor",
"github.com/golang/protobuf/ptypes/duration",
"github.com/golang/protobuf/ptypes/empty",
"google.golang.org/genproto/protobuf/field_mask",
"google.golang.org/genproto/protobuf/source_context",
"github.com/golang/protobuf/ptypes/struct",
"github.com/golang/protobuf/ptypes/timestamp",
"github.com/golang/protobuf/ptypes/wrappers":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: path.Base(imp) + "_go_proto",
}
case "github.com/golang/protobuf/protoc-gen-go/plugin":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: "compiler_plugin_go_proto",
}
case "google.golang.org/genproto/protobuf/ptype":
return label.Label{
Repo: config.RulesGoRepoName,
Pkg: config.WellKnownTypesPkg,
Name: "type_go_proto",
}
}
return label.NoLabel
}

func resolveWithIndexGo(ix *resolve.RuleIndex, imp string, from label.Label) (label.Label, error) {
matches := ix.FindRulesByImport(resolve.ImportSpec{Lang: "go", Imp: imp}, "go")
var bestMatch resolve.FindResult
@@ -248,13 +212,16 @@ func resolveVendored(rc *repos.RemoteCache, imp string) (label.Label, error) {
}

func resolveProto(gc *goConfig, ix *resolve.RuleIndex, rc *repos.RemoteCache, r *rule.Rule, imp string, from label.Label) (label.Label, error) {
if !strings.HasSuffix(imp, ".proto") {
return label.NoLabel, fmt.Errorf("can't import non-proto: %q", imp)
if wellKnownProtos[imp] {
return label.NoLabel, skipImportError
}
stem := imp[:len(imp)-len(".proto")]

if isWellKnownProto(stem) {
return label.NoLabel, skipImportError
if l, ok := knownProtoImports[imp]; ok {
if l.Equal(from) {
return label.NoLabel, skipImportError
} else {
return l, nil
}
}

if l, err := resolveWithIndexProto(ix, imp, from); err == nil || err == skipImportError {
@@ -282,22 +249,18 @@ func resolveProto(gc *goConfig, ix *resolve.RuleIndex, rc *repos.RemoteCache, r
// TODO(jayconrod): generate from
// @io_bazel_rules_go//proto/wkt:WELL_KNOWN_TYPE_PACKAGES
var wellKnownProtos = map[string]bool{
"google/protobuf/any": true,
"google/protobuf/api": true,
"google/protobuf/compiler_plugin": true,
"google/protobuf/descriptor": true,
"google/protobuf/duration": true,
"google/protobuf/empty": true,
"google/protobuf/field_mask": true,
"google/protobuf/source_context": true,
"google/protobuf/struct": true,
"google/protobuf/timestamp": true,
"google/protobuf/type": true,
"google/protobuf/wrappers": true,
}

func isWellKnownProto(stem string) bool {
return wellKnownProtos[stem]
"google/protobuf/any.proto": true,
"google/protobuf/api.proto": true,
"google/protobuf/compiler_plugin.proto": true,
"google/protobuf/descriptor.proto": true,
"google/protobuf/duration.proto": true,
"google/protobuf/empty.proto": true,
"google/protobuf/field_mask.proto": true,
"google/protobuf/source_context.proto": true,
"google/protobuf/struct.proto": true,
"google/protobuf/timestamp.proto": true,
"google/protobuf/type.proto": true,
"google/protobuf/wrappers.proto": true,
}

func resolveWithIndexProto(ix *resolve.RuleIndex, imp string, from label.Label) (label.Label, error) {
@@ -308,10 +271,10 @@ func resolveWithIndexProto(ix *resolve.RuleIndex, imp string, from label.Label)
if len(matches) > 1 {
return label.NoLabel, fmt.Errorf("multiple rules (%s and %s) may be imported with %q from %s", matches[0].Label, matches[1].Label, imp, from)
}
// If some go_library embeds the go_proto_library we found, use that instead.
importpath := matches[0].Rule.AttrString("importpath")
if l, err := resolveWithIndexGo(ix, importpath, from); err == nil {
return l, nil
// TODO(#247): this check is not sufficient. We should check whether the
// match embeds this library (possibly transitively).
if from.Equal(matches[0].Label) {
return label.NoLabel, skipImportError
}
return matches[0].Label, nil
}
53 changes: 51 additions & 2 deletions internal/language/go/resolve_test.go
Original file line number Diff line number Diff line change
@@ -568,14 +568,17 @@ go_proto_library(
"google/protobuf/timestamp.proto",
"google/protobuf/type.proto",
"google/protobuf/wrappers.proto",
"google/api/http.proto",
"google/rpc/status.proto",
"google/type/latlng.proto",
],
)

go_library(
name = "wkts_go_lib",
_imports = [
"github.com/golang/protobuf/ptypes/any",
"github.com/golang/protobuf/ptypes/api",
"google.golang.org/genproto/protobuf/api",
"github.com/golang/protobuf/protoc-gen-go/descriptor",
"github.com/golang/protobuf/ptypes/duration",
"github.com/golang/protobuf/ptypes/empty",
@@ -586,15 +589,28 @@ go_library(
"github.com/golang/protobuf/ptypes/wrappers",
"github.com/golang/protobuf/protoc-gen-go/plugin",
"google.golang.org/genproto/protobuf/ptype",
"google.golang.org/genproto/googleapis/api/annotations",
"google.golang.org/genproto/googleapis/rpc/status",
"google.golang.org/genproto/googleapis/type/latlng",
],
)
`},
want: `
go_proto_library(name = "wkts_go_proto")
go_proto_library(
name = "wkts_go_proto",
deps = [
"@go_googleapis//google/api:annotations_go_proto",
"@go_googleapis//google/rpc:status_go_proto",
"@go_googleapis//google/type:latlng_go_proto",
],
)

go_library(
name = "wkts_go_lib",
deps = [
"@go_googleapis//google/api:annotations_go_proto",
"@go_googleapis//google/rpc:status_go_proto",
"@go_googleapis//google/type:latlng_go_proto",
"@io_bazel_rules_go//proto/wkt:any_go_proto",
"@io_bazel_rules_go//proto/wkt:api_go_proto",
"@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto",
@@ -609,6 +625,39 @@ go_library(
"@io_bazel_rules_go//proto/wkt:wrappers_go_proto",
],
)
`,
}, {
desc: "proto_self_import",
old: buildFile{content: `
proto_library(
name = "foo_proto",
srcs = [
"a.proto",
"b.proto",
],
)

go_proto_library(
name = "foo_go_proto",
importpath = "foo",
proto = ":foo_proto",
_imports = ["a.proto"],
)
`},
want: `
proto_library(
name = "foo_proto",
srcs = [
"a.proto",
"b.proto",
],
)

go_proto_library(
name = "foo_go_proto",
importpath = "foo",
proto = ":foo_proto",
)
`,
},
} {
12 changes: 11 additions & 1 deletion internal/language/proto/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -2,6 +2,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

# gazelle:exclude testdata

genrule(
name = "known_imports",
srcs = ["proto.csv"],
outs = ["known_imports.go"],
cmd = "$(location //internal/language/proto/gen:gen_known_imports) -proto_csv $< -known_imports $@ -package proto -var knownImports -key 0 -value 1",
tools = ["//internal/language/proto/gen:gen_known_imports"],
)

go_library(
name = "go_default_library",
srcs = [
@@ -11,6 +19,7 @@ go_library(
"fix.go",
"generate.go",
"kinds.go",
"known_imports.go",
"lang.go",
"package.go",
"resolve.go",
@@ -21,7 +30,6 @@ go_library(
"//internal/config:go_default_library",
"//internal/label:go_default_library",
"//internal/language:go_default_library",
"//internal/pathtools:go_default_library",
"//internal/repos:go_default_library",
"//internal/resolve:go_default_library",
"//internal/rule:go_default_library",
@@ -48,3 +56,5 @@ go_test(
"//vendor/github.com/bazelbuild/buildtools/build:go_default_library",
],
)

exports_files(["proto.csv"])
15 changes: 15 additions & 0 deletions internal/language/proto/gen/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
name = "go_default_library",
srcs = ["gen_known_imports.go"],
importpath = "github.com/bazelbuild/bazel-gazelle/internal/language/proto/gen",
visibility = ["//visibility:private"],
deps = ["//internal/label:go_default_library"],
)

go_binary(
name = "gen_known_imports",
embed = [":go_default_library"],
visibility = ["//:__subpackages__"],
)
Loading