/*
 * Copyright 2018-present Facebook, Inc.
 *
 * 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.facebook.buck.parser.cache.impl;

import com.facebook.buck.io.filesystem.ProjectFilesystem;
import com.facebook.buck.util.config.Config;
import com.facebook.buck.util.environment.Architecture;
import com.facebook.buck.util.environment.Platform;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;

/**
 * This class implements functionality to get the weak fingerprint and strong fingerprint hashes for
 * caching parser result - {@link com.facebook.buck.parser.api.BuildFileManifest}.
 *
 * <p>Note: The Fingerprinter object provides fingerprints for the two-level cache used to identify
 * the relevant {@link com.facebook.buck.parser.api.BuildFileManifest} objects in the cache. The
 * first level cache is provided by the so called weak fingerprint. The weak fingerprint encodes
 * some common configuration/environments used by the build file parser, and the name of the file
 * that is associated with the cell currently being built. The weak fingerprint maps to a set of
 * strong fingerprints that are relevant. Examples of entries that are currently included into a
 * weak fingerprint are the buck configuration environment, the name of the build file associated
 * with the cell object being built, platform and architecture for which the build is performed.
 *
 * <p>The strong fingerprint is used to narrow a specific version of the pre-parsed serialized
 * objects - it adds another level of lookup rules that point to a specific match of the current
 * build files states, from a set that use the same weak fingerprints. Currently the strong
 * fingerprint includes the content hashes of all the loaded build files during the parsing of the
 * build spec of interest.
 *
 * <p>Splitting the lookup into two phases reduces the data that needs to be transferred locally
 * since only the entries that match the weak and strong fingerprint could be relevant. More
 * importantly, it reduces the amount of glob operations that need to be performed to validate the
 * use of the cached {@link com.facebook.buck.parser.api.BuildFileManifest} - only the globs for the
 * potential match, both weak and strong fingerprints are performed.
 */
public final class Fingerprinter {
  private Fingerprinter() {}

  /**
   * Gets the weak fingerprint for this configuration.
   *
   * @param buildFile the path to the BUCK file build spec of interest.
   * @param config the {@link Config} object to calculate the weak fingerprint for
   * @return a weak fingerprint - {@link com.google.common.hash.HashCode} that represent a unique
   *     hash value.
   */
  public static HashCode getWeakFingerprint(Path buildFile, Config config) {
    Hasher hasher = Hashing.sha256().newHasher();
    return hasher
        .putString(buildFile.toString(), StandardCharsets.UTF_8)
        .putBytes(config.getOrderIndependentHashCode().asBytes())
        .putString(Platform.detect().name(), StandardCharsets.UTF_8)
        .putString(Architecture.detect().name(), StandardCharsets.UTF_8)
        .hash();
  }

  private static void addContentHash(ProjectFilesystem fs, Path filePath, Hasher hasher)
      throws IOException {
    hasher.putString(fs.computeSha256(filePath), StandardCharsets.UTF_8);
  }

  private static void addIncludeEntryToFingerprint(
      ProjectFilesystem fs, Hasher hasher, String value) throws IOException {
    Path includePath = fs.getPath(value);
    hasher.putString(fs.relativize(includePath).toString(), StandardCharsets.UTF_8);
    addContentHash(fs, includePath, hasher);
  }

  /**
   * Calculates a strong fingerprint.
   *
   * @param fs the {@Link ProjectFilesystem} that we use to calculate the strong fingerprint.
   * @param includes the list of included build files for which we calculate the strong fingerprint.
   * @return a strong fingerprint - {@Link HashCode} that represent a unique hash value.
   * @throws IOException can throw if there is a problem getting the content of the main BUCK build
   *     spec or an included file.
   */
  public static HashCode getStrongFingerprint(ProjectFilesystem fs, ImmutableList<String> includes)
      throws IOException {
    Hasher hasher = Hashing.sha256().newHasher();

    // Now add the loaded paths.
    ImmutableSortedSet<String> sortedIncludes = ImmutableSortedSet.copyOf(includes);
    for (String value : sortedIncludes) {
      addIncludeEntryToFingerprint(fs, hasher, value);
    }

    return hasher.hash();
  }
}

@@ -4447,17 +4447,17 @@
 s the %7B@
-L
+l
 ink Proj
@@ -4659,17 +4659,17 @@
 int - %7B@
-L
+l
 ink Hash

Fix wrong javadoc tags.