diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBuiltins.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBuiltins.java index e84c93b2ed936e..f479a9c187b98b 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBuiltins.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBuiltins.java @@ -17,4 +17,8 @@ import com.google.devtools.build.lib.rules.python.PyBuiltins; /** PyBuiltins with Bazel-specific functionality. */ -public final class BazelPyBuiltins extends PyBuiltins {} +public final class BazelPyBuiltins extends PyBuiltins { + public BazelPyBuiltins() { + super(BazelPythonSemantics.GET_INIT_PY_FILES); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyBuiltins.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyBuiltins.java index 7e7105209af7da..39e8a8076ee58e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/python/PyBuiltins.java +++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyBuiltins.java @@ -58,6 +58,12 @@ public abstract class PyBuiltins implements StarlarkValue { public static final String NAME = "py_builtins"; + private final Runfiles.EmptyFilesSupplier emptyFilesSupplier; + + protected PyBuiltins(Runfiles.EmptyFilesSupplier emptyFilesSupplier) { + this.emptyFilesSupplier = emptyFilesSupplier; + } + @StarlarkMethod( name = "is_singleton_depset", doc = "Efficiently checks if the depset is a singleton.", @@ -259,6 +265,36 @@ public Object newEmptyRunfilesWithMiddleman( .build(); } + @StarlarkMethod( + name = "merge_runfiles_with_generated_inits_empty_files_supplier", + doc = + "Create a runfiles that generates missing __init__.py files using Java and " + + "the internal EmptyFilesProvider interface", + parameters = { + @Param(name = "ctx", positional = false, named = true, defaultValue = "unbound"), + @Param( + name = "runfiles", + positional = false, + named = true, + defaultValue = "unbound", + doc = "Runfiles to merge into the result; must be non-empty"), + }) + public Object mergeRunfilesWithGeneratedInitsEmptyFilesSupplier( + StarlarkRuleContext starlarkCtx, Runfiles runfiles) throws EvalException { + if (runfiles.isEmpty()) { + // The Runfiles merge functions have an optimization to detect an empty runfiles and return a + // singleton. Unfortunately, this optimization considers an empty runfiles with + // a emptyFilesSupplier as empty, so then drops it when returning the singleton. To work + // around this, require that there is *something* in the runfiles. + throw Starlark.errorf("input runfiles cannot be empty"); + } + return new Runfiles.Builder( + starlarkCtx.getWorkspaceName(), starlarkCtx.getConfiguration().legacyExternalRunfiles()) + .setEmptyFilesSupplier(emptyFilesSupplier) + .merge(runfiles) + .build(); + } + @StarlarkMethod( name = "declare_constant_metadata_file", doc = "Declare a file that always reports it is unchanged.",