Make it possible for aspects to provide FileProvider.
This will then be merged with the FileProvider of the associated configured target.
RELNOTES[NEW]: aspects can now return DefaultInfo, which will then be merged with that of the configured target they are applied to. Currently, only the files= field is supported.
PiperOrigin-RevId: 661221846
Change-Id: I15a95220b9ea263e3e2125f80c8acadd80078565
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java
index e27fd48..3fb9985 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Provider;
@@ -47,7 +48,7 @@
UnloadedToolchainContext unloadedToolchainContext,
String targetDescription,
ImmutableMultimap<ToolchainTypeInfo, ConfiguredTargetAndData> toolchainTargets)
- throws DuplicateException {
+ throws MergingException {
ImmutableMap.Builder<ToolchainTypeInfo, ToolchainAspectsProviders> toolchainsBuilder =
new ImmutableMap.Builder<>();
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index 59a75aa..177b241 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -89,7 +89,6 @@
":constraints/supported_environments_provider",
":constraints/top_level_constraint_semantics",
":dependency_kind",
- ":duplicate_exception",
":extra/extra_action_info_file_write_action",
":extra_action_artifacts_provider",
":file_provider",
@@ -305,7 +304,6 @@
":constraints/supported_environments",
":constraints/supported_environments_provider",
":dependency_kind",
- ":duplicate_exception",
":exec_group_collection",
":extra/extra_action_info_file_write_action",
":extra_action_artifacts_provider",
@@ -751,11 +749,6 @@
)
java_library(
- name = "duplicate_exception",
- srcs = ["DuplicateException.java"],
-)
-
-java_library(
name = "exec_group_collection",
srcs = ["ExecGroupCollection.java"],
deps = [
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DuplicateException.java b/src/main/java/com/google/devtools/build/lib/analysis/DuplicateException.java
deleted file mode 100644
index 3ad5cc1..0000000
--- a/src/main/java/com/google/devtools/build/lib/analysis/DuplicateException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2020 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.analysis;
-
-/**
- * This exception is thrown when configured targets and aspects being merged provide duplicate
- * things that they shouldn't (output groups or providers).
- */
-public final class DuplicateException extends Exception {
- public DuplicateException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java
index e38e157..85de020 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java
@@ -26,6 +26,7 @@
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleConfiguredTargetUtil;
import com.google.devtools.build.lib.collect.ImmutableSharedKeyMap;
import com.google.devtools.build.lib.collect.nestedset.Depset;
@@ -178,7 +179,7 @@
* disjoint, except for the special validation output group, which is always merged.
*/
@Nullable
- public static OutputGroupInfo merge(List<OutputGroupInfo> providers) throws DuplicateException {
+ public static OutputGroupInfo merge(List<OutputGroupInfo> providers) throws MergingException {
if (providers.isEmpty()) {
return null;
}
@@ -193,7 +194,7 @@
continue;
}
if (outputGroups.put(group, provider.getOutputGroup(group)) != null) {
- throw new DuplicateException("Output group " + group + " provided twice");
+ throw new MergingException("Output group " + group + " provided twice");
}
}
}
@@ -204,7 +205,7 @@
validationOutputs.addTransitive(provider.getOutputGroup(VALIDATION));
} catch (IllegalArgumentException e) {
// Thrown if nested set orders aren't compatible.
- throw new DuplicateException(
+ throw new MergingException(
"Output group " + VALIDATION + " provided twice with incompatible depset orders");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
index 4f64db4..801e48b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
@@ -16,11 +16,13 @@
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionLookupKey;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.DuplicateException;
+import com.google.devtools.build.lib.analysis.DefaultInfo;
import com.google.devtools.build.lib.analysis.ExtraActionArtifactsProvider;
+import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
import com.google.devtools.build.lib.analysis.RequiredConfigFragmentsProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
@@ -30,7 +32,9 @@
import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesInfo;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.Depset.TypeException;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.Info;
import com.google.devtools.build.lib.packages.Provider;
@@ -52,8 +56,23 @@
*/
@Immutable
public final class MergedConfiguredTarget extends AbstractConfiguredTarget {
+ /**
+ * This exception is thrown when the providers of a configured target and the aspects applied to
+ * it cannot be merged.
+ */
+ public static final class MergingException extends Exception {
+ public MergingException(String message) {
+ super(message);
+ }
+
+ public MergingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
private final ConfiguredTarget base;
private final ImmutableList<ConfiguredAspect> aspects;
+
/**
* Providers that come from any source that isn't a pure pointer to the base rule's providers.
*
@@ -160,13 +179,50 @@
/** Creates an instance based on a configured target and a set of aspects. */
public static ConfiguredTarget of(ConfiguredTarget base, Collection<ConfiguredAspect> aspects)
- throws DuplicateException {
+ throws MergingException {
if (aspects.isEmpty()) {
return base; // If there are no aspects, don't bother with creating a proxy object.
}
TransitiveInfoProviderMapBuilder nonBaseProviders = new TransitiveInfoProviderMapBuilder();
+ // filesToBuild is special: for native aspects, it is returned in a FileProvider, for Starlark
+ // ones, in a DefaultInfo. Furthermore, DefaultInfo is not a "normal" provider on configured
+ // targets but is created on demand from FileProvider, etc. So we need to jump through some
+ // hoops here.
+ List<NestedSet<Artifact>> filesToBuild = new ArrayList<>();
+ filesToBuild.add(base.getProvider(FileProvider.class).getFilesToBuild());
+ for (ConfiguredAspect aspect : aspects) {
+ if (aspect.getProvider(FileProvider.class) != null) {
+ filesToBuild.add(aspect.getProvider(FileProvider.class).getFilesToBuild());
+ } else if (aspect.get(DefaultInfo.PROVIDER.getKey()) != null) {
+ DefaultInfo defaultInfo = (DefaultInfo) aspect.get(DefaultInfo.PROVIDER.getKey());
+ if (defaultInfo.getDataRunfiles() != null
+ || defaultInfo.getDefaultRunfiles() != null
+ || defaultInfo.getExecutable() != null
+ || defaultInfo.getFilesToRun() != null) {
+ throw new MergingException(
+ "Provider 'DefaultInfo' returned by an aspect not at top level must only have the "
+ + "'files' field set");
+ }
+
+ if (defaultInfo.getFiles() != null) {
+ try {
+ filesToBuild.add(defaultInfo.getFiles().getSet(Artifact.class));
+ } catch (TypeException e) {
+ throw new MergingException(
+ "'files' field of 'DefaultInfo' should contain a depset of files", e);
+ }
+ }
+ }
+ }
+
+ if (filesToBuild.size() > 1) {
+ nonBaseProviders.put(
+ FileProvider.class,
+ FileProvider.of(NestedSetBuilder.fromNestedSets(filesToBuild).build()));
+ }
+
// Merge output group providers.
OutputGroupInfo mergedOutputGroupInfo = mergeOutputGroupProviders(base, aspects);
if (mergedOutputGroupInfo != null) {
@@ -199,23 +255,27 @@
Object providerKey = providers.getProviderKeyAt(i);
if (OutputGroupInfo.STARLARK_CONSTRUCTOR.getKey().equals(providerKey)
|| AnalysisFailureInfo.STARLARK_CONSTRUCTOR.getKey().equals(providerKey)
+ || FileProvider.class.equals(providerKey)
|| ExtraActionArtifactsProvider.class.equals(providerKey)
|| RequiredConfigFragmentsProvider.class.equals(providerKey)) {
continue;
}
- if (providerKey instanceof Class<?>) {
+ if (providerKey.equals(DefaultInfo.PROVIDER.getKey())) {
+ // This was handled when creating FileProvider above.
+ continue;
+ } else if (providerKey instanceof Class<?>) {
@SuppressWarnings("unchecked")
Class<? extends TransitiveInfoProvider> providerClass =
(Class<? extends TransitiveInfoProvider>) providerKey;
if (base.getProvider(providerClass) != null || nonBaseProviders.contains(providerClass)) {
- throw new DuplicateException("Provider " + providerKey + " provided twice");
+ throw new MergingException("Provider " + providerKey + " provided twice");
}
nonBaseProviders.put(
providerClass, (TransitiveInfoProvider) providers.getProviderInstanceAt(i));
} else if (providerKey instanceof String legacyId) {
if (base.get(legacyId) != null || nonBaseProviders.contains(legacyId)) {
- throw new DuplicateException("Provider " + legacyId + " provided twice");
+ throw new MergingException("Provider " + legacyId + " provided twice");
}
nonBaseProviders.put(legacyId, providers.getProviderInstanceAt(i));
} else if (providerKey instanceof Provider.Key key) {
@@ -227,7 +287,7 @@
if ((!InstrumentedFilesInfo.STARLARK_CONSTRUCTOR.getKey().equals(key)
&& base.get(key) != null)
|| nonBaseProviders.contains(key)) {
- throw new DuplicateException("Provider " + key + " provided twice");
+ throw new MergingException("Provider " + key + " provided twice");
}
nonBaseProviders.put((Info) providers.getProviderInstanceAt(i));
}
@@ -237,8 +297,7 @@
}
private static OutputGroupInfo mergeOutputGroupProviders(
- @Nullable ConfiguredTarget base, Iterable<ConfiguredAspect> aspects)
- throws DuplicateException {
+ @Nullable ConfiguredTarget base, Iterable<ConfiguredAspect> aspects) throws MergingException {
ImmutableList.Builder<OutputGroupInfo> providers = ImmutableList.builder();
if (base != null) {
@@ -321,7 +380,7 @@
}
/** Returns only the providers from the aspects. */
- public TransitiveInfoProviderMap getAspectsProviders() throws DuplicateException {
+ public TransitiveInfoProviderMap getAspectsProviders() throws MergingException {
TransitiveInfoProviderMapBuilder aspectsProviders = new TransitiveInfoProviderMapBuilder();
// Merge output group providers of aspects only. Filtering the base target output
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
index 2849660..a7bc9ed 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
@@ -46,7 +46,6 @@
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target_value",
"//src/main/java/com/google/devtools/build/lib/analysis:constraints/incompatible_target_checker",
"//src/main/java/com/google/devtools/build/lib/analysis:dependency_kind",
- "//src/main/java/com/google/devtools/build/lib/analysis:duplicate_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:exec_group_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_aspect_order_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_null_config_exception",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredAspectProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredAspectProducer.java
index e34533c..14d8935 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredAspectProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredAspectProducer.java
@@ -20,9 +20,9 @@
import com.google.devtools.build.lib.analysis.AspectCollection.AspectDeps;
import com.google.devtools.build.lib.analysis.AspectValue;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
-import com.google.devtools.build.lib.analysis.DuplicateException;
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.skyframe.AspectCreationException;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
@@ -42,7 +42,7 @@
void acceptConfiguredAspectError(AspectCreationException error);
- void acceptConfiguredAspectError(DuplicateException error);
+ void acceptConfiguredAspectError(MergingException error);
}
// -------------------- Input --------------------
@@ -117,7 +117,7 @@
outputIndex,
prerequisite.fromConfiguredTarget(
MergedConfiguredTarget.of(prerequisite.getConfiguredTarget(), configuredAspects)));
- } catch (DuplicateException e) {
+ } catch (MergingException e) {
sink.acceptConfiguredAspectError(e);
}
return DONE;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
index bc2c047..ac198ed 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
@@ -22,11 +22,11 @@
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.AspectCollection;
-import com.google.devtools.build.lib.analysis.DuplicateException;
import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException;
import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException;
import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
import com.google.devtools.build.lib.analysis.configuredtargets.PackageGroupConfiguredTarget;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Aspect;
@@ -243,7 +243,7 @@
}
@Override
- public void acceptConfiguredAspectError(DuplicateException error) {
+ public void acceptConfiguredAspectError(MergingException error) {
hasError = true;
sink.acceptPrerequisitesAspectError(
new DependencyEvaluationException(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 18095b3..05a5cdc 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -35,7 +35,6 @@
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
import com.google.devtools.build.lib.analysis.DependencyKind;
-import com.google.devtools.build.lib.analysis.DuplicateException;
import com.google.devtools.build.lib.analysis.ExecGroupCollection;
import com.google.devtools.build.lib.analysis.ExecGroupCollection.InvalidExecGroupException;
import com.google.devtools.build.lib.analysis.IncompatiblePlatformProvider;
@@ -50,6 +49,7 @@
import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader;
import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader.StarlarkExecTransitionLoadingException;
import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException;
import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
import com.google.devtools.build.lib.analysis.producers.DependencyContext;
import com.google.devtools.build.lib.analysis.producers.DependencyContextProducer;
@@ -338,7 +338,7 @@
Lists.transform(key.getBaseKeys(), k -> ((AspectValue) aspectValues.get(k)));
try {
associatedTarget = MergedConfiguredTarget.of(associatedTarget, directlyRequiredAspects);
- } catch (DuplicateException e) {
+ } catch (MergingException e) {
env.getListener().handle(Event.error(target.getLocation(), e.getMessage()));
throw new AspectFunctionException(
new AspectCreationException(e.getMessage(), target.getLabel(), configuration));
@@ -426,7 +426,7 @@
baseTargetToolchainContexts =
getBaseTargetToolchainContexts(
baseTargetUnloadedToolchainContexts, aspect, target, depValueMap);
- } catch (DuplicateException e) {
+ } catch (MergingException e) {
env.getListener().handle(Event.error(target.getLocation(), e.getMessage()));
throw new AspectFunctionException(
new AspectCreationException(e.getMessage(), target.getLabel(), configuration));
@@ -487,7 +487,7 @@
Aspect aspect,
Target target,
OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> depValueMap)
- throws DuplicateException {
+ throws MergingException {
if (baseTargetUnloadedToolchainContexts == null) {
return null;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index 7bf8943..f8da79a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -264,7 +264,6 @@
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target_value",
"//src/main/java/com/google/devtools/build/lib/analysis:constraints/incompatible_target_checker",
"//src/main/java/com/google/devtools/build/lib/analysis:dependency_kind",
- "//src/main/java/com/google/devtools/build/lib/analysis:duplicate_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:exec_group_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:incompatible_platform_provider",
"//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_aspect_order_exception",