diff options
author | twerth <twerth@google.com> | 2018-06-22 01:39:14 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-22 01:40:18 -0700 |
commit | be6d548b1cf373a9f706c9fff96dd6e2c25aaac6 (patch) | |
tree | 3ba42138a14795ed44cf70497e9dfcde731f9f4d /src/main/java/com/google/devtools/build/lib/buildtool | |
parent | 36b5a7f52982a05549072c7b75dc84d895e469ac (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')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java | 387 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java | 328 |
2 files changed, 401 insertions, 314 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java new file mode 100644 index 0000000000..36ac9cfb77 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java @@ -0,0 +1,387 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.buildtool; + +import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.actions.BuildFailedException; +import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent; +import com.google.devtools.build.lib.analysis.AnalysisResult; +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.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.buildevent.NoAnalyzeEvent; +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.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.CommandEnvironment; +import com.google.devtools.build.lib.skyframe.BuildConfigurationValue; +import com.google.devtools.build.lib.util.AbruptExitException; +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.Logger; +import java.util.stream.Stream; + +/** Performs target pattern eval, configuration creation, loading and analysis. */ +public final class AnalysisPhaseRunner { + + private static Logger logger = Logger.getLogger(BuildTool.class.getName()); + + protected CommandEnvironment env; + + public AnalysisPhaseRunner(CommandEnvironment env) { + this.env = env; + } + + public AnalysisResult execute( + BuildRequest request, BuildOptions buildOptions, TargetValidator validator) + throws BuildFailedException, InterruptedException, ViewCreationFailedException, + TargetParsingException, LoadingFailedException, AbruptExitException, + InvalidConfigurationException { + + // 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()); + + // 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(), + env.getRuntime().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"); + + AnalysisResult analysisResult = null; + if (request.getBuildOptions().performAnalysisPhase) { + Profiler.instance().markPhase(ProfilePhase.ANALYZE); + 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()); + } + } + + 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)); + } + } else { + env.getReporter().handle(Event.progress("Loading complete.")); + env.getReporter().post(new NoAnalyzeEvent()); + logger.info("No analysis requested, so finished"); + String errorMessage = BuildView.createErrorMessage(loadingResult, null); + if (errorMessage != null) { + throw new BuildFailedException(errorMessage); + } + } + + return analysisResult; + } + + private final LoadingResult evaluateTargetPatterns( + final BuildRequest request, final TargetValidator validator) + throws LoadingFailedException, TargetParsingException, InterruptedException { + + 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( + env.getReporter(), + request.getTargets(), + env.getRelativeWorkingDirectory(), + request.getLoadingOptions(), + keepGoing, + request.shouldRunTests(), + callback); + return result; + } + + /** + * 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(); + env.getReporter().handle(Event.progress("Loading complete. Analyzing...")); + + BuildView view = + new BuildView( + env.getDirectories(), + env.getRuntime().getRuleClassProvider(), + env.getSkyframeExecutor(), + env.getRuntime().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 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) { + env.getReporter() + .handle( + Event.info( + "Found " + + testCount + + (testCount == 1 ? " test target..." : " test targets..."))); + } else { + env.getReporter() + .handle( + Event.info( + "Found " + + targetCount + + (targetCount == 1 ? " target and " : " targets and ") + + testCount + + (testCount == 1 ? " test target..." : " test targets..."))); + } + } else { + int targetCount = targetsToBuild.size(); + env.getReporter() + .handle( + Event.info( + "Found " + targetCount + (targetCount == 1 ? " target..." : " targets..."))); + } + } + + /** + * 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(), + env.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(), env.getReporter(), staticallyLinked)) { + if (!keepGoing) { + throw new ViewCreationFailedException("Build aborted due to licensing error"); + } + } + } + } + } +} 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(); } |