diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java index 43f72fc5966686..1327cdab47dbcb 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java @@ -14,13 +14,10 @@ package com.google.devtools.build.lib.bazel.rules.python; -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses.PyBinaryBaseRule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.rules.python.PyRuleClasses; @@ -41,15 +38,6 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) return builder .requiresConfigurationFragments(PythonConfiguration.class, BazelPythonConfiguration.class) .cfg(PyRuleClasses.VERSION_TRANSITION) - .add( - attr("$zipper", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .exec() - .value(env.getToolsLabel("//tools/zip:zipper"))) - .add( - attr("$launcher", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .value(env.getToolsLabel("//tools/launcher:launcher"))) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java index 3282c86bbe6f50..c238f4eb85389e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java @@ -17,7 +17,6 @@ import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL; import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL; import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; import static com.google.devtools.build.lib.packages.Type.STRING; import static com.google.devtools.build.lib.packages.Type.STRING_LIST; @@ -36,7 +35,6 @@ import com.google.devtools.build.lib.rules.python.PyCommon; import com.google.devtools.build.lib.rules.python.PyInfo; import com.google.devtools.build.lib.rules.python.PyRuleClasses; -import com.google.devtools.build.lib.rules.python.PyRuntimeInfo; import com.google.devtools.build.lib.rules.python.PythonVersion; /** @@ -215,18 +213,6 @@ responsible for creating (possibly empty) __init__.py files and adding them to t
Stamped binaries are not rebuilt unless their dependencies change.
*/ .add(attr("stamp", TRISTATE).value(TriState.AUTO)) - // TODO(brandjon): Consider adding to py_interpreter a .mandatoryBuiltinProviders() of - // PyRuntimeInfoProvider. (Add a test case to PythonConfigurationTest for violations of - // this requirement.) Probably moot now that this is going to be replaced by toolchains. - .add(attr(":py_interpreter", LABEL).value(PY_INTERPRETER)) - .add( - attr("$py_toolchain_type", NODEP_LABEL) - .value(env.getToolsLabel("//tools/python:toolchain_type"))) - /* Only used when no py_runtime() is available. See #7901 - */ - .add( - attr("$default_bootstrap_template", LABEL) - .value(env.getToolsLabel(PyRuntimeInfo.DEFAULT_BOOTSTRAP_TEMPLATE))) .addToolchainTypes( ToolchainTypeRequirement.builder(env.getToolsLabel("//tools/python:toolchain_type")) .mandatory(true) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java index 6075ece52fb33f..d2df05df645cda 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyTestRule.java @@ -15,14 +15,12 @@ package com.google.devtools.build.lib.bazel.rules.python; import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; import static com.google.devtools.build.lib.packages.Type.BOOLEAN; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses.PyBinaryBaseRule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; @@ -39,11 +37,6 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) return builder .requiresConfigurationFragments(PythonConfiguration.class, BazelPythonConfiguration.class) .cfg(PyRuleClasses.VERSION_TRANSITION) - .add( - attr("$zipper", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .exec() - .value(env.getToolsLabel("//tools/zip:zipper"))) .override( attr("testonly", BOOLEAN) .value(true) @@ -53,21 +46,6 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) that the stamp argument is set to 0 by default for tests. */ .override(attr("stamp", TRISTATE).value(TriState.NO)) - .add( - attr("$launcher", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .value(env.getToolsLabel("//tools/launcher:launcher"))) - .add( - attr(":lcov_merger", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .value(BaseRuleClasses.getCoverageOutputGeneratorLabel())) - // Add the script as an attribute in order for py_test to output code coverage results for - // code covered by CC binaries invocations. - .add( - attr("$collect_cc_coverage", LABEL) - .cfg(ExecutionTransitionFactory.create()) - .singleArtifact() - .value(env.getToolsLabel("//tools/test:collect_cc_coverage"))) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java index 56391e6cc4010b..f62111d45d82c1 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java @@ -14,48 +14,22 @@ package com.google.devtools.build.lib.bazel.rules.python; -import static java.nio.charset.StandardCharsets.ISO_8859_1; -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.CommandLineItem; -import com.google.devtools.build.lib.actions.ParamFileInfo; -import com.google.devtools.build.lib.actions.ParameterFile; -import com.google.devtools.build.lib.analysis.AnalysisUtils; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesSupport; -import com.google.devtools.build.lib.analysis.ShToolchain; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.LauncherFileWriteAction; -import com.google.devtools.build.lib.analysis.actions.LauncherFileWriteAction.LaunchInfo; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.analysis.actions.Substitution; -import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; -import com.google.devtools.build.lib.cmdline.LabelConstants; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.rules.cpp.CcInfo; -import com.google.devtools.build.lib.rules.python.PyCcLinkParamsProvider; import com.google.devtools.build.lib.rules.python.PyCommon; -import com.google.devtools.build.lib.rules.python.PyRuntimeInfo; -import com.google.devtools.build.lib.rules.python.PythonConfiguration; import com.google.devtools.build.lib.rules.python.PythonSemantics; import com.google.devtools.build.lib.rules.python.PythonUtils; -import com.google.devtools.build.lib.rules.python.PythonVersion; -import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.PathFragment; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Predicate; -import javax.annotation.Nullable; /** Functionality specific to the Python rules in Bazel. */ public class BazelPythonSemantics implements PythonSemantics { @@ -63,8 +37,6 @@ public class BazelPythonSemantics implements PythonSemantics { public static final Runfiles.EmptyFilesSupplier GET_INIT_PY_FILES = new PythonUtils.GetInitPyFiles((PredicateCan only be called for an executable Python rule. - * - *
Returns {@code null} if there's a problem retrieving the runtime.
- */
- @Nullable
- private static PyRuntimeInfo getRuntime(RuleContext ruleContext, PyCommon common) {
- return common.shouldGetRuntimeFromToolchain()
- ? common.getRuntimeFromToolchain()
- : ruleContext.getPrerequisite(":py_interpreter", PyRuntimeInfo.PROVIDER);
- }
-
- private static Artifact getBootstrapTemplate(RuleContext ruleContext, PyCommon common) {
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null) {
- Artifact bootstrapTemplate = provider.getBootstrapTemplate();
- if (bootstrapTemplate != null) {
- return bootstrapTemplate;
- }
- }
- return ruleContext.getPrerequisiteArtifact("$default_bootstrap_template");
- }
-
- private static void addRuntime(
- RuleContext ruleContext, PyCommon common, Runfiles.Builder builder) {
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null && provider.isInBuild()) {
- builder.addArtifact(provider.getInterpreter());
- // WARNING: we are adding the all Python runtime files here,
- // and it would fail if the filenames of them contain spaces.
- // Currently, we need to exclude them in py_runtime rules.
- // Possible files in Python runtime which contain spaces in filenames:
- // - https://github.com/pypa/setuptools/blob/master/setuptools/script%20(dev).tmpl
- // - https://github.com/pypa/setuptools/blob/master/setuptools/command/launcher%20manifest.xml
- builder.addTransitiveArtifacts(provider.getFiles());
- }
- }
-
- private static String getPythonBinary(
- RuleContext ruleContext, PyCommon common, BazelPythonConfiguration bazelConfig) {
- String pythonBinary;
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null) {
- // make use of py_runtime defined by --python_top
- if (!provider.isInBuild()) {
- // absolute Python path in py_runtime
- pythonBinary = provider.getInterpreterPath().getPathString();
- } else {
- // checked in Python interpreter in py_runtime
- PathFragment workspaceName =
- PathFragment.create(ruleContext.getRule().getPackage().getWorkspaceName());
- pythonBinary =
- workspaceName.getRelative(provider.getInterpreter().getRunfilesPath()).getPathString();
- }
- } else {
- // make use of the Python interpreter in an absolute path
- pythonBinary = bazelConfig.getPythonPath();
- }
-
- return pythonBinary;
- }
-
- private static void addCoverageSupport(
- RuleContext ruleContext, PyCommon common, Runfiles.Builder builder) {
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null && provider.getCoverageTool() != null) {
- builder.addArtifact(provider.getCoverageTool());
- builder.addTransitiveArtifacts(provider.getCoverageToolFiles());
- }
- }
-
- @Nullable
- private static String getCoverageTool(RuleContext ruleContext, PyCommon common) {
- if (!ruleContext.getConfiguration().isCodeCoverageEnabled()) {
- return null;
- }
- String coverageTool = null;
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null && provider.getCoverageTool() != null) {
- PathFragment workspaceName =
- PathFragment.create(ruleContext.getRule().getPackage().getWorkspaceName());
- coverageTool =
- workspaceName.getRelative(provider.getCoverageTool().getRunfilesPath()).getPathString();
- }
- return coverageTool;
- }
-
- private static String getStubShebang(RuleContext ruleContext, PyCommon common) {
- PyRuntimeInfo provider = getRuntime(ruleContext, common);
- if (provider != null) {
- return provider.getStubShebang();
- } else {
- return PyRuntimeInfo.DEFAULT_STUB_SHEBANG;
- }
+ throw new UnsupportedOperationException("Should not be called");
}
@Override
public CcInfo buildCcInfoProvider(
RuleContext ruleContext, Iterable extends TransitiveInfoCollection> deps) {
- ImmutableList This is always either {@code PY2} or {@code PY3}.
- */
- private final PythonVersion version;
-
- /**
- * The level of compatibility with Python major versions, as per the {@code srcs_version}
- * attribute.
- */
- private final PythonVersion sourcesVersion;
-
- /**
- * The Python sources belonging to this target's transitive {@code deps}, not including this
- * target's own {@code srcs}.
- */
- private final NestedSet This is computed slightly differently than the difference between {@link
- * #dependencyTransitivePythonSources} and {@link transitivePythonSources}; it includes the
- * filesToBuild rather than the prerequisite artifacts.
- */
- // TODO(bazel-team): Can this be simplified to instead just be (transitivePythonSources -
- // dependencyTransitivePythonSources)?
- private final List This is non-null only if
- *
- * If a target has the PyInfo provider, the value from that provider is used. Otherwise, we
- * fall back on collecting .py source files from the target's filesToBuild.
- */
- // TODO(bazel-team): Eliminate the fallback behavior by returning an appropriate py provider from
- // the relevant rules.
- private static void collectTransitivePythonSourcesFromDeps(
- RuleContext ruleContext, NestedSetBuilder For targets with the py provider, we consult the {@code uses_shared_libraries} field. For
- * targets without this provider, we look for {@link CppFileTypes#SHARED_LIBRARY}-type files in
- * the filesToBuild.
- */
- private static boolean initUsesSharedLibraries(RuleContext ruleContext) {
- Iterable extends TransitiveInfoCollection> targets;
- // The deps attribute must exist for all rule types that use PyCommon, but not necessarily the
- // data attribute.
- if (ruleContext.attributes().has("data")) {
- targets =
- Iterables.concat(
- ruleContext.getPrerequisites("deps"), ruleContext.getPrerequisites("data"));
- } else {
- targets = ruleContext.getPrerequisites("deps");
- }
- for (TransitiveInfoCollection target : targets) {
- if (target.get(PyInfo.PROVIDER) != null) {
- if (target.get(PyInfo.PROVIDER).getUsesSharedLibraries()) {
- return true;
- }
- } else if (FileType.contains(
- target.getProvider(FileProvider.class).getFilesToBuild().toList(),
- CppFileTypes.SHARED_LIBRARY)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the transitive import paths of a target.
- *
- * For targets with the PyInfo provider, the value from that provider is used. Otherwise, we
- * default to an empty set.
- */
- private static NestedSet If the field holds {@code None}, null is returned instead.
- *
- * If the field does not exist on the given {@code ToolchainInfo}, or is not a {@code
- * PyRuntimeInfo} and not {@code None}, an error is reported on the {@code ruleContext} and null
- * is returned.
- *
- * If the {@code PyRuntimeInfo} does not have {@code expectedVersion} as its Python version, an
- * error is reported on the {@code ruleContext} (but the provider is still returned).
- */
- @Nullable
- private static PyRuntimeInfo parseRuntimeField(
- RuleContext ruleContext,
- PythonVersion expectedVersion,
- ToolchainInfo toolchainInfo,
- String field) {
- Object fieldValue;
- try {
- fieldValue = toolchainInfo.getValue(field);
- } catch (EvalException e) {
- ruleContext.ruleError(
- String.format(
- "Error parsing the Python toolchain's ToolchainInfo: Could not retrieve field "
- + "'%s': %s",
- field, e.getMessage()));
- return null;
- }
- if (fieldValue == null) {
- ruleContext.ruleError(
- String.format(
- "Error parsing the Python toolchain's ToolchainInfo: field '%s' is missing", field));
- return null;
- }
- if (fieldValue == NONE) {
- return null;
- }
- if (!(fieldValue instanceof PyRuntimeInfo)) {
- ruleContext.ruleError(
- String.format(
- "Error parsing the Python toolchain's ToolchainInfo: Expected a PyRuntimeInfo in "
- + "field '%s', but got '%s'",
- field, Starlark.type(fieldValue)));
- return null;
- }
- PyRuntimeInfo pyRuntimeInfo = (PyRuntimeInfo) fieldValue;
- if (pyRuntimeInfo.getPythonVersion() != expectedVersion) {
- ruleContext.ruleError(
- String.format(
- "Error retrieving the Python runtime from the toolchain: Expected field '%s' to have "
- + "a runtime with python_version = '%s', but got python_version = '%s'",
- field, expectedVersion.name(), pyRuntimeInfo.getPythonVersion().name()));
- }
- return pyRuntimeInfo;
- }
-
- /**
- * Returns a {@link PyRuntimeInfo} representing the runtime to use for this target, as retrieved
- * from the resolved Python toolchain.
- *
- * If the configuration says to use the legacy mechanism for obtaining the runtime rather than
- * the toolchain mechanism, OR if this target's rule class does not define the
- * "$py_toolchain_type" attribute, then null is returned. In this case no attempt is made to
- * retrieve any toolchain information, and no errors are reported.
- *
- * Otherwise, the toolchain provider structure is retrieved and validated, and any errors are
- * reported on the rule context. If we're unable to determine the runtime due to an error, or if
- * the toolchain does not specify a runtime for the version of Python we need, null is returned.
- *
- * @throws IllegalArgumentException if the rule class defines the "$py_toolchain_type" attribute
- * but does not declare a requirement on the toolchain type
- */
- @Nullable
- private static PyRuntimeInfo initRuntimeFromToolchain(
- RuleContext ruleContext, PythonVersion version) {
- if (!shouldGetRuntimeFromToolchain(ruleContext)
- || !ruleContext.attributes().has("$py_toolchain_type", BuildType.NODEP_LABEL)) {
- return null;
- }
- Label toolchainType = ruleContext.attributes().get("$py_toolchain_type", BuildType.NODEP_LABEL);
- ToolchainInfo toolchainInfo = ruleContext.getToolchainInfo(toolchainType);
- Preconditions.checkArgument(
- toolchainInfo != null,
- "Could not retrieve a Python toolchain for '%s' rule",
- ruleContext.getRule().getRuleClass());
-
- PyRuntimeInfo py2RuntimeInfo =
- parseRuntimeField(ruleContext, PythonVersion.PY2, toolchainInfo, "py2_runtime");
- PyRuntimeInfo py3RuntimeInfo =
- parseRuntimeField(ruleContext, PythonVersion.PY3, toolchainInfo, "py3_runtime");
- Preconditions.checkState(version == PythonVersion.PY2 || version == PythonVersion.PY3);
- PyRuntimeInfo result = version == PythonVersion.PY2 ? py2RuntimeInfo : py3RuntimeInfo;
- if (result == null) {
- ruleContext.ruleError(
- String.format(
- "The Python toolchain does not provide a runtime for Python version %s",
- version.name()));
- }
-
- // Hack around the fact that the autodetecting Python toolchain, which is automatically
- // registered, does not yet support windows. In this case, we want to return null so that
- // BazelPythonSemantics falls back on --python_path. See toolchain.bzl.
- // TODO(#7844): Remove this hack when the autodetecting toolchain has a windows implementation.
- if (py2RuntimeInfo != null
- && py2RuntimeInfo.getInterpreterPathString() != null
- && py2RuntimeInfo
- .getInterpreterPathString()
- .equals("/_magic_pyruntime_sentinel_do_not_use")) {
- return null;
- }
-
- return result;
- }
-
- /**
- * Reports an attribute error if {@code python_version} cannot be parsed as {@code PY2}, {@code
- * PY3}, or the sentinel value.
- *
- * This *should* be enforced by rule attribute validation ({@link
- * Attribute.Builder.allowedValues}), but this check is here to fail-fast just in case.
- */
- private void validatePythonVersionAttr() {
- AttributeMap attrs = ruleContext.attributes();
- if (!attrs.has(PYTHON_VERSION_ATTRIBUTE, Type.STRING)) {
- return;
- }
- String attrValue = attrs.get(PYTHON_VERSION_ATTRIBUTE, Type.STRING);
- try {
- PythonVersion.parseTargetOrSentinelValue(attrValue);
- } catch (IllegalArgumentException ex) {
- ruleContext.attributeError(
- PYTHON_VERSION_ATTRIBUTE,
- String.format("'%s' is not a valid value. Expected either 'PY2' or 'PY3'", attrValue));
- }
- }
-
- /**
- * If the Python version (as determined by the configuration) is inconsistent with {@link
- * #hasPy2OnlySources} or {@link #hasPy3OnlySources}, emits a {@link FailAction} that "generates"
- * the executable.
- *
- * We use a {@code FailAction} rather than a rule error because we want to defer the error
- * until the execution phase. This way, we still get a configured target that the user can query
- * over with an aspect to find the exact transitive dependency that introduced the offending
- * version constraint. (See {@code This may only be called for executable Python rules (rules defining the attribute
- * "$py_toolchain_type", i.e. {@code py_binary} and {@code py_test}). In addition, it may not be
- * called if {@link #shouldGetRuntimeFromToolchain()} returns false.
- *
- * If there was a problem retrieving the runtime information from the toolchain, null is
- * returned. An error would have already been reported on the rule context at {@code PyCommon}
- * initialization time.
- */
- @Nullable
- public PyRuntimeInfo getRuntimeFromToolchain() {
- Preconditions.checkArgument(
- ruleContext.attributes().has("$py_toolchain_type", BuildType.NODEP_LABEL),
- "Cannot retrieve Python toolchain information for '%s' rule",
- ruleContext.getRule().getRuleClass());
- Preconditions.checkArgument(
- shouldGetRuntimeFromToolchain(),
- "Access to the Python toolchain is disabled by --incompatible_use_python_toolchains=false");
-
- return runtimeFromToolchain;
- }
-
- public void initBinary(List This is a public method because some rules just want a PyInfo provider without the other
- * things py_library needs.
- */
- public void addPyInfoProvider(RuleConfiguredTargetBuilder builder) {
- builder.addNativeDeclaredProvider(
- PyInfo.builder()
- .setTransitiveSources(transitivePythonSources)
- .setUsesSharedLibraries(usesSharedLibraries)
- .setImports(imports)
- .setHasPy2OnlySources(hasPy2OnlySources)
- .setHasPy3OnlySources(hasPy3OnlySources)
- .build());
- }
-
- public void addCommonTransitiveInfoProviders(RuleConfiguredTargetBuilder builder) {
- addPyInfoProvider(builder);
-
- // Add PyRuntimeInfo if this is an executable rule.
- if (runtimeFromToolchain != null) {
- builder.addNativeDeclaredProvider(runtimeFromToolchain);
- }
-
- builder
- .addNativeDeclaredProvider(
- InstrumentedFilesCollector.collect(ruleContext, INSTRUMENTATION_SPEC))
- // Python targets are not really compilable. The best we can do is make sure that all
- // generated source files are ready.
- .addOutputGroup(OutputGroupInfo.FILES_TO_COMPILE, transitivePythonSources)
- .addOutputGroup(OutputGroupInfo.COMPILATION_PREREQUISITES, transitivePythonSources);
- }
-
- /** Returns a list of the source artifacts */
- public List If there is a transitive sources version conflict, may produce a {@link FailAction} to
- * trigger an execution-time failure. See {@link
- * #maybeCreateFailActionDueToTransitiveSourcesVersion}.
- */
- public void createExecutable(CcInfo ccInfo, Runfiles.Builder defaultRunfilesBuilder)
- throws InterruptedException, RuleErrorException {
- boolean failed = maybeCreateFailActionDueToTransitiveSourcesVersion();
- if (!failed) {
- semantics.createExecutable(ruleContext, this, ccInfo, defaultRunfilesBuilder);
- }
- }
-
- private static String buildMultipleMainMatchesErrorText(
- boolean explicit, String proposedMainName, String match1, String match2) {
- String errorText;
- if (explicit) {
- errorText =
- String.format(
- "file name '%s' specified by 'main' attribute matches multiple files: e.g., '%s' and"
- + " '%s'",
- proposedMainName, match1, match2);
- } else {
- errorText =
- String.format(
- "default main file name '%s' matches multiple files. Perhaps specify an explicit"
- + " file with 'main' attribute? Matches were: '%s' and '%s'",
- proposedMainName, match1, match2);
- }
- return errorText;
- }
-
- private static String buildNoMainMatchesErrorText(boolean explicit, String proposedMainName) {
- String errorText;
- if (explicit) {
- errorText = "could not find '" + proposedMainName + "' as specified by 'main' attribute";
- } else {
- errorText =
- String.format(
- "corresponding default '%s' does not appear in srcs. Add it or override default file"
- + " name with a 'main' attribute",
- proposedMainName);
- }
- return errorText;
- }
-
// Used purely to set the legacy ActionType of the ExtraActionInfo.
@Immutable
private static final class PyPseudoAction extends PseudoAction
- *
- */
- @Nullable private final PyRuntimeInfo runtimeFromToolchain;
-
- // Null if requiresMainFile is false, or the main artifact couldn't be determined.
- @Nullable private Artifact mainArtifact = null;
-
- private Artifact executable = null;
-
- private NestedSet