Description redacted.
--
MOS_MIGRATED_REVID=105214382
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 aef654c..cc3c804 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.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.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.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 @@
 
       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 @@
   }
 
 
-  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<ConfiguredTarget> configuredTargets,
-      Collection<AspectValue> 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<ConfiguredTarget> succeeded = new ArrayList<>();
-    Collection<ConfiguredTarget> 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<ConfiguredTarget> 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<Artifact> 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();