From 3ca7b788dfbd5f323e9b6c58df3bdce4ced95d81 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 12 Oct 2015 15:44:09 +0000 Subject: Description redacted. -- MOS_MIGRATED_REVID=105214382 --- .../build/lib/analysis/TopLevelArtifactHelper.java | 55 ++--- .../devtools/build/lib/buildtool/BuildRequest.java | 12 +- .../build/lib/buildtool/BuildResultPrinter.java | 243 +++++++++++++++++++++ .../build/lib/buildtool/ExecutionTool.java | 185 +--------------- 4 files changed, 280 insertions(+), 215 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java (limited to 'src/main/java/com/google') 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 e5aefd07ab..d7c9a8a807 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 @@ -23,6 +23,8 @@ 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; +import javax.annotation.Nullable; + /** * A small static class containing utility methods for handling the inclusion of * extra top-level artifacts into the build. @@ -123,53 +125,34 @@ public final class TopLevelArtifactHelper { */ public static ArtifactsToBuild getAllArtifactsToBuild(TransitiveInfoCollection target, TopLevelArtifactContext context) { - NestedSetBuilder importantBuilder = NestedSetBuilder.stableOrder(); - NestedSetBuilder allBuilder = NestedSetBuilder.stableOrder(); - - OutputGroupProvider outputGroupProvider = - target.getProvider(OutputGroupProvider.class); - - for (String outputGroup : context.outputGroups()) { - NestedSetBuilder results = NestedSetBuilder.stableOrder(); - - if (outputGroup.equals(OutputGroupProvider.DEFAULT)) { - // For the default group, we also throw in filesToBuild - FileProvider fileProvider = target.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 importantArtifacts = importantBuilder.build(); - allBuilder.addTransitive(importantArtifacts); - return new ArtifactsToBuild(importantArtifacts, allBuilder.build()); + return getAllArtifactsToBuild( + target.getProvider(OutputGroupProvider.class), + target.getProvider(FileProvider.class), + context + ); } public static ArtifactsToBuild getAllArtifactsToBuild( AspectValue aspectValue, TopLevelArtifactContext context) { + Aspect aspect = aspectValue.getAspect(); + return getAllArtifactsToBuild( + aspect.getProvider(OutputGroupProvider.class), + aspect.getProvider(FileProvider.class), + context + ); + } + + public static ArtifactsToBuild getAllArtifactsToBuild( + @Nullable OutputGroupProvider outputGroupProvider, + @Nullable FileProvider fileProvider, + TopLevelArtifactContext context) { NestedSetBuilder importantBuilder = NestedSetBuilder.stableOrder(); NestedSetBuilder allBuilder = NestedSetBuilder.stableOrder(); - OutputGroupProvider outputGroupProvider = - aspectValue.getAspect().getProvider(OutputGroupProvider.class); - for (String outputGroup : context.outputGroups()) { NestedSetBuilder 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()); } 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 cf822c4ee0..c4f3aa35e8 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 @@ -225,15 +225,15 @@ public class BuildRequest implements OptionsClassProvider { + "causes printing of the result to occur always. The default is one.") public int maxResultTargets; - @Option(name = "experimental_detailed_result", - defaultValue = "false", - category = "undocumented", - help = "Detailed format for build results (see --show_results). " - + "Output all produced files. Use output format suitable for tool consumption. " + @Option(name = "experimental_show_artifacts", + defaultValue = "false", + category = "undocumented", + help = "Output a list of all top level artifacts produced by this build." + + "Use output format suitable for tool consumption. " + "This flag is temporary and intended to facilitate Android Studio integration. " + "This output format will likely change in the future or disappear completely." ) - public boolean detailedResult; + public boolean showArtifacts; @Option(name = "announce", defaultValue = "false", diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java new file mode 100644 index 0000000000..c12fed248d --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java @@ -0,0 +1,243 @@ +// Copyright 2014 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.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.InputFileConfiguredTarget; +import com.google.devtools.build.lib.analysis.OutputFileConfiguredTarget; +import com.google.devtools.build.lib.analysis.OutputGroupProvider; +import com.google.devtools.build.lib.analysis.TopLevelArtifactContext; +import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.CollectionUtils; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.exec.ExecutionOptions; +import com.google.devtools.build.lib.packages.Rule; +import com.google.devtools.build.lib.runtime.BlazeRuntime; +import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.skyframe.AspectValue; +import com.google.devtools.build.lib.util.io.OutErr; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Handles --show_results and --experimental_show_artifacts. + */ +class BuildResultPrinter { + private final CommandEnvironment env; + private final BlazeRuntime runtime; + + BuildResultPrinter(CommandEnvironment env) { + this.env = env; + this.runtime = env.getRuntime(); + } + + /** + * Shows the result of the build. Information includes the list of up-to-date + * and failed targets and list of output artifacts for successful targets + * + *

This corresponds to the --show_results flag. + */ + public void showBuildResult( + BuildRequest request, + BuildResult result, + Collection configuredTargets, + Collection aspects) { + // NOTE: be careful what you print! We don't want to create a consistency + // problem where the summary message and the exit code disagree. The logic + // here is already complex. + + Collection targetsToPrint = filterTargetsToPrint(configuredTargets); + Collection aspectsToPrint = filterAspectsToPrint(aspects); + + // Filter the targets we care about into two buckets: + Collection succeeded = new ArrayList<>(); + Collection failed = new ArrayList<>(); + for (ConfiguredTarget target : targetsToPrint) { + Collection successfulTargets = result.getSuccessfulTargets(); + (successfulTargets.contains(target) ? succeeded : failed).add(target); + } + + // Suppress summary if --show_result value is exceeded: + if (succeeded.size() + failed.size() + aspectsToPrint.size() + > request.getBuildOptions().maxResultTargets) { + return; + } + + OutErr outErr = request.getOutErr(); + + TopLevelArtifactContext context = request.getTopLevelArtifactContext(); + for (ConfiguredTarget target : succeeded) { + Label label = target.getLabel(); + // For up-to-date targets report generated artifacts, but only + // if they have associated action and not middleman artifacts. + boolean headerFlag = true; + for (Artifact artifact : + TopLevelArtifactHelper.getAllArtifactsToBuild(target, context).getImportantArtifacts()) { + if (shouldPrint(artifact)) { + if (headerFlag) { + outErr.printErr("Target " + label + " up-to-date:\n"); + headerFlag = false; + } + outErr.printErrLn(formatArtifactForShowResults(artifact, request)); + } + } + if (headerFlag) { + outErr.printErr("Target " + label + " up-to-date (nothing to build)\n"); + } + } + + for (AspectValue aspect : aspectsToPrint) { + Label label = aspect.getLabel(); + String aspectName = aspect.getAspect().getName(); + boolean headerFlag = true; + NestedSet importantArtifacts = + TopLevelArtifactHelper.getAllArtifactsToBuild(aspect, context).getImportantArtifacts(); + for (Artifact importantArtifact : importantArtifacts) { + if (headerFlag) { + outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n"); + headerFlag = false; + } + if (shouldPrint(importantArtifact)) { + outErr.printErrLn(formatArtifactForShowResults(importantArtifact, request)); + } + } + if (headerFlag) { + outErr.printErr( + "Aspect " + aspectName + " of " + label + " up-to-date (nothing to build)\n"); + } + } + + for (ConfiguredTarget target : failed) { + outErr.printErr("Target " + target.getLabel() + " failed to build\n"); + + // For failed compilation, it is still useful to examine temp artifacts, + // (ie, preprocessed and assembler files). + OutputGroupProvider topLevelProvider = + target.getProvider(OutputGroupProvider.class); + if (topLevelProvider != null) { + for (Artifact temp : topLevelProvider.getOutputGroup(OutputGroupProvider.TEMP_FILES)) { + if (temp.getPath().exists()) { + outErr.printErrLn(" See temp at " + + OutputDirectoryLinksUtils.getPrettyPath(temp.getPath(), + runtime.getWorkspaceName(), + runtime.getWorkspace(), + request.getSymlinkPrefix())); + } + } + } + } + if (!failed.isEmpty() && !request.getOptions(ExecutionOptions.class).verboseFailures) { + outErr.printErr("Use --verbose_failures to see the command lines of failed build steps.\n"); + } + } + + private boolean shouldPrint(Artifact artifact) { + return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact(); + } + + private String formatArtifactForShowResults(Artifact artifact, BuildRequest request) { + return " " + OutputDirectoryLinksUtils.getPrettyPath(artifact.getPath(), + runtime.getWorkspaceName(), runtime.getWorkspace(), request.getSymlinkPrefix()); + } + + /** + * Prints a flat list of all artifacts built by the passed top-level targets. + * + *

This corresponds to the --experimental_show_artifacts flag. + */ + public void showArtifacts( + BuildRequest request, + Collection configuredTargets, + Collection aspects) { + + TopLevelArtifactContext context = request.getTopLevelArtifactContext(); + Collection targetsToPrint = filterTargetsToPrint(configuredTargets); + Collection aspectsToPrint = filterAspectsToPrint(aspects); + + NestedSetBuilder artifactsBuilder = NestedSetBuilder.stableOrder(); + for (ConfiguredTarget target : targetsToPrint) { + artifactsBuilder.addTransitive( + TopLevelArtifactHelper.getAllArtifactsToBuild(target, context).getImportantArtifacts()); + } + + for (AspectValue aspect : aspectsToPrint) { + artifactsBuilder.addTransitive( + TopLevelArtifactHelper.getAllArtifactsToBuild(aspect, context).getImportantArtifacts()); + } + + OutErr outErr = request.getOutErr(); + outErr.printErrLn("Build artifacts:"); + + NestedSet artifacts = artifactsBuilder.build(); + for (Artifact artifact : artifacts) { + if (!artifact.isSourceArtifact()) { + outErr.printErrLn(">>>" + artifact.getPath()); + } + } + } + + /** + * Returns a list of configured targets that should participate in printing. + * + *

Hidden rules and other inserted targets are ignored. + */ + private Collection filterTargetsToPrint( + Collection configuredTargets) { + ImmutableList.Builder result = ImmutableList.builder(); + for (ConfiguredTarget target : configuredTargets) { + // TODO(bazel-team): this is quite ugly. Add a marker provider for this check. + if (target instanceof InputFileConfiguredTarget) { + // Suppress display of source files (because we do no work to build them). + continue; + } + if (target.getTarget() instanceof Rule) { + Rule rule = (Rule) target.getTarget(); + if (rule.getRuleClass().contains("$")) { + // Suppress display of hidden rules + continue; + } + } + if (target instanceof OutputFileConfiguredTarget) { + // Suppress display of generated files (because they appear underneath + // their generating rule), EXCEPT those ones which are not part of the + // filesToBuild of their generating rule (e.g. .par, _deploy.jar + // files), OR when a user explicitly requests an output file but not + // its rule. + TransitiveInfoCollection generatingRule = + env.getView().getGeneratingRule((OutputFileConfiguredTarget) target); + if (CollectionUtils.containsAll( + generatingRule.getProvider(FileProvider.class).getFilesToBuild(), + target.getProvider(FileProvider.class).getFilesToBuild()) + && configuredTargets.contains(generatingRule)) { + continue; + } + } + + result.add(target); + } + return result.build(); + } + + private Collection filterAspectsToPrint(Collection aspects) { + return aspects; + } +} 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 aef654ce98..cc3c8046f3 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 @@ -50,22 +50,13 @@ import com.google.devtools.build.lib.actions.cache.ActionCache; import com.google.devtools.build.lib.analysis.BuildView; import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult; import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FileProvider; -import com.google.devtools.build.lib.analysis.InputFileConfiguredTarget; -import com.google.devtools.build.lib.analysis.OutputFileConfiguredTarget; -import com.google.devtools.build.lib.analysis.OutputGroupProvider; import com.google.devtools.build.lib.analysis.SymlinkTreeActionContext; -import com.google.devtools.build.lib.analysis.TopLevelArtifactContext; import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper; -import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection; import com.google.devtools.build.lib.buildtool.buildevent.ExecutionPhaseCompleteEvent; import com.google.devtools.build.lib.buildtool.buildevent.ExecutionStartingEvent; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.CollectionUtils; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.EventKind; @@ -75,7 +66,6 @@ import com.google.devtools.build.lib.exec.ExecutionOptions; import com.google.devtools.build.lib.exec.OutputService; import com.google.devtools.build.lib.exec.SingleBuildFileCache; import com.google.devtools.build.lib.exec.SymlinkTreeStrategy; -import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.profiler.AutoProfiler; import com.google.devtools.build.lib.profiler.ProfilePhase; import com.google.devtools.build.lib.profiler.Profiler; @@ -92,7 +82,6 @@ import com.google.devtools.build.lib.skyframe.SkyframeExecutor; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.ExitCode; import com.google.devtools.build.lib.util.LoggingUtil; -import com.google.devtools.build.lib.util.io.OutErr; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; @@ -476,9 +465,20 @@ public class ExecutionTool { try (AutoProfiler p = AutoProfiler.profiled("Show results", ProfilerTask.INFO)) { determineSuccessfulTargets(buildResult, configuredTargets, builtTargets, timer); - showBuildResult(request, buildResult, configuredTargets, analysisResult.getAspects()); + BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env); + buildResultPrinter.showBuildResult( + request, buildResult, configuredTargets, analysisResult.getAspects()); Preconditions.checkNotNull(buildResult.getSuccessfulTargets()); } + + try (AutoProfiler p = AutoProfiler.profiled("Show artifacts", ProfilerTask.INFO)) { + if (request.getBuildOptions().showArtifacts) { + BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env); + buildResultPrinter.showArtifacts( + request, configuredTargets, analysisResult.getAspects()); + } + } + if (explanationHandler != null) { uninstallExplanationHandler(explanationHandler); } @@ -646,167 +646,6 @@ public class ExecutionTool { } - private interface ArtifactFormatter { - boolean shouldPrint(Artifact artifact); - String format(Artifact artifact); - } - - private class BriefArtifactFormatter implements ArtifactFormatter { - @Override - public boolean shouldPrint(Artifact artifact) { - return !artifact.isSourceArtifact() && !artifact.isMiddlemanArtifact(); - } - - @Override - public String format(Artifact artifact) { - return " " + - OutputDirectoryLinksUtils.getPrettyPath(artifact.getPath(), - runtime.getWorkspaceName(), getWorkspace(), request.getSymlinkPrefix()); - } - } - - private class DetailedArtifactFormatter implements ArtifactFormatter { - @Override - public boolean shouldPrint(Artifact artifact) { - return !artifact.isSourceArtifact(); - } - - @Override - public String format(Artifact artifact) { - return ">>>" + artifact.getPath(); - } - } - - /** - * Shows the result of the build. Information includes the list of up-to-date - * and failed targets and list of output artifacts for successful targets - * @param request The build request, which specifies various options. - * @param configuredTargets The configured targets whose artifacts are to be - * built. - *@param aspects - */ - private void showBuildResult( - BuildRequest request, - BuildResult result, - Collection configuredTargets, - Collection aspects) { - // NOTE: be careful what you print! We don't want to create a consistency - // problem where the summary message and the exit code disagree. The logic - // here is already complex. - - // Filter the targets we care about into two buckets: - Collection succeeded = new ArrayList<>(); - Collection failed = new ArrayList<>(); - for (ConfiguredTarget target : configuredTargets) { - // TODO(bazel-team): this is quite ugly. Add a marker provider for this check. - if (target instanceof InputFileConfiguredTarget) { - // Suppress display of source files (because we do no work to build them). - continue; - } - if (target.getTarget() instanceof Rule) { - Rule rule = (Rule) target.getTarget(); - if (rule.getRuleClass().contains("$")) { - // Suppress display of hidden rules - continue; - } - } - if (target instanceof OutputFileConfiguredTarget) { - // Suppress display of generated files (because they appear underneath - // their generating rule), EXCEPT those ones which are not part of the - // filesToBuild of their generating rule (e.g. .par, _deploy.jar - // files), OR when a user explicitly requests an output file but not - // its rule. - TransitiveInfoCollection generatingRule = - env.getView().getGeneratingRule((OutputFileConfiguredTarget) target); - if (CollectionUtils.containsAll( - generatingRule.getProvider(FileProvider.class).getFilesToBuild(), - target.getProvider(FileProvider.class).getFilesToBuild()) && - configuredTargets.contains(generatingRule)) { - continue; - } - } - - Collection successfulTargets = result.getSuccessfulTargets(); - (successfulTargets.contains(target) ? succeeded : failed).add(target); - } - - // Suppress summary if --show_result value is exceeded: - if (succeeded.size() + failed.size() + aspects.size() - > request.getBuildOptions().maxResultTargets) { - return; - } - - OutErr outErr = request.getOutErr(); - - ArtifactFormatter formatter = - request.getBuildOptions().detailedResult - ? new DetailedArtifactFormatter() - : new BriefArtifactFormatter(); - - TopLevelArtifactContext context = request.getTopLevelArtifactContext(); - for (ConfiguredTarget target : succeeded) { - Label label = target.getLabel(); - // For up-to-date targets report generated artifacts, but only - // if they have associated action and not middleman artifacts. - boolean headerFlag = true; - for (Artifact artifact : - TopLevelArtifactHelper.getAllArtifactsToBuild(target, context).getImportantArtifacts()) { - if (formatter.shouldPrint(artifact)) { - if (headerFlag) { - outErr.printErr("Target " + label + " up-to-date:\n"); - headerFlag = false; - } - outErr.printErrLn(formatter.format(artifact)); - } - } - if (headerFlag) { - outErr.printErr("Target " + label + " up-to-date (nothing to build)\n"); - } - } - - for (AspectValue aspect : aspects) { - Label label = aspect.getLabel(); - String aspectName = aspect.getAspect().getName(); - boolean headerFlag = true; - NestedSet importantArtifacts = - TopLevelArtifactHelper.getAllArtifactsToBuild(aspect, context).getImportantArtifacts(); - for (Artifact importantArtifact : importantArtifacts) { - if (headerFlag) { - outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n"); - headerFlag = false; - } - if (formatter.shouldPrint(importantArtifact)) { - outErr.printErrLn(formatter.format(importantArtifact)); - } - } - if (headerFlag) { - outErr.printErr( - "Aspect " + aspectName + " of " + label + " up-to-date (nothing to build)\n"); - } - } - - for (ConfiguredTarget target : failed) { - outErr.printErr("Target " + target.getLabel() + " failed to build\n"); - - // For failed compilation, it is still useful to examine temp artifacts, - // (ie, preprocessed and assembler files). - OutputGroupProvider topLevelProvider = - target.getProvider(OutputGroupProvider.class); - if (topLevelProvider != null) { - for (Artifact temp : topLevelProvider.getOutputGroup(OutputGroupProvider.TEMP_FILES)) { - if (temp.getPath().exists()) { - outErr.printErrLn(" See temp at " + - OutputDirectoryLinksUtils.getPrettyPath(temp.getPath(), - runtime.getWorkspaceName(), getWorkspace(), request.getSymlinkPrefix())); - } - } - } - } - if (!failed.isEmpty() && !request.getOptions(ExecutionOptions.class).verboseFailures) { - outErr.printErr("Use --verbose_failures to see the command lines of failed build steps.\n"); - } - } - private ActionCache getActionCache() throws LocalEnvironmentException { try { return env.getPersistentActionCache(); -- cgit v1.2.3