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/BuildTool.java | |
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/BuildTool.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java | 328 |
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(); } |