// 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.packages;

import static com.google.devtools.build.lib.packages.BuildType.TRISTATE;
import static com.google.devtools.build.lib.packages.Type.BOOLEAN;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.actions.ExecutionRequirements;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.util.Pair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import net.starlark.java.eval.Dict;
import net.starlark.java.eval.EvalException;
import net.starlark.java.syntax.Location;

/**
 * Utility functions over Targets that don't really belong in the base {@link
 * Target} interface.
 */
public final class TargetUtils {

  // *_test / test_suite attribute that used to specify constraint keywords.
  private static final String CONSTRAINTS_ATTR = "tags";

  // We don't want to pollute the execution info with random things, and we also need to reserve
  // some internal tags that we don't allow to be set on targets. We also don't want to
  // exhaustively enumerate all the legal values here. Right now, only a ~small set of tags is
  // recognized by Bazel.
  private static boolean legalExecInfoKeys(String tag) {
    return tag.startsWith("block-")
        || tag.startsWith("requires-")
        || tag.startsWith("no-")
        || tag.startsWith("supports-")
        || tag.startsWith("disable-")
        || tag.startsWith("cpu:")
        || tag.equals(ExecutionRequirements.LOCAL)
        || tag.equals(ExecutionRequirements.WORKER_KEY_MNEMONIC)
        || tag.startsWith("resources:");
  }

  private TargetUtils() {} // Uninstantiable.

  public static boolean isTestRuleName(String name) {
    return name.endsWith("_test");
  }

  public static boolean isTestSuiteRuleName(String name) {
    return name.equals("test_suite");
  }

  /**
   * Returns true iff {@code target} is a {@code *_test} rule; excludes {@code
   * test_suite}.
   */
  public static boolean isTestRule(Target target) {
    return (target instanceof Rule) && isTestRuleName(((Rule) target).getRuleClass());
  }

  /**
   * Returns true iff {@code target} is a {@code test_suite} rule.
   */
  public static boolean isTestSuiteRule(Target target) {
    return target instanceof Rule && isTestSuiteRuleName(((Rule) target).getRuleClass());
  }

  /**
   * Returns true iff {@code target} is a {@code *_test} or {@code test_suite}.
   */
  public static boolean isTestOrTestSuiteRule(Target target) {
    return isTestRule (target) || isTestSuiteRule(target);
  }

  /**
   * Returns true if {@code target} has "manual" in the tags attribute and thus should be ignored by
   * command-line wildcards or by test_suite $implicit_tests attribute.
   */
  public static boolean hasManualTag(Target target) {
    return (target instanceof Rule) && hasConstraint((Rule) target, "manual");
  }

  /**
   * Returns true if test marked as "exclusive" by the appropriate keyword
   * in the tags attribute.
   *
   * Method assumes that passed target is a test rule, so usually it should be
   * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is
   * undefined otherwise.
   */
  public static boolean isExclusiveTestRule(Rule rule) {
    return hasConstraint(rule, "exclusive");
  }

  /**
   * Returns true if test marked as "exclusive-if-local" by the appropriate keyword in the tags
   * attribute.
   *
   * <p>Method assumes that passed target is a test rule, so usually it should be used only after
   * isTestRule() or isTestOrTestSuiteRule(). Behavior is undefined otherwise.
   */
  public static boolean isExclusiveIfLocalTestRule(Rule rule) {
    return hasConstraint(rule, "exclusive-if-local");
  }
  /**
   * Returns true if test marked as "local" by the appropriate keyword
   * in the tags attribute.
   *
   * Method assumes that passed target is a test rule, so usually it should be
   * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is
   * undefined otherwise.
   */
  public static boolean isLocalTestRule(Rule rule) {
    return hasConstraint(rule, "local")
        || NonconfigurableAttributeMapper.of(rule).get("local", Type.BOOLEAN);
  }

  /**
   * Returns true if test marked as "external" by the appropriate keyword
   * in the tags attribute.
   *
   * Method assumes that passed target is a test rule, so usually it should be
   * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is
   * undefined otherwise.
   */
  public static boolean isExternalTestRule(Rule rule) {
    return hasConstraint(rule, "external");
  }

  /**
   * Returns true if test marked as "no-testloasd" by the appropriate keyword in the tags attribute.
   *
   * <p>Method assumes that passed target is a test rule, so usually it should be used only after
   * isTestRule() or isTestOrTestSuiteRule(). Behavior is undefined otherwise.
   */
  public static boolean isNoTestloasdTestRule(Rule rule) {
    return hasConstraint(rule, "no-testloasd");
  }

  public static List<String> getStringListAttr(Target target, String attrName) {
    Preconditions.checkArgument(target instanceof Rule);
    return NonconfigurableAttributeMapper.of((Rule) target).get(attrName, Type.STRING_LIST);
  }

  public static String getStringAttr(Target target, String attrName) {
    Preconditions.checkArgument(target instanceof Rule);
    return NonconfigurableAttributeMapper.of((Rule) target).get(attrName, Type.STRING);
  }

