aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
diff options
context:
space:
mode:
authorGravatar twerth <twerth@google.com>2018-06-22 01:39:14 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-06-22 01:40:18 -0700
commitbe6d548b1cf373a9f706c9fff96dd6e2c25aaac6 (patch)
tree3ba42138a14795ed44cf70497e9dfcde731f9f4d /src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
parent36b5a7f52982a05549072c7b75dc84d895e469ac (diff)
Split target pattern eval, config creation, and analysis into a new class.
This is in preparation for interleaving them. RELNOTES: None PiperOrigin-RevId: 201652267
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java328
1 files changed, 14 insertions, 314 deletions
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 5b09d81401..92fa1b7d39 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
@@ -15,72 +15,38 @@ package com.google.devtools.build.lib.buildtool;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.BuildFailedException;
import com.google.devtools.build.lib.actions.TestExecException;
-import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent;
import com.google.devtools.build.lib.analysis.AnalysisResult;
import com.google.devtools.build.lib.analysis.BuildInfoEvent;
import com.google.devtools.build.lib.analysis.BuildView;
-import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.LicensesProvider;
-import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense;
-import com.google.devtools.build.lib.analysis.MakeEnvironmentEvent;
-import com.google.devtools.build.lib.analysis.StaticallyLinkedMarkerProvider;
import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.DefaultsPackage;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
-import com.google.devtools.build.lib.buildeventstream.AbortedEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEventId;
-import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Aborted.AbortReason;
import com.google.devtools.build.lib.buildtool.PostAnalysisQueryBuildTool.PostAnalysisQueryCommandLineException;
import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
import com.google.devtools.build.lib.buildtool.buildevent.BuildInterruptedEvent;
import com.google.devtools.build.lib.buildtool.buildevent.BuildStartingEvent;
-import com.google.devtools.build.lib.buildtool.buildevent.NoAnalyzeEvent;
import com.google.devtools.build.lib.buildtool.buildevent.NoExecutionEvent;
-import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
-import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.OutputFilter;
import com.google.devtools.build.lib.events.Reporter;
-import com.google.devtools.build.lib.packages.InputFile;
-import com.google.devtools.build.lib.packages.License;
-import com.google.devtools.build.lib.packages.License.DistributionType;
-import com.google.devtools.build.lib.packages.NoSuchPackageException;
-import com.google.devtools.build.lib.packages.NoSuchTargetException;
-import com.google.devtools.build.lib.packages.Target;
-import com.google.devtools.build.lib.packages.TargetUtils;
-import com.google.devtools.build.lib.pkgcache.LoadingCallback;
import com.google.devtools.build.lib.pkgcache.LoadingFailedException;
-import com.google.devtools.build.lib.pkgcache.LoadingResult;
import com.google.devtools.build.lib.profiler.ProfilePhase;
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.SilentCloseable;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
-import com.google.devtools.build.lib.skyframe.BuildConfigurationValue;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.ExitCode;
-import com.google.devtools.build.lib.util.RegexFilter;
-import com.google.devtools.common.options.OptionsParsingException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
-import java.util.stream.Stream;
/**
* Provides the bulk of the implementation of the 'blaze build' command.
@@ -171,105 +137,30 @@ public class BuildTool {
// Exit if there are any pending exceptions from modules.
env.throwPendingException();
- // Target pattern evaluation.
- LoadingResult loadingResult;
- Profiler.instance().markPhase(ProfilePhase.LOAD);
- try (SilentCloseable c = Profiler.instance().profile("evaluateTargetPatterns")) {
- loadingResult = evaluateTargetPatterns(request, validator);
- }
- env.setWorkspaceName(loadingResult.getWorkspaceName());
- executionTool = new ExecutionTool(env, request);
- if (needsExecutionPhase(request.getBuildOptions())) {
- try (SilentCloseable closeable = Profiler.instance().profile("ExecutionTool.init")) {
- executionTool.init();
- }
- }
+ initializeOutputFilter(request);
- // Compute the heuristic instrumentation filter if needed.
- if (request.needsInstrumentationFilter()) {
- String instrumentationFilter =
- InstrumentationFilterSupport.computeInstrumentationFilter(
- env.getReporter(), loadingResult.getTestsToRun());
- try {
- // We're modifying the buildOptions in place, which is not ideal, but we also don't want
- // to pay the price for making a copy. Maybe reconsider later if this turns out to be a
- // problem (and the performance loss may not be a big deal).
- buildOptions.get(BuildConfiguration.Options.class).instrumentationFilter =
- new RegexFilter.RegexFilterConverter().convert(instrumentationFilter);
- } catch (OptionsParsingException e) {
- throw new InvalidConfigurationException(e);
- }
- }
-
- // Exit if there are any pending exceptions from modules.
- env.throwPendingException();
-
- // Configuration creation.
- // TODO(gregce): Consider dropping this phase and passing on-the-fly target / host configs as
- // needed. This requires cleaning up the invalidation in SkyframeBuildView.setConfigurations.
- BuildConfigurationCollection configurations;
- try (SilentCloseable c = Profiler.instance().profile("createConfigurations")) {
- configurations =
- env.getSkyframeExecutor()
- .createConfigurations(
- env.getReporter(),
- runtime.getConfigurationFragmentFactories(),
- buildOptions,
- request.getMultiCpus(),
- request.getKeepGoing());
- }
-
- env.throwPendingException();
- if (configurations.getTargetConfigurations().size() == 1) {
- // TODO(bazel-team): This is not optimal - we retain backwards compatibility in the case
- // where there's only a single configuration, but we don't send an event in the multi-config
- // case. Can we do better? [multi-config]
- env.getEventBus().post(new MakeEnvironmentEvent(
- configurations.getTargetConfigurations().get(0).getMakeEnvironment()));
- }
- logger.info("Configurations created");
+ AnalysisPhaseRunner analysisPhaseRunner = new AnalysisPhaseRunner(env);
+ AnalysisResult analysisResult = analysisPhaseRunner.execute(request, buildOptions, validator);
+ // We cannot move the executionTool down to the execution phase part since it does set up the
+ // symlinks for tools.
+ // TODO(twerth): Extract embedded tool setup from execution tool and move object creation to
+ // execution phase.
+ executionTool = new ExecutionTool(env, request);
if (request.getBuildOptions().performAnalysisPhase) {
- Profiler.instance().markPhase(ProfilePhase.ANALYZE);
- AnalysisResult analysisResult;
- try (SilentCloseable c = Profiler.instance().profile("runAnalysisPhase")) {
- analysisResult = runAnalysisPhase(request, loadingResult, configurations);
- }
-
- // Check licenses.
- // We check licenses if the first target configuration has license checking enabled. Right
- // now, it is not possible to have multiple target configurations with different settings
- // for this flag, which allows us to take this short cut.
- boolean checkLicenses = configurations.getTargetConfigurations().get(0).checkLicenses();
- if (checkLicenses) {
- Profiler.instance().markPhase(ProfilePhase.LICENSE);
- try (SilentCloseable c = Profiler.instance().profile("validateLicensingForTargets")) {
- validateLicensingForTargets(analysisResult.getTargetsToBuild(), request.getKeepGoing());
- }
- }
-
- result.setBuildConfigurationCollection(configurations);
+ result.setBuildConfigurationCollection(analysisResult.getConfigurationCollection());
result.setActualTargets(analysisResult.getTargetsToBuild());
result.setTestTargets(analysisResult.getTargetsToTest());
- reportTargets(analysisResult);
-
- for (ConfiguredTarget target : analysisResult.getTargetsToSkip()) {
- BuildConfiguration config =
- env.getSkyframeExecutor()
- .getConfiguration(env.getReporter(), target.getConfigurationKey());
- Label label = target.getLabel();
- env.getEventBus().post(
- new AbortedEvent(
- BuildEventId.targetCompleted(label, config.getEventId()),
- AbortReason.SKIPPED,
- String.format("Target %s build was skipped.", label), label));
- }
try (SilentCloseable c = Profiler.instance().profile("postProcessAnalysisResult")) {
postProcessAnalysisResult(request, analysisResult);
}
+
// Execution phase.
if (needsExecutionPhase(request.getBuildOptions())) {
+ try (SilentCloseable closeable = Profiler.instance().profile("ExecutionTool.init")) {
+ executionTool.init();
+ }
executionTool.executeBuild(
request.getId(),
analysisResult,
@@ -277,21 +168,12 @@ public class BuildTool {
analysisResult.getPackageRoots(),
request.getTopLevelArtifactContext());
} else {
- getReporter().post(new NoExecutionEvent());
+ env.getReporter().post(new NoExecutionEvent());
}
String delayedErrorMsg = analysisResult.getError();
if (delayedErrorMsg != null) {
throw new BuildFailedException(delayedErrorMsg);
}
- } else {
- getReporter().handle(Event.progress("Loading complete."));
- getReporter().post(new NoAnalyzeEvent());
- logger.info("No analysis requested, so finished");
- String errorMessage = BuildView.createErrorMessage(loadingResult, null);
- if (errorMessage != null) {
- throw new BuildFailedException(errorMessage);
- }
- // Will return after profiler line below.
}
Profiler.instance().markPhase(ProfilePhase.FINISH);
} catch (RuntimeException e) {
@@ -446,34 +328,6 @@ public class BuildTool {
return !(request.getKeepGoing() && request.getExecutionOptions().testKeepGoing);
}
- private final LoadingResult evaluateTargetPatterns(
- final BuildRequest request, final TargetValidator validator)
- throws LoadingFailedException, TargetParsingException, InterruptedException {
- initializeOutputFilter(request);
-
- final boolean keepGoing = request.getKeepGoing();
-
- LoadingCallback callback = new LoadingCallback() {
- @Override
- public void notifyTargets(Collection<Target> targets) throws LoadingFailedException {
- if (validator != null) {
- validator.validateTargets(targets, keepGoing);
- }
- }
- };
-
- LoadingResult result =
- env.getSkyframeExecutor().loadTargetPatterns(
- getReporter(),
- request.getTargets(),
- env.getRelativeWorkingDirectory(),
- request.getLoadingOptions(),
- keepGoing,
- request.shouldRunTests(),
- callback);
- return result;
- }
-
/**
* Initializes the output filter to the value given with {@code --output_filter}.
*/
@@ -484,75 +338,6 @@ public class BuildTool {
}
}
- /**
- * Performs the initial phases 0-2 of the build: Setup, Loading and Analysis.
- * <p>
- * Postcondition: On success, populates the BuildRequest's set of targets to
- * build.
- *
- * @return null if loading / analysis phases were successful; a useful error
- * message if loading or analysis phase errors were encountered and
- * request.keepGoing.
- * @throws InterruptedException if the current thread was interrupted.
- * @throws ViewCreationFailedException if analysis failed for any reason.
- */
- private AnalysisResult runAnalysisPhase(BuildRequest request, LoadingResult loadingResult,
- BuildConfigurationCollection configurations)
- throws InterruptedException, ViewCreationFailedException {
- Stopwatch timer = Stopwatch.createStarted();
- getReporter().handle(Event.progress("Loading complete. Analyzing..."));
-
- BuildView view = new BuildView(env.getDirectories(), runtime.getRuleClassProvider(),
- env.getSkyframeExecutor(), runtime.getCoverageReportActionFactory(request));
- AnalysisResult analysisResult =
- view.update(
- loadingResult,
- configurations,
- request.getAspects(),
- request.getViewOptions(),
- request.getKeepGoing(),
- request.getLoadingPhaseThreadCount(),
- request.getTopLevelArtifactContext(),
- env.getReporter(),
- env.getEventBus());
-
- // TODO(bazel-team): Merge these into one event.
- env.getEventBus()
- .post(
- new AnalysisPhaseCompleteEvent(
- analysisResult.getTargetsToBuild(),
- view.getTargetsVisited(),
- timer.stop().elapsed(TimeUnit.MILLISECONDS),
- view.getAndClearPkgManagerStatistics(),
- view.getActionsConstructed()));
- ImmutableSet<BuildConfigurationValue.Key> configurationKeys =
- Stream.concat(
- analysisResult
- .getTargetsToBuild()
- .stream()
- .map(ConfiguredTarget::getConfigurationKey)
- .distinct(),
- analysisResult.getTargetsToTest() == null
- ? Stream.empty()
- : analysisResult
- .getTargetsToTest()
- .stream()
- .map(ConfiguredTarget::getConfigurationKey)
- .distinct())
- .filter(Objects::nonNull)
- .distinct()
- .collect(ImmutableSet.toImmutableSet());
- Map<BuildConfigurationValue.Key, BuildConfiguration> configurationMap =
- env.getSkyframeExecutor().getConfigurations(env.getReporter(), configurationKeys);
- env.getEventBus()
- .post(
- new TestFilteringCompleteEvent(
- analysisResult.getTargetsToBuild(),
- analysisResult.getTargetsToTest(),
- configurationMap));
- return analysisResult;
- }
-
private static boolean needsExecutionPhase(BuildRequestOptions options) {
return options.performAnalysisPhase && options.performExecutionPhase;
}
@@ -598,27 +383,6 @@ public class BuildTool {
}
}
- private void reportTargets(AnalysisResult analysisResult) {
- Collection<ConfiguredTarget> targetsToBuild = analysisResult.getTargetsToBuild();
- Collection<ConfiguredTarget> targetsToTest = analysisResult.getTargetsToTest();
- if (targetsToTest != null) {
- int testCount = targetsToTest.size();
- int targetCount = targetsToBuild.size() - testCount;
- if (targetCount == 0) {
- getReporter().handle(Event.info("Found "
- + testCount + (testCount == 1 ? " test target..." : " test targets...")));
- } else {
- getReporter().handle(Event.info("Found "
- + targetCount + (targetCount == 1 ? " target and " : " targets and ")
- + testCount + (testCount == 1 ? " test target..." : " test targets...")));
- }
- } else {
- int targetCount = targetsToBuild.size();
- getReporter().handle(Event.info("Found "
- + targetCount + (targetCount == 1 ? " target..." : " targets...")));
- }
- }
-
/**
* Validates the options for this BuildRequest.
*
@@ -632,70 +396,6 @@ public class BuildTool {
}
}
- /**
- * Takes a set of configured targets, and checks if the distribution methods
- * declared for the targets are compatible with the constraints imposed by
- * their prerequisites' licenses.
- *
- * @param configuredTargets the targets to check
- * @param keepGoing if false, and a licensing error is encountered, both
- * generates an error message on the reporter, <em>and</em> throws an
- * exception. If true, then just generates a message on the reporter.
- * @throws ViewCreationFailedException if the license checking failed (and not
- * --keep_going)
- */
- private void validateLicensingForTargets(Iterable<ConfiguredTarget> configuredTargets,
- boolean keepGoing) throws ViewCreationFailedException {
- for (ConfiguredTarget configuredTarget : configuredTargets) {
- Target target = null;
- try {
- target = env.getPackageManager().getTarget(env.getReporter(), configuredTarget.getLabel());
- } catch (NoSuchPackageException | NoSuchTargetException | InterruptedException e) {
- env.getReporter().handle(Event.error("Failed to get target to validate license"));
- throw new ViewCreationFailedException(
- "Build aborted due to issue getting targets to validate licenses", e);
- }
-
- if (TargetUtils.isTestRule(target)) {
- continue; // Tests are exempt from license checking
- }
-
- final Set<DistributionType> distribs = target.getDistributions();
- StaticallyLinkedMarkerProvider markerProvider =
- configuredTarget.getProvider(StaticallyLinkedMarkerProvider.class);
- boolean staticallyLinked = markerProvider != null && markerProvider.isLinkedStatically();
-
- LicensesProvider provider = configuredTarget.getProvider(LicensesProvider.class);
- if (provider != null) {
- NestedSet<TargetLicense> licenses = provider.getTransitiveLicenses();
- for (TargetLicense targetLicense : licenses) {
- if (!targetLicense.getLicense().checkCompatibility(
- distribs, target, targetLicense.getLabel(), getReporter(), staticallyLinked)) {
- if (!keepGoing) {
- throw new ViewCreationFailedException("Build aborted due to licensing error");
- }
- }
- }
- } else if (target instanceof InputFile) {
- // Input file targets do not provide licenses because they do not
- // depend on the rule where their license is taken from. This is usually
- // not a problem, because the transitive collection of licenses always
- // hits the rule they come from, except when the input file is a
- // top-level target. Thus, we need to handle that case specially here.
- //
- // See FileTarget#getLicense for more information about the handling of
- // license issues with File targets.
- License license = target.getLicense();
- if (!license.checkCompatibility(distribs, target, configuredTarget.getLabel(),
- getReporter(), staticallyLinked)) {
- if (!keepGoing) {
- throw new ViewCreationFailedException("Build aborted due to licensing error");
- }
- }
- }
- }
- }
-
private Reporter getReporter() {
return env.getReporter();
}