aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-08-19 16:57:49 +0000
committerGravatar Lukacs Berki <lberki@google.com>2015-08-20 14:49:12 +0000
commite2033b1d28d3f17c7e307f62b2b13c3eed72a7f6 (patch)
tree25d06fad6196071dd07756c5e1a661bd689198fc /src/main/java/com/google/devtools/build
parent25f4494c484512898671aab57790f4917c0f9319 (diff)
A prototype implementation of top-level aspects.
-- MOS_MIGRATED_REVID=101033236
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/Aspect.java63
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/BuildView.java131
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java23
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java36
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java45
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java52
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java13
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java55
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidNeverlinkAspect.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletionValue.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java17
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java35
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/Builder.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/CompletionFunction.java275
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeAnalysisResult.java50
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java41
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java33
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/TargetCompletionFunction.java138
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/TestCompletionFunction.java2
26 files changed, 975 insertions, 245 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java b/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java
index 3f4a06e274..95f0683363 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java
@@ -17,10 +17,16 @@ package com.google.devtools.build.lib.analysis;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.UnmodifiableIterator;
+import com.google.devtools.build.lib.actions.Artifact;
+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 java.util.LinkedHashMap;
import java.util.Map;
+import java.util.TreeMap;
+
+import javax.annotation.Nullable;
/**
* Extra information about a configured target computed on request of a dependent.
@@ -34,15 +40,25 @@ import java.util.Map;
*/
@Immutable
public final class Aspect implements Iterable<TransitiveInfoProvider> {
- private final
- ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> providers;
+ private final String name;
+ private final ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>
+ providers;
private Aspect(
+ String name,
ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> providers) {
+ this.name = name;
this.providers = providers;
}
/**
+ * Returns the aspect name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
* Returns the providers created by the aspect.
*/
public ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>
@@ -50,6 +66,14 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> {
return providers;
}
+
+ @Nullable
+ <P extends TransitiveInfoProvider> P getProvider(Class<P> providerClass) {
+ AnalysisUtils.checkProvider(providerClass);
+
+ return providerClass.cast(providers.get(providerClass));
+ }
+
@Override
public UnmodifiableIterator<TransitiveInfoProvider> iterator() {
return providers.values().iterator();
@@ -61,6 +85,12 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> {
public static class Builder {
private final Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>
providers = new LinkedHashMap<>();
+ private final Map<String, NestedSetBuilder<Artifact>> outputGroupBuilders = new TreeMap<>();
+ private final String name;
+
+ public Builder(String name) {
+ this.name = name;
+ }
/**
* Adds a provider to the aspect.
@@ -75,8 +105,35 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> {
return this;
}
+ /**
+ * Adds a set of files to an output group.
+ */
+ public Builder addOutputGroup(String name, NestedSet<Artifact> artifacts) {
+ NestedSetBuilder<Artifact> nestedSetBuilder = outputGroupBuilders.get(name);
+ if (nestedSetBuilder == null) {
+ nestedSetBuilder = NestedSetBuilder.<Artifact>stableOrder();
+ outputGroupBuilders.put(name, nestedSetBuilder);
+ }
+ nestedSetBuilder.addTransitive(artifacts);
+ return this;
+ }
+
+
public Aspect build() {
- return new Aspect(ImmutableMap.copyOf(providers));
+ if (!outputGroupBuilders.isEmpty()) {
+ ImmutableMap.Builder<String, NestedSet<Artifact>> outputGroups = ImmutableMap.builder();
+ for (Map.Entry<String, NestedSetBuilder<Artifact>> entry : outputGroupBuilders.entrySet()) {
+ outputGroups.put(entry.getKey(), entry.getValue().build());
+ }
+
+ if (providers.containsKey(OutputGroupProvider.class)) {
+ throw new IllegalStateException(
+ "OutputGroupProvider was provided explicitly; do not use addOutputGroup");
+ }
+ addProvider(OutputGroupProvider.class, new OutputGroupProvider(outputGroups.build()));
+ }
+
+ return new Aspect(name, ImmutableMap.copyOf(providers));
}
}
} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java
new file mode 100644
index 0000000000..faefb3c066
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java
@@ -0,0 +1,73 @@
+// Copyright 2015 Google Inc. 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;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * This event is fired as soon as a top-level aspect is either built or fails.
+ */
+public class AspectCompleteEvent implements SkyValue {
+ private final AspectValue aspectValue;
+ private final NestedSet<Label> rootCauses;
+
+ private AspectCompleteEvent(AspectValue aspectValue, NestedSet<Label> rootCauses) {
+ this.aspectValue = aspectValue;
+ this.rootCauses =
+ (rootCauses == null) ? NestedSetBuilder.<Label>emptySet(Order.STABLE_ORDER) : rootCauses;
+ }
+
+ /**
+ * Construct a successful target completion event.
+ */
+ public static AspectCompleteEvent createSuccessful(AspectValue value) {
+ return new AspectCompleteEvent(value, null);
+ }
+
+ /**
+ * Construct a target completion event for a failed target, with the given non-empty root causes.
+ */
+ public static AspectCompleteEvent createFailed(AspectValue value, NestedSet<Label> rootCauses) {
+ Preconditions.checkArgument(!Iterables.isEmpty(rootCauses));
+ return new AspectCompleteEvent(value, rootCauses);
+ }
+
+ /**
+ * Returns the target associated with the event.
+ */
+ public AspectValue getAspectValue() {
+ return aspectValue;
+ }
+
+ /**
+ * Determines whether the target has failed or succeeded.
+ */
+ public boolean failed() {
+ return !rootCauses.isEmpty();
+ }
+
+ /**
+ * Get the root causes of the target. May be empty.
+ */
+ public Iterable<Label> getRootCauses() {
+ return rootCauses;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
index 3baae742e9..7ce8c04325 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
@@ -65,13 +65,15 @@ import com.google.devtools.build.lib.pkgcache.PackageManager;
import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory;
import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory.CoverageReportActionsWrapper;
import com.google.devtools.build.lib.skyframe.ActionLookupValue;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.CoverageReportValue;
+import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.RegexFilter;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.skyframe.SkyKey;
@@ -79,6 +81,7 @@ import com.google.devtools.build.skyframe.WalkableGraph;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -434,12 +437,17 @@ public class BuildView {
*/
public static final class AnalysisResult {
- public static final AnalysisResult EMPTY = new AnalysisResult(
- ImmutableList.<ConfiguredTarget>of(), null, null, null,
- ImmutableList.<Artifact>of(),
- ImmutableList.<ConfiguredTarget>of(),
- ImmutableList.<ConfiguredTarget>of(),
- null);
+ public static final AnalysisResult EMPTY =
+ new AnalysisResult(
+ ImmutableList.<ConfiguredTarget>of(),
+ ImmutableList.<AspectValue>of(),
+ null,
+ null,
+ null,
+ ImmutableList.<Artifact>of(),
+ ImmutableList.<ConfiguredTarget>of(),
+ ImmutableList.<ConfiguredTarget>of(),
+ null);
private final ImmutableList<ConfiguredTarget> targetsToBuild;
@Nullable private final ImmutableList<ConfiguredTarget> targetsToTest;
@@ -449,13 +457,20 @@ public class BuildView {
private final ImmutableSet<ConfiguredTarget> parallelTests;
private final ImmutableSet<ConfiguredTarget> exclusiveTests;
@Nullable private final TopLevelArtifactContext topLevelContext;
+ private final ImmutableList<AspectValue> aspects;
private AnalysisResult(
- Collection<ConfiguredTarget> targetsToBuild, Collection<ConfiguredTarget> targetsToTest,
- @Nullable String error, ActionGraph actionGraph,
- Collection<Artifact> artifactsToBuild, Collection<ConfiguredTarget> parallelTests,
- Collection<ConfiguredTarget> exclusiveTests, TopLevelArtifactContext topLevelContext) {
+ Collection<ConfiguredTarget> targetsToBuild,
+ Collection<AspectValue> aspects,
+ Collection<ConfiguredTarget> targetsToTest,
+ @Nullable String error,
+ ActionGraph actionGraph,
+ Collection<Artifact> artifactsToBuild,
+ Collection<ConfiguredTarget> parallelTests,
+ Collection<ConfiguredTarget> exclusiveTests,
+ TopLevelArtifactContext topLevelContext) {
this.targetsToBuild = ImmutableList.copyOf(targetsToBuild);
+ this.aspects = ImmutableList.copyOf(aspects);
this.targetsToTest = targetsToTest == null ? null : ImmutableList.copyOf(targetsToTest);
this.error = error;
this.actionGraph = actionGraph;
@@ -473,6 +488,16 @@ public class BuildView {
}
/**
+ * Returns aspects of configured targets to build.
+ *
+ * <p>If this list is empty, build the targets returned by {@code getTargetsToBuild()}.
+ * Otherwise, only build these aspects of the targets returned by {@code getTargetsToBuild()}.
+ */
+ public Collection<AspectValue> getAspects() {
+ return aspects;
+ }
+
+ /**
* Returns the configured targets to run as tests, or {@code null} if testing was not
* requested (e.g. "build" command rather than "test" command).
*/
@@ -520,10 +545,11 @@ public class BuildView {
static Iterable<? extends ConfiguredTarget> filterTestsByTargets(
Collection<? extends ConfiguredTarget> targets,
final Set<? extends Target> allowedTargets) {
- return Iterables.filter(targets,
+ return Iterables.filter(
+ targets,
new Predicate<ConfiguredTarget>() {
@Override
- public boolean apply(ConfiguredTarget rule) {
+ public boolean apply(ConfiguredTarget rule) {
return allowedTargets.contains(rule.getTarget());
}
});
@@ -536,10 +562,15 @@ public class BuildView {
}
@ThreadCompatible
- public AnalysisResult update(LoadingResult loadingResult,
- BuildConfigurationCollection configurations, Options viewOptions,
- TopLevelArtifactContext topLevelOptions, EventHandler eventHandler, EventBus eventBus)
- throws ViewCreationFailedException, InterruptedException {
+ public AnalysisResult update(
+ LoadingResult loadingResult,
+ BuildConfigurationCollection configurations,
+ List<String> aspects,
+ Options viewOptions,
+ TopLevelArtifactContext topLevelOptions,
+ EventHandler eventHandler,
+ EventBus eventBus)
+ throws ViewCreationFailedException, InterruptedException {
LOG.info("Starting analysis");
pollInterruptedStatus();
@@ -580,21 +611,36 @@ public class BuildView {
}
});
+ List<AspectKey> aspectKeys = new ArrayList<>();
+ for (String aspect : aspects) {
+ @SuppressWarnings("unchecked")
+ final Class<? extends ConfiguredAspectFactory> aspectFactoryClass =
+ (Class<? extends ConfiguredAspectFactory>)
+ ruleClassProvider.getAspectFactoryMap().get(aspect);
+ if (aspectFactoryClass != null) {
+ for (ConfiguredTargetKey targetSpec : targetSpecs) {
+ aspectKeys.add(
+ AspectValue.createAspectKey(
+ targetSpec.getLabel(), targetSpec.getConfiguration(), aspectFactoryClass));
+ }
+ } else {
+ throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown");
+ }
+ }
+
prepareToBuild(new SkyframePackageRootResolver(skyframeExecutor));
skyframeExecutor.injectWorkspaceStatusData();
- Collection<ConfiguredTarget> configuredTargets;
- WalkableGraph graph;
+ SkyframeAnalysisResult skyframeAnalysisResult;
try {
- Pair<Collection<ConfiguredTarget>, WalkableGraph> configuredTargetsResult =
- skyframeBuildView.configureTargets(targetSpecs, eventBus, viewOptions.keepGoing);
- configuredTargets = configuredTargetsResult.getFirst();
- graph = configuredTargetsResult.getSecond();
+ skyframeAnalysisResult =
+ skyframeBuildView.configureTargets(
+ targetSpecs, aspectKeys, eventBus, viewOptions.keepGoing);
} finally {
skyframeBuildView.clearInvalidatedConfiguredTargets();
}
int numTargetsToAnalyze = nodes.size();
- int numSuccessful = configuredTargets.size();
+ int numSuccessful = skyframeAnalysisResult.getConfiguredTargets().size();
boolean analysisSuccessful = (numSuccessful == numTargetsToAnalyze);
if (0 < numSuccessful && numSuccessful < numTargetsToAnalyze) {
String msg = String.format("Analysis succeeded for only %d of %d top-level targets",
@@ -603,17 +649,28 @@ public class BuildView {
LOG.info(msg);
}
- AnalysisResult result = createResult(loadingResult, topLevelOptions,
- viewOptions, configuredTargets, analysisSuccessful, graph);
+ AnalysisResult result =
+ createResult(
+ loadingResult,
+ topLevelOptions,
+ viewOptions,
+ skyframeAnalysisResult.getConfiguredTargets(),
+ skyframeAnalysisResult.getAspects(),
+ skyframeAnalysisResult.getWalkableGraph(),
+ analysisSuccessful);
LOG.info("Finished analysis");
return result;
}
- private AnalysisResult createResult(LoadingResult loadingResult,
- TopLevelArtifactContext topLevelOptions, BuildView.Options viewOptions,
- Collection<ConfiguredTarget> configuredTargets, boolean analysisSuccessful,
- final WalkableGraph graph)
- throws InterruptedException {
+ private AnalysisResult createResult(
+ LoadingResult loadingResult,
+ TopLevelArtifactContext topLevelOptions,
+ BuildView.Options viewOptions,
+ Collection<ConfiguredTarget> configuredTargets,
+ Collection<AspectValue> aspects,
+ final WalkableGraph graph,
+ boolean analysisSuccessful)
+ throws InterruptedException {
Collection<Target> testsToRun = loadingResult.getTestsToRun();
Collection<ConfiguredTarget> allTargetsToTest = null;
if (testsToRun != null) {
@@ -667,8 +724,16 @@ public class BuildView {
return null;
}
};
- return new AnalysisResult(configuredTargets, allTargetsToTest, error, actionGraph,
- artifactsToBuild, parallelTests, exclusiveTests, topLevelOptions);
+ return new AnalysisResult(
+ configuredTargets,
+ aspects,
+ allTargetsToTest,
+ error,
+ actionGraph,
+ artifactsToBuild,
+ parallelTests,
+ exclusiveTests,
+ topLevelOptions);
}
private static NestedSet<Artifact> getBaselineCoverageArtifacts(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 3b4030013f..543c71e28e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -31,6 +31,7 @@ import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.graph.Digraph;
import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.AspectFactory;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClassProvider;
@@ -83,6 +84,8 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
private final Map<String, RuleClass> ruleClassMap = new HashMap<>();
private final Map<String, Class<? extends RuleDefinition>> ruleDefinitionMap =
new HashMap<>();
+ private final Map<String, Class<? extends AspectFactory<?, ?, ?>>> aspectFactoryMap =
+ new HashMap<>();
private final Map<Class<? extends RuleDefinition>, RuleClass> ruleMap = new HashMap<>();
private final Map<Class<? extends RuleDefinition>, RuleDefinition> ruleDefinitionInstanceCache =
new HashMap<>();
@@ -117,6 +120,13 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
return this;
}
+ public Builder addAspectFactory(
+ String name, Class<? extends AspectFactory<?, ?, ?>> configuredAspectFactoryClass) {
+ aspectFactoryMap.put(name, configuredAspectFactoryClass);
+
+ return this;
+ }
+
public Builder addConfigurationOptions(Class<? extends FragmentOptions> configurationOptions) {
this.configurationOptions.add(configurationOptions);
return this;
@@ -199,6 +209,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
return new ConfiguredRuleClassProvider(
ImmutableMap.copyOf(ruleClassMap),
ImmutableMap.copyOf(ruleDefinitionMap),
+ ImmutableMap.copyOf(aspectFactoryMap),
defaultWorkspaceFile.toString(),
ImmutableList.copyOf(buildInfoFactories),
ImmutableList.copyOf(configurationOptions),
@@ -247,6 +258,11 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
private final ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap;
/**
+ * Maps aspect name to the aspect factory meta class.
+ */
+ private final ImmutableMap<String, Class<? extends AspectFactory<?, ?, ?>>> aspectFactoryMap;
+
+ /**
* The configuration options that affect the behavior of the rules.
*/
private final ImmutableList<Class<? extends FragmentOptions>> configurationOptions;
@@ -272,6 +288,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
public ConfiguredRuleClassProvider(
ImmutableMap<String, RuleClass> ruleClassMap,
ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap,
+ ImmutableMap<String, Class<? extends AspectFactory<?, ?, ?>>> aspectFactoryMap,
String defaultWorkspaceFile,
ImmutableList<BuildInfoFactory> buildInfoFactories,
ImmutableList<Class<? extends FragmentOptions>> configurationOptions,
@@ -282,6 +299,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
this.ruleClassMap = ruleClassMap;
this.ruleDefinitionMap = ruleDefinitionMap;
+ this.aspectFactoryMap = aspectFactoryMap;
this.defaultWorkspaceFile = defaultWorkspaceFile;
this.buildInfoFactories = buildInfoFactories;
this.configurationOptions = configurationOptions;
@@ -302,6 +320,11 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
return ruleClassMap;
}
+ @Override
+ public Map<String, Class<? extends AspectFactory<?, ?, ?>>> getAspectFactoryMap() {
+ return aspectFactoryMap;
+ }
+
/**
* Returns a list of build info factories that are needed for the supported languages.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
index 90b373f0d0..5411f0f5b3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
@@ -22,6 +22,12 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
/**
* {@code ConfiguredTarget}s implementing this interface can provide artifacts that <b>can</b> be
* built when the target is mentioned on the command line (as opposed to being always built, like
@@ -93,7 +99,7 @@ public final class OutputGroupProvider implements TransitiveInfoProvider {
private final ImmutableMap<String, NestedSet<Artifact>> outputGroups;
- OutputGroupProvider(ImmutableMap<String, NestedSet<Artifact>> outputGroups) {
+ public OutputGroupProvider(ImmutableMap<String, NestedSet<Artifact>> outputGroups) {
this.outputGroups = outputGroups;
}
@@ -107,4 +113,32 @@ public final class OutputGroupProvider implements TransitiveInfoProvider {
? outputGroups.get(outputGroupName)
: NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER);
}
+
+ /**
+ * Merges output groups from two output providers. The set of output groups must be disjoint.
+ *
+ * @param providers providers to merge {@code this} with.
+ */
+ @Nullable
+ public static OutputGroupProvider merge(List<OutputGroupProvider> providers) {
+ if (providers.size() == 0) {
+ return null;
+ }
+ if (providers.size() == 1) {
+ return providers.get(0);
+ }
+
+ ImmutableMap.Builder<String, NestedSet<Artifact>> resultBuilder = new ImmutableMap.Builder<>();
+ Set<String> seenGroups = new HashSet<>();
+ for (OutputGroupProvider provider : providers) {
+ for (String outputGroup : provider.outputGroups.keySet()) {
+ if (!seenGroups.add(outputGroup)) {
+ throw new IllegalStateException("Output group " + outputGroup + " provided twice");
+ }
+
+ resultBuilder.put(outputGroup, provider.getOutputGroup(outputGroup));
+ }
+ }
+ return new OutputGroupProvider(resultBuilder.build());
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java
index 6ba6f1e320..fb994670cc 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java
@@ -27,8 +27,10 @@ import com.google.devtools.build.lib.packages.OutputFile;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.rules.SkylarkApiProvider;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -127,15 +129,50 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget {
Set<Class<? extends TransitiveInfoProvider>> providers = new HashSet<>();
providers.addAll(base.providers.keySet());
+
+ // Merge output group providers.
+ OutputGroupProvider baseOutputGroupProvider = base.getProvider(OutputGroupProvider.class);
+ List<OutputGroupProvider> outputGroupProviders = new ArrayList<>();
+ if (baseOutputGroupProvider != null) {
+ outputGroupProviders.add(baseOutputGroupProvider);
+ }
+
+ for (Aspect aspect : aspects) {
+ final OutputGroupProvider aspectProvider = aspect.getProvider(OutputGroupProvider.class);
+ if (aspectProvider == null) {
+ continue;
+ }
+ outputGroupProviders.add(aspectProvider);
+ }
+ OutputGroupProvider outputGroupProvider = OutputGroupProvider.merge(outputGroupProviders);
+
+ // Validate that all other providers are only provided once.
for (Aspect aspect : aspects) {
for (TransitiveInfoProvider aspectProvider : aspect) {
- if (!providers.add(aspectProvider.getClass())) {
- throw new IllegalStateException(
- "Provider " + aspectProvider.getClass() + " provided twice");
+ Class<? extends TransitiveInfoProvider> aClass = aspectProvider.getClass();
+ if (OutputGroupProvider.class.equals(aClass)) {
+ continue;
+ }
+ if (!providers.add(aClass)) {
+ throw new IllegalStateException("Provider " + aClass + " provided twice");
+ }
+ }
+ }
+
+ if (baseOutputGroupProvider == outputGroupProvider) {
+ this.providers = base.providers;
+ } else {
+ ImmutableMap.Builder<Class<? extends TransitiveInfoProvider>, Object> builder =
+ new ImmutableMap.Builder<>();
+ for (Class<? extends TransitiveInfoProvider> aClass : base.providers.keySet()) {
+ if (OutputGroupProvider.class.equals(aClass)) {
+ continue;
}
+ builder.put(aClass, base.providers.get(aClass));
}
+ builder.put(OutputGroupProvider.class, outputGroupProvider);
+ this.providers = builder.build();
}
- this.providers = base.providers;
this.mandatoryStampFiles = base.mandatoryStampFiles;
this.configConditions = base.configConditions;
this.aspects = ImmutableList.copyOf(aspects);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
index ddf3646d9a..043f4e327d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
@@ -21,6 +21,7 @@ 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.rules.test.TestProvider;
+import com.google.devtools.build.lib.skyframe.AspectValue;
/**
* A small static class containing utility methods for handling the inclusion of
@@ -96,6 +97,22 @@ public final class TopLevelArtifactHelper {
}
/**
+ * Utility function to form a NestedSet of all top-level Artifacts of the given targets.
+ */
+ public static ArtifactsToBuild getAllArtifactsToBuildFromAspects(
+ Iterable<AspectValue> aspects, TopLevelArtifactContext context) {
+ NestedSetBuilder<Artifact> allArtifacts = NestedSetBuilder.stableOrder();
+ NestedSetBuilder<Artifact> importantArtifacts = NestedSetBuilder.stableOrder();
+ for (AspectValue aspect : aspects) {
+ ArtifactsToBuild aspectArtifacts = getAllArtifactsToBuild(aspect, context);
+ allArtifacts.addTransitive(aspectArtifacts.getAllArtifacts());
+ importantArtifacts.addTransitive(aspectArtifacts.getImportantArtifacts());
+ }
+ return new ArtifactsToBuild(importantArtifacts.build(), allArtifacts.build());
+ }
+
+
+ /**
* Returns all artifacts to build if this target is requested as a top-level target. The resulting
* set includes the temps and either the files to compile, if
* {@code context.compileOnly() == true}, or the files to run.
@@ -138,4 +155,39 @@ public final class TopLevelArtifactHelper {
allBuilder.addTransitive(importantArtifacts);
return new ArtifactsToBuild(importantArtifacts, allBuilder.build());
}
+
+ public static ArtifactsToBuild getAllArtifactsToBuild(
+ AspectValue aspectValue, TopLevelArtifactContext context) {
+ NestedSetBuilder<Artifact> importantBuilder = NestedSetBuilder.stableOrder();
+ NestedSetBuilder<Artifact> allBuilder = NestedSetBuilder.stableOrder();
+
+ OutputGroupProvider outputGroupProvider =
+ aspectValue.getAspect().getProvider(OutputGroupProvider.class);
+
+ for (String outputGroup : context.outputGroups()) {
+ NestedSetBuilder<Artifact> results = NestedSetBuilder.stableOrder();
+
+ if (outputGroup.equals(OutputGroupProvider.DEFAULT)) {
+ // For the default group, we also throw in filesToBuild
+ FileProvider fileProvider = aspectValue.getAspect().getProvider(FileProvider.class);
+ if (fileProvider != null) {
+ results.addTransitive(fileProvider.getFilesToBuild());
+ }
+ }
+
+ if (outputGroupProvider != null) {
+ results.addTransitive(outputGroupProvider.getOutputGroup(outputGroup));
+ }
+
+ if (outputGroup.startsWith(OutputGroupProvider.HIDDEN_OUTPUT_GROUP_PREFIX)) {
+ allBuilder.addTransitive(results.build());
+ } else {
+ importantBuilder.addTransitive(results.build());
+ }
+ }
+
+ NestedSet<Artifact> importantArtifacts = importantBuilder.build();
+ allBuilder.addTransitive(importantArtifacts);
+ return new ArtifactsToBuild(importantArtifacts, allBuilder.build());
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
index f9277a9b3e..a506c442eb 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
@@ -81,7 +81,7 @@ public class BuildRequest implements OptionsClassProvider {
/**
* Options interface--can be used to parse command-line arguments.
*
- * See also ExecutionOptions; from the user's point of view, there's no
+ * <p>See also ExecutionOptions; from the user's point of view, there's no
* qualitative difference between these two sets of options.
*/
public static class BuildRequestOptions extends OptionsBase {
@@ -261,6 +261,15 @@ public class BuildRequest implements OptionsClassProvider {
help = "Check for modifications made to the output files of a build. Consider setting "
+ "this flag to false to see the effect on incremental build times.")
public boolean checkOutputFiles;
+
+ @Option(
+ name = "aspects",
+ converter = Converters.CommaSeparatedOptionListConverter.class,
+ defaultValue = "",
+ category = "undocumented", // for now
+ help = "List of top-level aspects"
+ )
+ public List<String> aspects;
}
/**
@@ -522,6 +531,10 @@ public class BuildRequest implements OptionsClassProvider {
return ImmutableSortedSet.copyOf(getBuildOptions().multiCpus);
}
+ public ImmutableList<String> getAspects() {
+ return ImmutableList.copyOf(getBuildOptions().aspects);
+ }
+
public static BuildRequest create(String commandName, OptionsProvider options,
OptionsProvider startupOptions,
List<String> targets, OutErr outErr, UUID commandId, long commandStartTime) {
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
index 0fe2562fe0..15fdd4b1e4 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -460,9 +460,16 @@ public class BuildTool {
getReporter().handle(Event.progress("Loading complete. Analyzing..."));
Profiler.instance().markPhase(ProfilePhase.ANALYZE);
- AnalysisResult analysisResult = getView().update(loadingResult, configurations,
- request.getViewOptions(), request.getTopLevelArtifactContext(), getReporter(),
- getEventBus());
+ AnalysisResult analysisResult =
+ getView()
+ .update(
+ loadingResult,
+ configurations,
+ request.getAspects(),
+ request.getViewOptions(),
+ request.getTopLevelArtifactContext(),
+ getReporter(),
+ getEventBus());
// TODO(bazel-team): Merge these into one event.
getEventBus().post(new AnalysisPhaseCompleteEvent(analysisResult.getTargetsToBuild(),
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
index fbe41409e5..43ec616a8b 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
@@ -83,6 +83,7 @@ import com.google.devtools.build.lib.rules.fileset.FilesetActionContextImpl;
import com.google.devtools.build.lib.rules.test.TestActionContext;
import com.google.devtools.build.lib.runtime.BlazeModule;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
+import com.google.devtools.build.lib.skyframe.AspectValue;
import com.google.devtools.build.lib.skyframe.Builder;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.syntax.Label;
@@ -391,12 +392,20 @@ public class ExecutionTool {
Set<ConfiguredTarget> builtTargets = new HashSet<>();
boolean interrupted = false;
try {
- Iterable<Artifact> allArtifactsForProviders = Iterables.concat(
- additionalArtifacts,
- TopLevelArtifactHelper.getAllArtifactsToBuild(
- analysisResult.getTargetsToBuild(), analysisResult.getTopLevelContext())
- .getAllArtifacts(),
- TopLevelArtifactHelper.getAllArtifactsToTest(analysisResult.getTargetsToTest()));
+ Collection<AspectValue> aspects = analysisResult.getAspects();
+
+ Iterable<Artifact> allArtifactsForProviders =
+ Iterables.concat(
+ additionalArtifacts,
+ TopLevelArtifactHelper.getAllArtifactsToBuild(
+ analysisResult.getTargetsToBuild(), analysisResult.getTopLevelContext())
+ .getAllArtifacts(),
+ TopLevelArtifactHelper.getAllArtifactsToBuildFromAspects(
+ aspects, analysisResult.getTopLevelContext())
+ .getAllArtifacts(),
+ //TODO(dslomov): Artifacts to test from aspects?
+ TopLevelArtifactHelper.getAllArtifactsToTest(analysisResult.getTargetsToTest()));
+
if (request.isRunningInEmacs()) {
// The syntax of this message is tightly constrained by lisp/progmodes/compile.el in emacs
request.getOutErr().printErrLn("blaze: Entering directory `" + getExecRoot() + "/'");
@@ -422,11 +431,14 @@ public class ExecutionTool {
Profiler.instance().markPhase(ProfilePhase.EXECUTE);
- builder.buildArtifacts(additionalArtifacts,
+ builder.buildArtifacts(
+ additionalArtifacts,
analysisResult.getParallelTests(),
analysisResult.getExclusiveTests(),
analysisResult.getTargetsToBuild(),
- executor, builtTargets,
+ analysisResult.getAspects(),
+ executor,
+ builtTargets,
request.getBuildOptions().explanationPath != null,
runtime.getLastExecutionTimeRange());
@@ -711,8 +723,8 @@ public class ExecutionTool {
}
}
if (headerFlag) {
- outErr.printErr(
- "Target " + label + " up-to-date (nothing to build)\n");
+ outErr.printErr("Here we are\n");
+ outErr.printErr("Target " + label + " up-to-date (nothing to build)\n");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
index d01609d3d5..94c19ef61b 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
@@ -32,6 +32,7 @@ import com.google.devtools.build.lib.actions.Executor;
import com.google.devtools.build.lib.actions.MissingInputFileException;
import com.google.devtools.build.lib.actions.ResourceManager;
import com.google.devtools.build.lib.actions.TestExecException;
+import com.google.devtools.build.lib.analysis.AspectCompleteEvent;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.TargetCompleteEvent;
import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
@@ -39,6 +40,8 @@ import com.google.devtools.build.lib.rules.test.TestProvider;
import com.google.devtools.build.lib.runtime.BugReport;
import com.google.devtools.build.lib.skyframe.ActionExecutionInactivityWatchdog;
import com.google.devtools.build.lib.skyframe.ActionExecutionValue;
+import com.google.devtools.build.lib.skyframe.AspectCompletionValue;
+import com.google.devtools.build.lib.skyframe.AspectValue;
import com.google.devtools.build.lib.skyframe.Builder;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor;
@@ -90,10 +93,12 @@ public class SkyframeBuilder implements Builder {
}
@Override
- public void buildArtifacts(Set<Artifact> artifacts,
+ public void buildArtifacts(
+ Set<Artifact> artifacts,
Set<ConfiguredTarget> parallelTests,
Set<ConfiguredTarget> exclusiveTests,
Collection<ConfiguredTarget> targetsToBuild,
+ Collection<AspectValue> aspects,
Executor executor,
Set<ConfiguredTarget> builtTargets,
boolean explain,
@@ -125,17 +130,32 @@ public class SkyframeBuilder implements Builder {
watchdog.start();
try {
- result = skyframeExecutor.buildArtifacts(executor, artifacts, targetsToBuild, parallelTests,
- /*exclusiveTesting=*/false, keepGoing, explain, numJobs, actionCacheChecker,
- executionProgressReceiver);
+ result =
+ skyframeExecutor.buildArtifacts(
+ executor,
+ artifacts,
+ targetsToBuild,
+ aspects,
+ parallelTests,
+ /*exclusiveTesting=*/ false,
+ keepGoing,
+ explain,
+ numJobs,
+ actionCacheChecker,
+ executionProgressReceiver);
// progressReceiver is finished, so unsynchronized access to builtTargets is now safe.
success = processResult(result, keepGoing, skyframeExecutor);
Preconditions.checkState(
- !success || result.keyNames().size()
- == (artifacts.size() + targetsToBuild.size() + parallelTests.size()),
+ !success
+ || result.keyNames().size()
+ == (artifacts.size()
+ + targetsToBuild.size()
+ + aspects.size()
+ + parallelTests.size()),
"Build reported as successful but not all artifacts and targets built: %s, %s",
- result, artifacts);
+ result,
+ artifacts);
// Run exclusive tests: either tagged as "exclusive" or is run in an invocation with
// --test_output=streamed.
@@ -143,9 +163,19 @@ public class SkyframeBuilder implements Builder {
for (ConfiguredTarget exclusiveTest : exclusiveTests) {
// Since only one artifact is being built at a time, we don't worry about an artifact being
// built and then the build being interrupted.
- result = skyframeExecutor.buildArtifacts(executor, ImmutableSet.<Artifact>of(),
- targetsToBuild, ImmutableSet.of(exclusiveTest), /*exclusiveTesting=*/true, keepGoing,
- explain, numJobs, actionCacheChecker, null);
+ result =
+ skyframeExecutor.buildArtifacts(
+ executor,
+ ImmutableSet.<Artifact>of(),
+ targetsToBuild,
+ aspects,
+ ImmutableSet.of(exclusiveTest), /*exclusiveTesting=*/
+ true,
+ keepGoing,
+ explain,
+ numJobs,
+ actionCacheChecker,
+ null);
boolean exclusiveSuccess = processResult(result, keepGoing, skyframeExecutor);
Preconditions.checkState(!exclusiveSuccess || !result.keyNames().isEmpty(),
"Build reported as successful but test %s not executed: %s",
@@ -177,7 +207,7 @@ public class SkyframeBuilder implements Builder {
/**
* Process the Skyframe update, taking into account the keepGoing setting.
*
- * Returns false if the update() failed, but we should continue. Returns true on success.
+ * <p>Returns false if the update() failed, but we should continue. Returns true on success.
* Throws on fail-fast failures.
*/
private static boolean processResult(EvaluationResult<?> result, boolean keepGoing,
@@ -305,6 +335,9 @@ public class SkyframeBuilder implements Builder {
ConfiguredTarget target = val.getConfiguredTarget();
builtTargets.add(target);
eventBus.post(TargetCompleteEvent.createSuccessful(target));
+ } else if (type == SkyFunctions.ASPECT_COMPLETION && node != null) {
+ AspectCompletionValue val = (AspectCompletionValue) node;
+ eventBus.post(AspectCompleteEvent.createSuccessful(val.getAspectValue()));
} else if (type == SkyFunctions.ACTION_EXECUTION) {
// Remember all completed actions, even those in error, regardless of having been cached or
// really executed.
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
index 6781d56e54..3f24efb208 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
@@ -30,6 +30,11 @@ public interface RuleClassProvider {
Map<String, RuleClass> getRuleClassMap();
/**
+ * Returns a map from aspect names to aspect factory objects.
+ */
+ Map<String, Class<? extends AspectFactory<?, ?, ?>>> getAspectFactoryMap();
+
+ /**
* Returns a new Skylark Environment instance for rule creation. Implementations need to be
* thread safe.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidNeverlinkAspect.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidNeverlinkAspect.java
index 189b6fb736..92207e8734 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidNeverlinkAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidNeverlinkAspect.java
@@ -38,14 +38,16 @@ import java.util.List;
* ijars,
*/
public class AndroidNeverlinkAspect implements ConfiguredAspectFactory {
- private static final ImmutableList<String> ATTRIBUTES = ImmutableList.of(
- "deps", "exports", "runtime_deps", "binary_under_test", "$instrumentation_test_runner");
+ public static final String NAME = "AndroidNeverlinkAspect";
+ private static final ImmutableList<String> ATTRIBUTES =
+ ImmutableList.of(
+ "deps", "exports", "runtime_deps", "binary_under_test", "$instrumentation_test_runner");
@Override
public Aspect create(ConfiguredTarget base, RuleContext ruleContext) {
if (!JavaCommon.getConstraints(ruleContext).contains("android")
&& !ruleContext.getRule().getRuleClass().startsWith("android_")) {
- return new Aspect.Builder().build();
+ return new Aspect.Builder(NAME).build();
}
List<TransitiveInfoCollection> deps = new ArrayList<>();
@@ -61,12 +63,14 @@ public class AndroidNeverlinkAspect implements ConfiguredAspectFactory {
deps.addAll(ruleContext.getPrerequisites(attribute, Mode.TARGET));
}
- return new Aspect.Builder()
- .addProvider(AndroidNeverLinkLibrariesProvider.class,
- new AndroidNeverLinkLibrariesProvider(AndroidCommon.collectTransitiveNeverlinkLibraries(
- ruleContext,
- deps,
- base.getProvider(JavaRuntimeJarProvider.class).getRuntimeJars())))
+ return new Aspect.Builder(NAME)
+ .addProvider(
+ AndroidNeverLinkLibrariesProvider.class,
+ new AndroidNeverLinkLibrariesProvider(
+ AndroidCommon.collectTransitiveNeverlinkLibraries(
+ ruleContext,
+ deps,
+ base.getProvider(JavaRuntimeJarProvider.class).getRuntimeJars())))
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
index 99bdfb4e22..669dc4eb4a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
@@ -50,6 +50,7 @@ import java.util.List;
* J2ObjC transpilation aspect for Java rules.
*/
public class J2ObjcAspect implements ConfiguredAspectFactory {
+ public static final String NAME = "J2ObjcAspect";
/**
* Adds the attribute aspect args to the given AspectDefinition.Builder.
*/
@@ -85,7 +86,7 @@ public class J2ObjcAspect implements ConfiguredAspectFactory {
@Override
public Aspect create(ConfiguredTarget base, RuleContext ruleContext) {
- Aspect.Builder builder = new Aspect.Builder();
+ Aspect.Builder builder = new Aspect.Builder(NAME);
JavaCompilationArgsProvider compilationArgsProvider =
base.getProvider(JavaCompilationArgsProvider.class);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletionValue.java
new file mode 100644
index 0000000000..695bc392e1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletionValue.java
@@ -0,0 +1,47 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.util.Collection;
+
+/**
+ * The value of an AspectCompletion. Currently this just stores an Aspect.
+ */
+public class AspectCompletionValue implements SkyValue {
+ private final AspectValue aspectValue;
+
+ AspectCompletionValue(AspectValue aspectValue) {
+ this.aspectValue = aspectValue;
+ }
+
+ public AspectValue getAspectValue() {
+ return aspectValue;
+ }
+
+ public static Iterable<SkyKey> keys(Collection<AspectValue> targets) {
+ return Iterables.transform(
+ targets,
+ new Function<AspectValue, SkyKey>() {
+ @Override
+ public SkyKey apply(AspectValue aspectValue) {
+ return new SkyKey(SkyFunctions.ASPECT_COMPLETION, aspectValue.getKey());
+ }
+ });
+ }
+}
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 30358aca5b..7db3e463fe 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
@@ -80,9 +80,14 @@ public final class AspectFunction implements SkyFunction {
"aspects must be attached to rules"));
}
- RuleConfiguredTarget associatedTarget = (RuleConfiguredTarget)
- ((ConfiguredTargetValue) env.getValue(ConfiguredTargetValue.key(
- key.getLabel(), key.getConfiguration()))).getConfiguredTarget();
+ final ConfiguredTargetValue configuredTargetValue =
+ (ConfiguredTargetValue)
+ env.getValue(ConfiguredTargetValue.key(key.getLabel(), key.getConfiguration()));
+ if (configuredTargetValue == null) {
+ return null;
+ }
+ RuleConfiguredTarget associatedTarget =
+ (RuleConfiguredTarget) configuredTargetValue.getConfiguredTarget();
if (associatedTarget == null) {
return null;
@@ -152,7 +157,11 @@ public final class AspectFunction implements SkyFunction {
Preconditions.checkNotNull(aspect);
return new AspectValue(
- aspect, ImmutableList.copyOf(analysisEnvironment.getRegisteredActions()));
+ key,
+ associatedTarget.getLabel(),
+ associatedTarget.getTarget().getLocation(),
+ aspect,
+ ImmutableList.copyOf(analysisEnvironment.getRegisteredActions()));
}
@Nullable
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
index b8a60273f6..2657caa438 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
@@ -19,6 +19,7 @@ import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.analysis.Aspect;
import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
@@ -91,19 +92,49 @@ public final class AspectValue extends ActionLookupValue {
}
}
+ private final Label label;
+ private final Location location;
+ private final AspectKey key;
private final Aspect aspect;
- public AspectValue(Aspect aspect, Iterable<Action> actions) {
+ public AspectValue(
+ AspectKey key, Label label, Location location, Aspect aspect, Iterable<Action> actions) {
super(actions);
+ this.location = location;
+ this.label = label;
+ this.key = key;
this.aspect = aspect;
}
- public Aspect get() {
+ public Aspect getAspect() {
return aspect;
}
+ public Label getLabel() {
+ return label;
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public AspectKey getKey() {
+ return key;
+ }
+
public static SkyKey key(Label label, BuildConfiguration configuration,
Class<? extends ConfiguredAspectFactory> aspectFactory) {
return new SkyKey(SkyFunctions.ASPECT, new AspectKey(label, configuration, aspectFactory));
}
+
+ public static SkyKey key(AspectKey aspectKey) {
+ return new SkyKey(SkyFunctions.ASPECT, aspectKey);
+ }
+
+ public static AspectKey createAspectKey(
+ Label label,
+ BuildConfiguration configuration,
+ Class<? extends ConfiguredAspectFactory> aspectFactory) {
+ return new AspectKey(label, configuration, aspectFactory);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/Builder.java b/src/main/java/com/google/devtools/build/lib/skyframe/Builder.java
index f23b09f28b..67e32b143e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/Builder.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/Builder.java
@@ -54,6 +54,7 @@ public interface Builder {
* artifacts.
* @param exclusiveTests are executed one at a time, only after all other tasks have completed
* @param targetsToBuild Set of targets which will be built
+ * @param aspects Set of aspects that will be built
* @param executor an opaque application-specific value that will be
* passed down to the execute() method of any Action executed during
* this call
@@ -69,10 +70,12 @@ public interface Builder {
* @throws TestExecException if any test fails
*/
@ThreadCompatible
- void buildArtifacts(Set<Artifact> artifacts,
+ void buildArtifacts(
+ Set<Artifact> artifacts,
Set<ConfiguredTarget> parallelTests,
Set<ConfiguredTarget> exclusiveTests,
Collection<ConfiguredTarget> targetsToBuild,
+ Collection<AspectValue> aspects,
Executor executor,
Set<ConfiguredTarget> builtTargets,
boolean explain,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/CompletionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/CompletionFunction.java
new file mode 100644
index 0000000000..80eb624f4a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/CompletionFunction.java
@@ -0,0 +1,275 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.common.eventbus.EventBus;
+import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MissingInputFileException;
+import com.google.devtools.build.lib.analysis.AspectCompleteEvent;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
+import com.google.devtools.build.lib.analysis.TargetCompleteEvent;
+import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
+import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
+import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper.ArtifactsToBuild;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+import com.google.devtools.build.skyframe.ValueOrException2;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Nullable;
+
+/**
+ * CompletionFunction builds the artifactsToBuild collection of a {@link ConfiguredTarget}.
+ */
+public final class CompletionFunction<TValue extends SkyValue, TResult extends SkyValue>
+ implements SkyFunction {
+
+ /**
+ * A strategy for completing the build.
+ */
+ public interface Completor<TValue, TResult extends SkyValue> {
+
+ /**
+ * Obtains an analysis result value from environment.
+ */
+ TValue getValueFromSkyKey(SkyKey skyKey, Environment env);
+
+ /**
+ * Returns all artefacts that need to be built to complete the {@code value}
+ */
+ ArtifactsToBuild getAllArtifactsToBuild(TValue value, TopLevelArtifactContext context);
+
+ /**
+ * Creates an event reporting an absent input artifact.
+ */
+ Event getRootCauseError(TValue value, Label rootCause);
+
+ /**
+ * Creates an error message reporting {@code missingCount} missing input files.
+ */
+ MissingInputFileException getMissingFilesException(TValue value, int missingCount);
+
+ /**
+ * Creates a successful completion value.
+ */
+ TResult createResult(TValue value);
+
+ /**
+ * Creates a failed completion value.
+ */
+ SkyValue createFailed(TValue value, NestedSet<Label> rootCauses);
+ }
+
+ private static class TargetCompletor
+ implements Completor<ConfiguredTargetValue, TargetCompletionValue> {
+ @Override
+ public ConfiguredTargetValue getValueFromSkyKey(SkyKey skyKey, Environment env) {
+ LabelAndConfiguration lac = (LabelAndConfiguration) skyKey.argument();
+ return (ConfiguredTargetValue)
+ env.getValue(ConfiguredTargetValue.key(lac.getLabel(), lac.getConfiguration()));
+ }
+
+ @Override
+ public ArtifactsToBuild getAllArtifactsToBuild(
+ ConfiguredTargetValue value, TopLevelArtifactContext topLevelContext) {
+ return TopLevelArtifactHelper.getAllArtifactsToBuild(
+ value.getConfiguredTarget(), topLevelContext);
+ }
+
+ @Override
+ public Event getRootCauseError(ConfiguredTargetValue ctValue, Label rootCause) {
+ return Event.error(
+ ctValue.getConfiguredTarget().getTarget().getLocation(),
+ String.format(
+ "%s: missing input file '%s'", ctValue.getConfiguredTarget().getLabel(), rootCause));
+ }
+
+ @Override
+ public MissingInputFileException getMissingFilesException(
+ ConfiguredTargetValue value, int missingCount) {
+ return new MissingInputFileException(
+ value.getConfiguredTarget().getTarget().getLocation()
+ + " "
+ + missingCount
+ + " input file(s) do not exist",
+ value.getConfiguredTarget().getTarget().getLocation());
+ }
+
+ @Override
+ public TargetCompletionValue createResult(ConfiguredTargetValue value) {
+ return new TargetCompletionValue(value.getConfiguredTarget());
+ }
+
+ @Override
+ public SkyValue createFailed(ConfiguredTargetValue value, NestedSet<Label> rootCauses) {
+ return TargetCompleteEvent.createFailed(value.getConfiguredTarget(), rootCauses);
+ }
+ }
+
+ private static class AspectCompletor implements Completor<AspectValue, AspectCompletionValue> {
+ @Override
+ public AspectValue getValueFromSkyKey(SkyKey skyKey, Environment env) {
+ AspectKey aspectKey = (AspectKey) skyKey.argument();
+ return (AspectValue) env.getValue(AspectValue.key(aspectKey));
+ }
+
+ @Override
+ public ArtifactsToBuild getAllArtifactsToBuild(
+ AspectValue value, TopLevelArtifactContext topLevelArtifactContext) {
+ return TopLevelArtifactHelper.getAllArtifactsToBuild(value, topLevelArtifactContext);
+ }
+
+ @Override
+ public Event getRootCauseError(AspectValue value, Label rootCause) {
+ return Event.error(
+ value.getLocation(),
+ String.format(
+ "%s, aspect %s: missing input file '%s'",
+ value.getLabel(),
+ value.getAspect().getName(),
+ rootCause));
+ }
+
+ @Override
+ public MissingInputFileException getMissingFilesException(AspectValue value, int missingCount) {
+ return new MissingInputFileException(
+ value.getLabel()
+ + ", aspect "
+ + value.getAspect().getName()
+ + missingCount
+ + " input file(s) do not exist",
+ value.getLocation());
+ }
+
+ @Override
+ public AspectCompletionValue createResult(AspectValue value) {
+ return new AspectCompletionValue(value);
+ }
+
+ @Override
+ public SkyValue createFailed(AspectValue value, NestedSet<Label> rootCauses) {
+ return AspectCompleteEvent.createFailed(value, rootCauses);
+ }
+ }
+
+ public static SkyFunction targetCompletionFunction(AtomicReference<EventBus> eventBusRef) {
+ return new CompletionFunction<>(eventBusRef, new TargetCompletor());
+ }
+
+ public static SkyFunction aspectCompletionFunction(AtomicReference<EventBus> eventBusRef) {
+ return new CompletionFunction<>(eventBusRef, new AspectCompletor());
+ }
+
+ private final AtomicReference<EventBus> eventBusRef;
+ private final Completor<TValue, TResult> completor;
+
+ private CompletionFunction(
+ AtomicReference<EventBus> eventBusRef, Completor<TValue, TResult> completor) {
+ this.eventBusRef = eventBusRef;
+ this.completor = completor;
+ }
+
+ @Nullable
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws CompletionFunctionException {
+ TValue value = completor.getValueFromSkyKey(skyKey, env);
+ TopLevelArtifactContext topLevelContext = PrecomputedValue.TOP_LEVEL_CONTEXT.get(env);
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ Map<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> inputDeps =
+ env.getValuesOrThrow(
+ ArtifactValue.mandatoryKeys(
+ completor.getAllArtifactsToBuild(value, topLevelContext).getAllArtifacts()),
+ MissingInputFileException.class,
+ ActionExecutionException.class);
+
+ int missingCount = 0;
+ ActionExecutionException firstActionExecutionException = null;
+ MissingInputFileException missingInputException = null;
+ NestedSetBuilder<Label> rootCausesBuilder = NestedSetBuilder.stableOrder();
+ for (Map.Entry<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>>
+ depsEntry : inputDeps.entrySet()) {
+ Artifact input = ArtifactValue.artifact(depsEntry.getKey());
+ try {
+ depsEntry.getValue().get();
+ } catch (MissingInputFileException e) {
+ missingCount++;
+ final Label inputOwner = input.getOwner();
+ if (inputOwner != null) {
+ rootCausesBuilder.add(inputOwner);
+ env.getListener().handle(completor.getRootCauseError(value, inputOwner));
+ }
+ } catch (ActionExecutionException e) {
+ rootCausesBuilder.addTransitive(e.getRootCauses());
+ if (firstActionExecutionException == null) {
+ firstActionExecutionException = e;
+ }
+ }
+ }
+
+ if (missingCount > 0) {
+ missingInputException = completor.getMissingFilesException(value, missingCount);
+ }
+
+ NestedSet<Label> rootCauses = rootCausesBuilder.build();
+ if (!rootCauses.isEmpty()) {
+ eventBusRef.get().post(completor.createFailed(value, rootCauses));
+ if (firstActionExecutionException != null) {
+ throw new CompletionFunctionException(firstActionExecutionException);
+ } else {
+ throw new CompletionFunctionException(missingInputException);
+ }
+ }
+
+ return env.valuesMissing() ? null : completor.createResult(value);
+ }
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return Label.print(((LabelAndConfiguration) skyKey.argument()).getLabel());
+ }
+
+ private static final class CompletionFunctionException extends SkyFunctionException {
+
+ private final ActionExecutionException actionException;
+
+ public CompletionFunctionException(ActionExecutionException e) {
+ super(e, Transience.PERSISTENT);
+ this.actionException = e;
+ }
+
+ public CompletionFunctionException(MissingInputFileException e) {
+ super(e, Transience.TRANSIENT);
+ this.actionException = null;
+ }
+
+ @Override
+ public boolean isCatastrophic() {
+ return actionException != null && actionException.isCatastrophe();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index dff91d6976..1132a7b02b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -309,7 +309,7 @@ final class ConfiguredTargetFunction implements SkyFunction {
// Dependent aspect has either not been computed yet or is in error.
return null;
}
- result.put(depKey, aspectValue.get());
+ result.put(depKey, aspectValue.getAspect());
}
}
@@ -320,7 +320,7 @@ final class ConfiguredTargetFunction implements SkyFunction {
Class<? extends ConfiguredAspectFactory> aspectFactory) {
AspectDefinition aspectDefinition = AspectFactory.Util.create(aspectFactory).getDefinition();
for (Class<?> provider : aspectDefinition.getRequiredProviders()) {
- if (dep.getProvider((Class<? extends TransitiveInfoProvider>) provider) == null) {
+ if (dep.getProvider(provider.asSubclass(TransitiveInfoProvider.class)) == null) {
return false;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index caec042df4..aba4e49062 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -60,8 +60,9 @@ public final class SkyFunctions {
SkyFunctionName.create("POST_CONFIGURED_TARGET");
public static final SkyFunctionName TARGET_COMPLETION =
SkyFunctionName.create("TARGET_COMPLETION");
- public static final SkyFunctionName TEST_COMPLETION =
- SkyFunctionName.create("TEST_COMPLETION");
+ public static final SkyFunctionName ASPECT_COMPLETION =
+ SkyFunctionName.create("ASPECT_COMPLETION");
+ public static final SkyFunctionName TEST_COMPLETION = SkyFunctionName.create("TEST_COMPLETION");
public static final SkyFunctionName BUILD_CONFIGURATION =
SkyFunctionName.create("BUILD_CONFIGURATION");
public static final SkyFunctionName CONFIGURATION_FRAGMENT =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeAnalysisResult.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeAnalysisResult.java
new file mode 100644
index 0000000000..323dc3d88a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeAnalysisResult.java
@@ -0,0 +1,50 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.skyframe.WalkableGraph;
+
+import java.util.Collection;
+
+/**
+ * Encapsulates the raw analysis result of top level targets and aspects coming from Skyframe.
+ */
+public class SkyframeAnalysisResult {
+ private final ImmutableList<ConfiguredTarget> configuredTargets;
+ private final WalkableGraph walkableGraph;
+ private final ImmutableList<AspectValue> aspects;
+
+ public SkyframeAnalysisResult(
+ ImmutableList<ConfiguredTarget> configuredTargets,
+ WalkableGraph walkableGraph,
+ ImmutableList<AspectValue> aspects) {
+ this.configuredTargets = configuredTargets;
+ this.walkableGraph = walkableGraph;
+ this.aspects = aspects;
+ }
+
+ public Collection<ConfiguredTarget> getConfiguredTargets() {
+ return configuredTargets;
+ }
+
+ public WalkableGraph getWalkableGraph() {
+ return walkableGraph;
+ }
+
+ public Collection<AspectValue> getAspects() {
+ return aspects;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index ed85621d49..eed73aef66 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.skyframe;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -48,11 +49,11 @@ import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.skyframe.ActionLookupValue.ActionLookupKey;
+import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
import com.google.devtools.build.lib.skyframe.BuildInfoCollectionValue.BuildInfoKeyAndConfig;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.ConfiguredValueCreationException;
import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ConflictException;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.CycleInfo;
import com.google.devtools.build.skyframe.ErrorInfo;
@@ -61,7 +62,6 @@ import com.google.devtools.build.skyframe.EvaluationResult;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
-import com.google.devtools.build.skyframe.WalkableGraph;
import java.util.Collection;
import java.util.HashSet;
@@ -160,33 +160,51 @@ public final class SkyframeBuildView {
*
* @return the configured targets that should be built along with a WalkableGraph of the analysis.
*/
- public Pair<Collection<ConfiguredTarget>, WalkableGraph> configureTargets(
- List<ConfiguredTargetKey> values, EventBus eventBus, boolean keepGoing)
- throws InterruptedException, ViewCreationFailedException {
+ public SkyframeAnalysisResult configureTargets(
+ List<ConfiguredTargetKey> values,
+ List<AspectKey> aspectKeys,
+ EventBus eventBus,
+ boolean keepGoing)
+ throws InterruptedException, ViewCreationFailedException {
enableAnalysis(true);
- EvaluationResult<ConfiguredTargetValue> result;
+ EvaluationResult<ActionLookupValue> result;
try {
- result = skyframeExecutor.configureTargets(values, keepGoing);
+ result = skyframeExecutor.configureTargets(values, aspectKeys, keepGoing);
} finally {
enableAnalysis(false);
}
ImmutableMap<Action, ConflictException> badActions = skyframeExecutor.findArtifactConflicts();
+ Collection<AspectValue> goodAspects = Lists.newArrayListWithCapacity(values.size());
+ for (AspectKey aspectKey : aspectKeys) {
+ AspectValue value = (AspectValue) result.get(AspectValue.key(aspectKey));
+ if (value == null) {
+ // Skip aspects that couldn't be applied to targets.
+ continue;
+ }
+ goodAspects.add(value);
+ }
+
// Filter out all CTs that have a bad action and convert to a list of configured targets. This
// code ensures that the resulting list of configured targets has the same order as the incoming
// list of values, i.e., that the order is deterministic.
Collection<ConfiguredTarget> goodCts = Lists.newArrayListWithCapacity(values.size());
for (ConfiguredTargetKey value : values) {
- ConfiguredTargetValue ctValue = result.get(ConfiguredTargetValue.key(value));
+ ConfiguredTargetValue ctValue =
+ (ConfiguredTargetValue) result.get(ConfiguredTargetValue.key(value));
if (ctValue == null) {
continue;
}
goodCts.add(ctValue.getConfiguredTarget());
}
+
if (!result.hasError() && badActions.isEmpty()) {
setDeserializedArtifactOwners();
- return Pair.of(goodCts, result.getWalkableGraph());
+ return new SkyframeAnalysisResult(
+ ImmutableList.copyOf(goodCts),
+ result.getWalkableGraph(),
+ ImmutableList.copyOf(goodAspects));
}
// --nokeep_going so we fail with an exception for the first error.
@@ -291,7 +309,10 @@ public final class SkyframeBuildView {
}
}
setDeserializedArtifactOwners();
- return Pair.of(goodCts, result.getWalkableGraph());
+ return new SkyframeAnalysisResult(
+ ImmutableList.copyOf(goodCts),
+ result.getWalkableGraph(),
+ ImmutableList.copyOf(goodAspects));
}
@Nullable
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 8b482e5aa2..cbcc676aa4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -83,6 +83,7 @@ import com.google.devtools.build.lib.pkgcache.PackageManager;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader;
import com.google.devtools.build.lib.profiler.Profiler;
+import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.FileDirtinessChecker;
import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ActionCompletedReceiver;
import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ProgressSupplier;
@@ -338,7 +339,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
map.put(
SkyFunctions.WORKSPACE_FILE,
new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories));
- map.put(SkyFunctions.TARGET_COMPLETION, new TargetCompletionFunction(eventBus));
+ map.put(SkyFunctions.TARGET_COMPLETION, CompletionFunction.targetCompletionFunction(eventBus));
+ map.put(SkyFunctions.ASPECT_COMPLETION, CompletionFunction.aspectCompletionFunction(eventBus));
map.put(SkyFunctions.TEST_COMPLETION, new TestCompletionFunction());
map.put(SkyFunctions.ARTIFACT, new ArtifactFunction(allowedMissingInputs));
map.put(SkyFunctions.BUILD_INFO_COLLECTION, new BuildInfoCollectionFunction(artifactFactory,
@@ -1003,13 +1005,15 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
Executor executor,
Set<Artifact> artifactsToBuild,
Collection<ConfiguredTarget> targetsToBuild,
+ Collection<AspectValue> aspects,
Collection<ConfiguredTarget> targetsToTest,
boolean exclusiveTesting,
boolean keepGoing,
boolean explain,
int numJobs,
ActionCacheChecker actionCacheChecker,
- @Nullable EvaluationProgressReceiver executionProgressReceiver) throws InterruptedException {
+ @Nullable EvaluationProgressReceiver executionProgressReceiver)
+ throws InterruptedException {
checkActive();
Preconditions.checkState(actionLogBufferPathGenerator != null);
@@ -1020,9 +1024,13 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
progressReceiver.executionProgressReceiver = executionProgressReceiver;
Iterable<SkyKey> artifactKeys = ArtifactValue.mandatoryKeys(artifactsToBuild);
Iterable<SkyKey> targetKeys = TargetCompletionValue.keys(targetsToBuild);
+ Iterable<SkyKey> aspectKeys = AspectCompletionValue.keys(aspects);
Iterable<SkyKey> testKeys = TestCompletionValue.keys(targetsToTest, exclusiveTesting);
- return buildDriver.evaluate(Iterables.concat(artifactKeys, targetKeys, testKeys), keepGoing,
- numJobs, errorEventListener);
+ return buildDriver.evaluate(
+ Iterables.concat(artifactKeys, targetKeys, aspectKeys, testKeys),
+ keepGoing,
+ numJobs,
+ errorEventListener);
} finally {
progressReceiver.executionProgressReceiver = null;
// Also releases thread locks.
@@ -1108,7 +1116,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
continue DependentNodeLoop;
}
- aspects.add(((AspectValue) result.get(aspectKey)).get());
+ aspects.add(((AspectValue) result.get(aspectKey)).getAspect());
}
cts.add(RuleConfiguredTarget.mergeAspects(configuredTarget, aspects));
@@ -1157,13 +1165,20 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
/**
* Configures a given set of configured targets.
*/
- public EvaluationResult<ConfiguredTargetValue> configureTargets(
- List<ConfiguredTargetKey> values, boolean keepGoing) throws InterruptedException {
+ public EvaluationResult<ActionLookupValue> configureTargets(
+ List<ConfiguredTargetKey> values, List<AspectKey> aspectKeys, boolean keepGoing)
+ throws InterruptedException {
checkActive();
+ Set<SkyKey> keys = new HashSet<>();
+ keys.addAll(ConfiguredTargetValue.keys(values));
+ for (AspectKey aspectKey : aspectKeys) {
+ keys.add(AspectValue.key(aspectKey));
+ }
+
// Make sure to not run too many analysis threads. This can cause memory thrashing.
- return buildDriver.evaluate(ConfiguredTargetValue.keys(values), keepGoing,
- ResourceUsage.getAvailableProcessors(), errorEventListener);
+ return buildDriver.evaluate(
+ keys, keepGoing, ResourceUsage.getAvailableProcessors(), errorEventListener);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetCompletionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetCompletionFunction.java
deleted file mode 100644
index e89c0fc56d..0000000000
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetCompletionFunction.java
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2014 Google Inc. 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.skyframe;
-
-import com.google.common.eventbus.EventBus;
-import com.google.devtools.build.lib.actions.ActionExecutionException;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.MissingInputFileException;
-import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
-import com.google.devtools.build.lib.analysis.TargetCompleteEvent;
-import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
-import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.skyframe.SkyFunction;
-import com.google.devtools.build.skyframe.SkyFunctionException;
-import com.google.devtools.build.skyframe.SkyKey;
-import com.google.devtools.build.skyframe.SkyValue;
-import com.google.devtools.build.skyframe.ValueOrException2;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.annotation.Nullable;
-
-/**
- * TargetCompletionFunction builds the artifactsToBuild collection of a {@link ConfiguredTarget}.
- */
-public final class TargetCompletionFunction implements SkyFunction {
-
- private final AtomicReference<EventBus> eventBusRef;
-
- public TargetCompletionFunction(AtomicReference<EventBus> eventBusRef) {
- this.eventBusRef = eventBusRef;
- }
-
- @Nullable
- @Override
- public SkyValue compute(SkyKey skyKey, Environment env) throws TargetCompletionFunctionException {
- LabelAndConfiguration lac = (LabelAndConfiguration) skyKey.argument();
- ConfiguredTargetValue ctValue = (ConfiguredTargetValue)
- env.getValue(ConfiguredTargetValue.key(lac.getLabel(), lac.getConfiguration()));
- TopLevelArtifactContext topLevelContext = PrecomputedValue.TOP_LEVEL_CONTEXT.get(env);
- if (env.valuesMissing()) {
- return null;
- }
-
- Map<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> inputDeps =
- env.getValuesOrThrow(ArtifactValue.mandatoryKeys(
- TopLevelArtifactHelper.getAllArtifactsToBuild(
- ctValue.getConfiguredTarget(), topLevelContext).getAllArtifacts()),
- MissingInputFileException.class, ActionExecutionException.class);
-
- int missingCount = 0;
- ActionExecutionException firstActionExecutionException = null;
- MissingInputFileException missingInputException = null;
- NestedSetBuilder<Label> rootCausesBuilder = NestedSetBuilder.stableOrder();
- for (Map.Entry<SkyKey, ValueOrException2<MissingInputFileException,
- ActionExecutionException>> depsEntry : inputDeps.entrySet()) {
- Artifact input = ArtifactValue.artifact(depsEntry.getKey());
- try {
- depsEntry.getValue().get();
- } catch (MissingInputFileException e) {
- missingCount++;
- if (input.getOwner() != null) {
- rootCausesBuilder.add(input.getOwner());
- env.getListener().handle(Event.error(
- ctValue.getConfiguredTarget().getTarget().getLocation(),
- String.format("%s: missing input file '%s'",
- lac.getLabel(), input.getOwner())));
- }
- } catch (ActionExecutionException e) {
- rootCausesBuilder.addTransitive(e.getRootCauses());
- if (firstActionExecutionException == null) {
- firstActionExecutionException = e;
- }
- }
- }
-
- if (missingCount > 0) {
- missingInputException = new MissingInputFileException(
- ctValue.getConfiguredTarget().getTarget().getLocation() + " " + missingCount
- + " input file(s) do not exist", ctValue.getConfiguredTarget().getTarget().getLocation());
- }
-
- NestedSet<Label> rootCauses = rootCausesBuilder.build();
- if (!rootCauses.isEmpty()) {
- eventBusRef.get().post(
- TargetCompleteEvent.createFailed(ctValue.getConfiguredTarget(), rootCauses));
- if (firstActionExecutionException != null) {
- throw new TargetCompletionFunctionException(firstActionExecutionException);
- } else {
- throw new TargetCompletionFunctionException(missingInputException);
- }
- }
-
- return env.valuesMissing() ? null : new TargetCompletionValue(ctValue.getConfiguredTarget());
- }
-
- @Override
- public String extractTag(SkyKey skyKey) {
- return Label.print(((LabelAndConfiguration) skyKey.argument()).getLabel());
- }
-
- private static final class TargetCompletionFunctionException extends SkyFunctionException {
-
- private final ActionExecutionException actionException;
-
- public TargetCompletionFunctionException(ActionExecutionException e) {
- super(e, Transience.PERSISTENT);
- this.actionException = e;
- }
-
- public TargetCompletionFunctionException(MissingInputFileException e) {
- super(e, Transience.TRANSIENT);
- this.actionException = null;
- }
-
- @Override
- public boolean isCatastrophic() {
- return actionException != null && actionException.isCatastrophe();
- }
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TestCompletionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TestCompletionFunction.java
index b6f96061ef..35abad2fa2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TestCompletionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TestCompletionFunction.java
@@ -23,7 +23,7 @@ import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
/**
- * TargetCompletionFunction builds all relevant test artifacts of a {@link
+ * TestCompletionFunction builds all relevant test artifacts of a {@link
* com.google.devtools.build.lib.analysis.ConfiguredTarget}. This includes test shards and repeated
* runs.
*/