  public static Iterable<String> getAttrAsString(Target target, String attrName) {
    Preconditions.checkArgument(target instanceof Rule);
    List<String> values = new ArrayList<>(); // May hold null values.
    Attribute attribute = ((Rule) target).getAttributeDefinition(attrName);
    if (attribute != null) {
      Type<?> attributeType = attribute.getType();
      for (Object attrValue :
          AggregatingAttributeMapper.of((Rule) target)
              .visitAttribute(attribute.getName(), attributeType)) {

        // Ugly hack to maintain backward 'attr' query compatibility for BOOLEAN and TRISTATE
        // attributes. These are internally stored as actual Boolean or TriState objects but were
        // historically queried as integers. To maintain compatibility, we inspect their actual
        // value and return the integer equivalent represented as a String. This code is the
        // opposite of the code in BooleanType and TriStateType respectively.
        if (attributeType == BOOLEAN) {
          values.add(Type.BOOLEAN.cast(attrValue) ? "1" : "0");
        } else if (attributeType == TRISTATE) {
          switch (BuildType.TRISTATE.cast(attrValue)) {
            case AUTO:
              values.add("-1");
              break;
            case NO:
              values.add("0");
              break;
            case YES:
              values.add("1");
              break;
            default:
              throw new AssertionError("This can't happen!");
          }
        } else {
          values.add(attrValue == null ? null : attrValue.toString());
        }
      }
    }
    return values;
  }

