diff --git a/rules.bzl b/rules.bzl index 03db4f5..741fec3 100644 --- a/rules.bzl +++ b/rules.bzl @@ -78,13 +78,48 @@ def _protoc_plugin_rule_implementation(context): ] _virtual_imports = "/_virtual_imports/" + + # Remove duplicate proto files, if the proto file location is the same + # it won't break the `protoc` invocation, however we might have a + # generated proto file (for example we have to generate proto files when + # we have a Pydantic API) and if we have a `proto_library` which + # depends on that proto, it will create a copy of the same proto file + # inside `_virtual_imports` and that will break the build. + seen = {} + unique_proto_files = [] + for proto_file in proto_files: + short_path = proto_file.short_path + if _virtual_imports in proto_file.path: + before, after = proto_file.path.split(_virtual_imports) + import_path = before + _virtual_imports + after.split("/")[0] + "/" + short_path = proto_file.path.replace(import_path, "") + + if short_path not in seen: + seen[short_path] = True + unique_proto_files.append(proto_file) + + proto_files = unique_proto_files + for proto_file in proto_files: if len(proto_file.owner.workspace_root) == 0: # Handle case where `proto_file` is a local file. - args += [ - "-I" + ".", + # This includes both source files in the workspace and files + # generated by custom Bazel rules. Generated files will be + # placed in the `bazel-out` directory, so we need to + # determine the import path correctly for that case. For + # files which are part of the workspace, the `import_path` + # will be empty and we will set it to `./`. + elements = proto_file.path.split("/") + import_path = proto_file.path[:-len(proto_file.short_path)] + + if import_path == "": + import_path = "./" + args.append( + "-I" + import_path, + ) + args.append( proto_file.short_path, - ] + ) elif proto_file.path.startswith("external"): # Handle case where `proto_file` is from an external # repository (i.e., from 'git_repository()' or