| """ | |
| Internal helpers for building the Python protobuf runtime. | |
| """ | |
| load("@rules_python//python:py_test.bzl", "py_test") | |
| # Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_common.bzl#L47 | |
| InternalOsInfo = provider( | |
| doc = "Information about the target platform's OS.", | |
| fields = ["is_windows"], | |
| ) | |
| # Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_common.bzl#L52 | |
| internal_is_windows = rule( | |
| implementation = lambda ctx: InternalOsInfo( | |
| is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]), | |
| ), | |
| attrs = { | |
| "_windows_constraint": attr.label(default = "@platforms//os:windows"), | |
| }, | |
| ) | |
| def _remove_cross_repo_path(path): | |
| components = path.split("/") | |
| if components[0] == "..": | |
| return "/".join(components[2:]) | |
| return path | |
| def _internal_copy_files_impl(ctx): | |
| strip_prefix = ctx.attr.strip_prefix | |
| if strip_prefix[-1] != "/": | |
| strip_prefix += "/" | |
| src_dests = [] | |
| for src in ctx.files.srcs: | |
| short_path = _remove_cross_repo_path(src.short_path) | |
| if short_path[:len(strip_prefix)] != strip_prefix: | |
| fail("Source does not start with %s: %s" % | |
| (strip_prefix, short_path)) | |
| dest = ctx.actions.declare_file(short_path[len(strip_prefix):]) | |
| src_dests.append([src, dest]) | |
| # Windows check adapted from | |
| # https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_file_private.bzl#L71C10-L71C54 | |
| if ctx.attr._exec_is_windows[InternalOsInfo].is_windows: | |
| bat_file = ctx.actions.declare_file(ctx.label.name + "_copy.bat") | |
| ctx.actions.write( | |
| output = bat_file, | |
| content = "\r\n".join([ | |
| '@copy /Y "{}" "{}" >NUL'.format( | |
| src.path.replace("/", "\\"), | |
| dest.path.replace("/", "\\"), | |
| ) | |
| for src, dest in src_dests | |
| ]) + "\r\n", | |
| ) | |
| ctx.actions.run( | |
| inputs = ctx.files.srcs, | |
| tools = [bat_file], | |
| outputs = [dest for src, dest in src_dests], | |
| executable = "cmd.exe", | |
| arguments = ["/C", bat_file.path.replace("/", "\\")], | |
| mnemonic = "InternalCopyFile", | |
| progress_message = "Copying files", | |
| use_default_shell_env = True, | |
| toolchain = None, | |
| ) | |
| else: | |
| sh_file = ctx.actions.declare_file(ctx.label.name + "_copy.sh") | |
| ctx.actions.write( | |
| output = sh_file, | |
| content = "\n".join([ | |
| 'cp -f "{}" "{}"'.format(src.path, dest.path) | |
| for src, dest in src_dests | |
| ]), | |
| ) | |
| ctx.actions.run( | |
| inputs = ctx.files.srcs, | |
| tools = [sh_file], | |
| outputs = [dest for src, dest in src_dests], | |
| executable = "bash", | |
| arguments = [sh_file.path], | |
| mnemonic = "InternalCopyFile", | |
| progress_message = "Copying files", | |
| use_default_shell_env = True, | |
| toolchain = None, | |
| ) | |
| return [ | |
| DefaultInfo(files = depset([dest for src, dest in src_dests])), | |
| ] | |
| internal_copy_files_impl = rule( | |
| doc = """ | |
| Implementation for internal_copy_files macro. | |
| This rule implements file copying, including a compatibility mode for Windows. | |
| """, | |
| implementation = _internal_copy_files_impl, | |
| attrs = { | |
| "srcs": attr.label_list(allow_files = True, providers = [DefaultInfo]), | |
| "strip_prefix": attr.string(), | |
| # Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_file_private.bzl#L91C1-L96C7 | |
| "_exec_is_windows": attr.label( | |
| default = ":is_windows", | |
| # The exec transition must match the exec group of the actions, which in | |
| # this case is the default exec group. | |
| cfg = "exec", | |
| ), | |
| }, | |
| ) | |
| def internal_copy_files(name, srcs, strip_prefix, **kwargs): | |
| """Copies common proto files to the python tree. | |
| In order for Python imports to work, generated proto interfaces under | |
| the google.protobuf package need to be in the same directory as other | |
| source files. This rule copies the .proto files themselves, e.g. with | |
| strip_prefix = 'src', 'src/google/protobuf/blah.proto' could be copied | |
| to '<package>/google/protobuf/blah.proto'. | |
| (An alternative might be to implement a separate rule to generate | |
| Python code in a different location for the sources. However, this | |
| would be strange behavior that doesn't match any other language's proto | |
| library generation.) | |
| Args: | |
| name: the name for the rule. | |
| srcs: the sources. | |
| strip_prefix: the prefix to remove from each of the paths in 'srcs'. The | |
| remainder will be used to construct the output path. | |
| **kwargs: common rule arguments. | |
| """ | |
| internal_copy_files_impl( | |
| name = name, | |
| srcs = srcs, | |
| strip_prefix = strip_prefix, | |
| **kwargs | |
| ) | |
| def internal_py_test(deps = [], **kwargs): | |
| """Internal wrapper for shared test configuration | |
| Args: | |
| deps: any additional dependencies of the test. | |
| **kwargs: arguments forwarded to py_test. | |
| """ | |
| py_test( | |
| imports = ["."], | |
| deps = deps + [ | |
| "//python:python_test_lib", | |
| "@com_google_absl_py//absl/testing:parameterized", | |
| ], | |
| target_compatible_with = select({ | |
| "@system_python//:supported": [], | |
| "//conditions:default": ["@platforms//:incompatible"], | |
| }), | |
| **kwargs | |
| ) |