From c93e1f53a1a734c857619c7c51ecaffaa13af4f7 Mon Sep 17 00:00:00 2001 From: DolceTriade Date: Tue, 20 Feb 2024 17:06:19 -0800 Subject: [PATCH] python: Provide python rules via CrossResolve. (#316) This allows rules_python's gazelle plugin to find python rules generated by rules_proto allowing for a fully gazelle'ified experience working with protos with Python. --- pkg/plugin/grpc/grpc/BUILD.bazel | 5 +- pkg/rule/rules_python/py_library.go | 14 ++++++ pkg/rule/rules_python/py_library_test.go | 47 +++++++++++++++++++ rules/private/proto_repository_tools_srcs.bzl | 4 ++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/pkg/plugin/grpc/grpc/BUILD.bazel b/pkg/plugin/grpc/grpc/BUILD.bazel index 60696437..70f7b59d 100644 --- a/pkg/plugin/grpc/grpc/BUILD.bazel +++ b/pkg/plugin/grpc/grpc/BUILD.bazel @@ -14,7 +14,10 @@ go_library( go_test( name = "grpc_test", - srcs = ["protoc-gen-grpc-python_test.go"], + srcs = [ + "grpc_test.go", + "protoc-gen-grpc-python_test.go", + ], data = [ ":protoc", ":protoc-gen-grpc-python", diff --git a/pkg/rule/rules_python/py_library.go b/pkg/rule/rules_python/py_library.go index 106c3c27..f189258d 100644 --- a/pkg/rule/rules_python/py_library.go +++ b/pkg/rule/rules_python/py_library.go @@ -121,11 +121,25 @@ func (s *PyLibrary) Rule(otherGen ...*rule.Rule) *rule.Rule { return newRule } +func pyFilenameToImport(s string) string { + if strings.HasSuffix(s, ".py") { + return strings.ReplaceAll(s[:len(s)-3], "/", ".") + } + return s +} + // Imports implements part of the RuleProvider interface. func (s *PyLibrary) Imports(c *config.Config, r *rule.Rule, file *rule.File) []resolve.ImportSpec { if lib, ok := r.PrivateAttr(protoc.ProtoLibraryKey).(protoc.ProtoLibrary); ok { specs := protoc.ProtoLibraryImportSpecsForKind(r.Kind(), lib) specs = maybeStripImportPrefix(specs, lib.StripImportPrefix()) + from := label.New("", file.Pkg, r.Name()) + for _, o := range s.Outputs { + pyImp := pyFilenameToImport(o) + protoc.GlobalResolver().Provide("py", "py", pyImp, from) + specs = append(specs, resolve.ImportSpec{Lang: "py", Imp: pyImp}) + } + return specs } return nil diff --git a/pkg/rule/rules_python/py_library_test.go b/pkg/rule/rules_python/py_library_test.go index 155c161a..857d3ee5 100644 --- a/pkg/rule/rules_python/py_library_test.go +++ b/pkg/rule/rules_python/py_library_test.go @@ -1,10 +1,14 @@ package rules_python import ( + "fmt" + "path" "testing" "github.com/bazelbuild/bazel-gazelle/resolve" + "github.com/bazelbuild/bazel-gazelle/rule" "github.com/google/go-cmp/cmp" + "github.com/stackb/rules_proto/pkg/protoc" ) func TestMaybeStripImportPrefix(t *testing.T) { @@ -49,3 +53,46 @@ func TestMaybeStripImportPrefix(t *testing.T) { }) } } + +func TestImports(t *testing.T) { + kind := "mykind" + suffix := "_suffix" + pkg := "mypkg" + protoName := "test" + cases := []struct { + Name string + Outputs []string + WantImports []resolve.ImportSpec + }{{ + Name: "Empty", + // If for some reason, no python files were output... + Outputs: []string{}, + // Always include the output from the proto_library + WantImports: []resolve.ImportSpec{{Lang: kind, Imp: fmt.Sprintf("%s/%s", pkg, protoName)}}, + }, { + Name: "One output", + Outputs: []string{path.Join(pkg, "test_pb2.py")}, + WantImports: []resolve.ImportSpec{ + {Lang: kind, Imp: fmt.Sprintf("%s/%s", pkg, protoName)}, + {Lang: "py", Imp: fmt.Sprintf("%s.%s_pb2", pkg, protoName)}, + }, + }} + + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + py := &PyLibrary{ + KindName: kind, + RuleNameSuffix: suffix, + Outputs: c.Outputs, + Resolver: protoc.ResolveDepsAttr("deps", true), + } + protoLib := protoc.NewOtherProtoLibrary(&rule.File{}, rule.NewRule("proto_library", protoName+"_proto"), protoc.NewFile(pkg, protoName)) + r := rule.NewRule(kind, "test"+suffix) + r.SetPrivateAttr(protoc.ProtoLibraryKey, protoLib) + imps := py.Imports(nil, r, &rule.File{Pkg: pkg}) + if diff := cmp.Diff(imps, c.WantImports); diff != "" { + t.Fatalf("import mismatch: (-got, +want): %s", diff) + } + }) + } +} diff --git a/rules/private/proto_repository_tools_srcs.bzl b/rules/private/proto_repository_tools_srcs.bzl index 0908f047..94d34a14 100644 --- a/rules/private/proto_repository_tools_srcs.bzl +++ b/rules/private/proto_repository_tools_srcs.bzl @@ -66,6 +66,9 @@ PROTO_REPOSITORY_TOOLS_SRCS = [ "@build_stack_rules_proto//pkg/language/protobuf:resolve.go", "@build_stack_rules_proto//pkg/plugin/akka/akka_grpc:BUILD.bazel", "@build_stack_rules_proto//pkg/plugin/akka/akka_grpc:protoc_gen_akka_grpc.go", + "@build_stack_rules_proto//pkg/plugin/bufbuild:BUILD.bazel", + "@build_stack_rules_proto//pkg/plugin/bufbuild:connect_es_plugin.go", + "@build_stack_rules_proto//pkg/plugin/bufbuild:es_plugin.go", "@build_stack_rules_proto//pkg/plugin/builtin:BUILD.bazel", "@build_stack_rules_proto//pkg/plugin/builtin:cpp_plugin.go", "@build_stack_rules_proto//pkg/plugin/builtin:csharp_plugin.go", @@ -165,6 +168,7 @@ PROTO_REPOSITORY_TOOLS_SRCS = [ "@build_stack_rules_proto//pkg/rule/rules_scala:scala_proto_library.go", "@build_stack_rules_proto//plugin:BUILD.bazel", "@build_stack_rules_proto//plugin/akka/akka-grpc:BUILD.bazel", + "@build_stack_rules_proto//plugin/bufbuild:BUILD.bazel", "@build_stack_rules_proto//plugin/builtin:BUILD.bazel", "@build_stack_rules_proto//plugin/gogo/protobuf:BUILD.bazel", "@build_stack_rules_proto//plugin/golang/protobuf:BUILD.bazel",