// 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.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
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.configuredtargets.InputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.OutputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
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.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
import com.google.devtools.build.lib.util.io.OutErr;
import java.util.ArrayList;
import java.util.Collection;

/**
 * Handles --show_result and --experimental_show_artifacts.
 */
class BuildResultPrinter {
  private final CommandEnvironment env;

  BuildResultPrinter(CommandEnvironment env) {
    this.env = env;
  }

  /**
   * 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
   *
   * <p>This corresponds to the --show_result flag.
   */
  void showBuildResult(
      BuildRequest request,
      BuildResult result,
      Collection<ConfiguredTarget> configuredTargets,
      Collection<ConfiguredTarget> configuredTargetsToSkip,
      ImmutableMap<AspectKey, ConfiguredAspect> 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.

    BlazeRuntime runtime = env.getRuntime();
    String productName = runtime.getProductName();
    PathPrettyPrinter prettyPrinter =
        OutputDirectoryLinksUtils.getPathPrettyPrinter(
            runtime.getRuleClassProvider().getSymlinkDefinitions(),
            request.getBuildOptions().getSymlinkPrefix(productName),
            productName,
            env.getWorkspace(),
            request.getBuildOptions().printWorkspaceInOutputPathsIfNeeded
                ? env.getWorkingDirectory()
                : env.getWorkspace(),
            request.getBuildOptions().experimentalNoProductNameOutSymlink);
    OutErr outErr = request.getOutErr();
    Collection<ConfiguredTarget> targetsToPrint = filterTargetsToPrint(configuredTargets);
    final boolean success;
    if (aspects.isEmpty()) {
      // Suppress summary if --show_result value is exceeded:
      if (targetsToPrint.size() > request.getBuildOptions().maxResultTargets) {
        return;
      }
      // Filter the targets we care about into three buckets:
      Collection<ConfiguredTarget> succeeded = new ArrayList<>();
      Collection<ConfiguredTarget> failed = new ArrayList<>();
      Collection<ConfiguredTarget> skipped = new ArrayList<>();
      Collection<ConfiguredTarget> successfulTargets = result.getSuccessfulTargets();
      for (ConfiguredTarget target : targetsToPrint) {
        if (configuredTargetsToSkip.contains(target)) {
          skipped.add(target);
        } else {
          (successfulTargets.contains(target) ? succeeded : failed).add(target);
        }
      }

      for (ConfiguredTarget target : skipped) {
        outErr.printErr("Target " + target.getLabel() + " was skipped\n");
      }

      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()
                .toList()) {
          if (shouldPrint(artifact)) {
            if (headerFlag) {
              outErr.printErr("Target " + label + " up-to-date:\n");
              headerFlag = false;
            }
            outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, artifact));
          }
        }
        if (headerFlag) {
          outErr.printErr("Target " + 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).
        OutputGroupInfo topLevelProvider = OutputGroupInfo.get(target);
        if (topLevelProvider != null) {
          for (Artifact temp :
              topLevelProvider.getOutputGroup(OutputGroupInfo.TEMP_FILES).toList()) {
            if (temp.getPath().exists()) {
              outErr.printErrLn("  See temp at " + prettyPrinter.getPrettyPath(temp.getPath()));
            }
          }
        }
      }
      success = failed.isEmpty();
    } else {
      // Suppress summary if --show_result value is exceeded:
      if (aspects.size() > request.getBuildOptions().maxResultTargets) {
        return;
      }
      // Filter the targets we care about into two buckets:
      Collection<AspectKey> succeeded = new ArrayList<>();
      Collection<AspectKey> failed = new ArrayList<>();
      ImmutableSet<AspectKey> successfulAspects = result.getSuccessfulAspects();
      for (AspectKey aspect : aspects.keySet()) {
        (successfulAspects.contains(aspect) ? succeeded : failed).add(aspect);
      }
      TopLevelArtifactContext context = request.getTopLevelArtifactContext();
      for (AspectKey aspect : succeeded) {
        Label label = aspect.getLabel();
        ConfiguredAspect configuredAspect = aspects.get(aspect);
        String aspectName = aspect.getAspectClass().getName();
        boolean headerFlag = true;
        NestedSet<Artifact> importantArtifacts =
            TopLevelArtifactHelper.getAllArtifactsToBuild(configuredAspect, context)
                .getImportantArtifacts();
        for (Artifact importantArtifact : importantArtifacts.toList()) {
          if (headerFlag) {
            outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n");
            headerFlag = false;
          }
          if (shouldPrint(importantArtifact)) {
            outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, importantArtifact));
          }
        }
        if (headerFlag) {
          outErr.printErr(
              "Aspect " + aspectName + " of " + label + " up-to-date (nothing to build)\n");
        }
      }
      for (AspectKey aspect : failed) {
        Label label = aspect.getLabel();
        String aspectName = aspect.getAspectClass().getName();
        outErr.printErr("Aspect " + aspectName + " of " + label + " failed to build\n");
      }
      success = failed.isEmpty();
    }
    if (!success && !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(PathPrettyPrinter prettyPrinter, Artifact artifact) {
    return "  " + prettyPrinter.getPrettyPath(artifact.getPath());
  }

  /**
   * Prints a flat list of all artifacts built by the passed top-level targets.
   *
   * <p>This corresponds to the --experimental_show_artifacts flag.
   */
  void showArtifacts(
      BuildRequest request,
      Collection<ConfiguredTarget> configuredTargets,
      Collection<ConfiguredAspect> aspects) {

    TopLevelArtifactContext context = request.getTopLevelArtifactContext();
    Collection<ConfiguredTarget> targetsToPrint = filterTargetsToPrint(configuredTargets);

    NestedSetBuilder<Artifact> artifactsBuilder = NestedSetBuilder.stableOrder();
    targetsToPrint.forEach(
        t ->
            artifactsBuilder.addTransitive(
                TopLevelArtifactHelper.getAllArtifactsToBuild(t, context).getImportantArtifacts()));

    aspects.forEach(
        a ->
            artifactsBuilder.addTransitive(
                TopLevelArtifactHelper.getAllArtifactsToBuild(a, context).getImportantArtifacts()));

    OutErr outErr = request.getOutErr();
    outErr.printErrLn("Build artifacts:");

    NestedSet<Artifact> artifacts = artifactsBuilder.build();
    for (Artifact artifact : artifacts.toList()) {
      if (!artifact.isSourceArtifact()) {
        outErr.printErrLn(">>>" + artifact.getPath());
      }
    }
  }

  /**
   * Returns a list of configured targets that should participate in printing.
   *
   * <p>Hidden rules and other inserted targets are ignored.
   */
  private Collection<ConfiguredTarget> filterTargetsToPrint(
      Collection<ConfiguredTarget> configuredTargets) {
    ImmutableList.Builder<ConfiguredTarget> result = ImmutableList.builder();
    for (ConfiguredTarget configuredTarget : configuredTargets) {
      // TODO(bazel-team): this is quite ugly. Add a marker provider for this check.
      if (configuredTarget instanceof InputFileConfiguredTarget) {
        // Suppress display of source files (because we do no work to build them).
        continue;
      }
      if (configuredTarget instanceof RuleConfiguredTarget) {
        RuleConfiguredTarget ruleCt = (RuleConfiguredTarget) configuredTarget;
        if (ruleCt.getRuleClassString().contains("$")) {
          // Suppress display of hidden rules
          continue;
        }
      }
      if (configuredTarget 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 =
            ((OutputFileConfiguredTarget) configuredTarget).getGeneratingRule();
        if (CollectionUtils.containsAll(
                generatingRule.getProvider(FileProvider.class).getFilesToBuild().toList(),
                configuredTarget.getProvider(FileProvider.class).getFilesToBuild().toList())
            && configuredTargets.contains(generatingRule)) {
          continue;
        }
      }

      result.add(configuredTarget);
    }
    return result.build();
  }
}
