Skip to content

Commit

Permalink
Hard code dependency resolution bindings for @go_googleapis and WKTs
Browse files Browse the repository at this point in the history
* 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 bazel-contrib#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
  • Loading branch information
Jay Conrod committed Jul 2, 2018
1 parent 91e6a1e commit 002a239
Show file tree
Hide file tree
Showing 31 changed files with 1,304 additions and 172 deletions.
12 changes: 0 additions & 12 deletions internal/config/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
18 changes: 18 additions & 0 deletions internal/language/go/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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",
Expand Down
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.

83 changes: 25 additions & 58 deletions internal/language/go/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
Expand Down Expand Up @@ -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 isWellKnownProto(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 {
Expand Down Expand Up @@ -282,18 +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,
"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 isWellKnownProto(stem string) bool {
Expand All @@ -308,10 +275,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
}
Expand Down
53 changes: 51 additions & 2 deletions internal/language/go/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
)
`,
},
} {
Expand Down
12 changes: 11 additions & 1 deletion internal/language/proto/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -11,6 +19,7 @@ go_library(
"fix.go",
"generate.go",
"kinds.go",
"known_imports.go",
"lang.go",
"package.go",
"resolve.go",
Expand All @@ -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",
Expand All @@ -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

0 comments on commit 002a239

Please sign in to comment.