  /**
   * If the given target is a rule, returns its <code>deprecation<code/> value, or null if unset.
   */
  @Nullable
  public static String getDeprecation(Target target) {
    if (!(target instanceof Rule)) {
      return null;
    }
    Rule rule = (Rule) target;
    return rule.isAttrDefined("deprecation", Type.STRING)
        ? NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING)
        : null;
  }

  /**
   * Checks whether specified constraint keyword is present in the
   * tags attribute of the test or test suite rule.
   *
   * Method assumes that provided rule is a test or a test suite. Behavior is
   * undefined otherwise.
   */
  private static boolean hasConstraint(Rule rule, String keyword) {
    return NonconfigurableAttributeMapper.of(rule).get(CONSTRAINTS_ATTR, Type.STRING_LIST)
        .contains(keyword);
  }

  /**
   * Returns the execution info from the tags declared on the target. These include only some tags
   * {@link #legalExecInfoKeys} as keys with empty values.
   */
  public static Map<String, String> getExecutionInfo(Rule rule) {
    // tags may contain duplicate values.
    Map<String, String> map = new HashMap<>();
    for (String tag :
        NonconfigurableAttributeMapper.of(rule).get(CONSTRAINTS_ATTR, Type.STRING_LIST)) {
      if (legalExecInfoKeys(tag)) {
        map.put(tag, "");
      }
    }
    return ImmutableMap.copyOf(map);
  }

  /**
   * Returns the execution info from the tags declared on the target. These include only some tags
   * {@link #legalExecInfoKeys} as keys with empty values.
   *
   * @param rule a rule instance to get tags from
   * @param allowTagsPropagation if set to true, tags will be propagated from a target to the
   *     actions' execution requirements, for more details {@see
   *     BuildLanguageOptions#experimentalAllowTagsPropagation}
   */
  public static ImmutableMap<String, String> getExecutionInfo(
      Rule rule, boolean allowTagsPropagation) {
    if (allowTagsPropagation) {
      return ImmutableMap.copyOf(getExecutionInfo(rule));
    } else {
      return ImmutableMap.of();
    }
  }

  /**
   * Returns the execution info, obtained from the rule's tags and the execution requirements
   * provided. Only supported tags are included into the execution info, see {@link
   * #legalExecInfoKeys}.
   *
   * @param executionRequirementsUnchecked execution_requirements of a rule, expected to be of a
   *     {@code Dict<String, String>} type, null or Starlark None.
   * @param rule a rule instance to get tags from
   * @param allowTagsPropagation if set to true, tags will be propagated from a target to the
   *     actions' execution requirements, for more details {@see
   *     StarlarkSematicOptions#experimentalAllowTagsPropagation}
   */
  public static ImmutableSortedMap<String, String> getFilteredExecutionInfo(
      @Nullable Object executionRequirementsUnchecked, Rule rule, boolean allowTagsPropagation)
      throws EvalException {
    Map<String, String> executionInfo =
        executionRequirementsUnchecked == null
            ? ImmutableMap.of()
            : TargetUtils.filter(
                Dict.noneableCast(
                    executionRequirementsUnchecked,
                    String.class,
                    String.class,
                    "execution_requirements"));

    if (allowTagsPropagation) {
      executionInfo = new HashMap<>(executionInfo); // Make mutable.
      Map<String, String> checkedTags = getExecutionInfo(rule);
      // merging filtered tags to the execution info map avoiding duplicates
      checkedTags.forEach(executionInfo::putIfAbsent);
    }

    return ImmutableSortedMap.copyOf(executionInfo);
  }

  /**
   * Returns the execution info. These include execution requirement tags ('block-*', 'requires-*',
   * 'no-*', 'supports-*', 'disable-*', 'local', and 'cpu:*') as keys with empty values.
   */
  private static Map<String, String> filter(Map<String, String> executionInfo) {
    return Maps.filterKeys(executionInfo, TargetUtils::legalExecInfoKeys);
  }

  /**
   * Returns the language part of the rule name (e.g. "foo" for foo_test or foo_binary).
   *
   * <p>In practice this is the part before the "_", if any, otherwise the entire rule class name.
   *
   * <p>Precondition: isTestRule(target) || isRunnableNonTestRule(target).
   */
  public static String getRuleLanguage(Target target) {
    return getRuleLanguage(((Rule) target).getRuleClass());
  }

  /**
   * Returns the language part of the rule name (e.g. "foo" for foo_test or foo_binary).
   *
   * <p>In practice this is the part before the "_", if any, otherwise the entire rule class name.
   */
  public static String getRuleLanguage(String ruleClass) {
    int index = ruleClass.lastIndexOf('_');
    // Chop off "_binary" or "_test".
    return index != -1 ? ruleClass.substring(0, index) : ruleClass;
  }

  private static boolean isExplicitDependency(Rule rule, Label label) {
    if (rule.getVisibility().getDependencyLabels().contains(label)) {
      return true;
    }

    AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
    try {
      mapper.visitLabels(
          DependencyFilter.NO_IMPLICIT_DEPS,
          (Label depLabel, Attribute attribute) -> {
            if (label.equals(depLabel)) {
              throw StopIteration.INSTANCE;
            }
          });
    } catch (StopIteration e) {
      return true;
    }
    return false;
  }

  private static final class StopIteration extends RuntimeException {
    private static final StopIteration INSTANCE = new StopIteration();
  }

  /**
   * Returns a predicate to be used for test tag filtering, i.e., that only accepts tests that match
   * all of the required tags and none of the excluded tags.
   */
  public static Predicate<Target> tagFilter(List<String> tagFilterList) {
    Pair<Collection<String>, Collection<String>> tagLists =
        TestTargetUtils.sortTagsBySense(tagFilterList);
    final Collection<String> requiredTags = tagLists.first;
    final Collection<String> excludedTags = tagLists.second;
    return input -> {
      if (requiredTags.isEmpty() && excludedTags.isEmpty()) {
        return true;
      }

      if (!(input instanceof Rule)) {
        return requiredTags.isEmpty();
      }
      // Note that test_tags are those originating from the XX_test rule, whereas the requiredTags
      // and excludedTags originate from the command line or test_suite rule.
      // TODO(ulfjack): getRuleTags is inconsistent with TestFunction and other places that use
      // tags + size, but consistent with TestSuite.
      return TestTargetUtils.testMatchesFilters(
          ((Rule) input).getRuleTags(), requiredTags, excludedTags, false);
    };
  }

  /** Return {@link Location} for {@link Target} target, if it should not be null. */
  @Nullable
  public static Location getLocationMaybe(Target target) {
    return (target instanceof Rule) || (target instanceof InputFile) ? target.getLocation() : null;
  }

  /**
   * Return nicely formatted error message that {@link Label} label that was pointed to by {@link
   * Target} target did not exist, due to {@link NoSuchThingException} e.
   */
  public static String formatMissingEdge(
      @Nullable Target target, Label label, NoSuchThingException e, @Nullable Attribute attr) {
    // instanceof returns false if target is null (which is exploited here)
    if (target instanceof Rule) {
      Rule rule = (Rule) target;
      if (isExplicitDependency(rule, label)) {
        return String.format("%s and referenced by '%s'", e.getMessage(), target.getLabel());
      } else {
        String additionalInfo = "";
        if (attr != null && !Strings.isNullOrEmpty(attr.getDoc())) {
          additionalInfo =
              String.format(
                  "\nDocumentation for implicit attribute %s of rules of type %s:\n%s",
                  attr.getPublicName(), rule.getRuleClass(), attr.getDoc());
        }
        // N.B. If you see this error message in one of our integration tests during development of
        // a change that adds a new implicit dependency when running Blaze, maybe you forgot to add
        // a new mock target to the integration test's setup.
        return String.format(
            "every rule of type %s implicitly depends upon the target '%s', but "
                + "this target could not be found because of: %s%s",
            rule.getRuleClass(), label, e.getMessage(), additionalInfo);
      }
    } else if (target instanceof InputFile) {
      return e.getMessage() + " (this is usually caused by a missing package group in the"
          + " package-level visibility declaration)";
    } else {
      if (target != null) {
        return String.format("in target '%s', no such label '%s': %s", target.getLabel(), label,
            e.getMessage());
      }
      return e.getMessage();
    }
  }

  public static String formatMissingEdge(
      @Nullable Target target, Label label, NoSuchThingException e) {
    return formatMissingEdge(target, label, e, null);
  }
}
