/* * Copyright 2016-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.rules.keys; import com.facebook.buck.hashing.FileHashLoader; import com.facebook.buck.io.ArchiveMemberPath; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildTargetSourcePath; import com.facebook.buck.rules.RuleKey; import com.facebook.buck.rules.RuleKeyAppendable; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; import com.google.common.hash.HashCode; import java.io.IOException; import java.nio.file.Path; /** * A factory for generating {@link RuleKey}s that only take into the account the path of a file and * not the contents(hash) of the file. */ public class ContentAgnosticRuleKeyFactory implements RuleKeyFactory<RuleKey> { private final RuleKeyFieldLoader ruleKeyFieldLoader; private final SourcePathResolver pathResolver; private final SourcePathRuleFinder ruleFinder; private final FileHashLoader fileHashLoader = new FileHashLoader() { @Override public HashCode get(Path path) throws IOException { return HashCode.fromLong(0); } @Override public long getSize(Path path) throws IOException { return 0; } @Override public HashCode get(ArchiveMemberPath archiveMemberPath) throws IOException { throw new AssertionError(); } }; private final SingleBuildRuleKeyCache<RuleKey> ruleKeyCache = new SingleBuildRuleKeyCache<>(); public ContentAgnosticRuleKeyFactory( RuleKeyFieldLoader ruleKeyFieldLoader, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder) { this.ruleKeyFieldLoader = ruleKeyFieldLoader; this.pathResolver = pathResolver; this.ruleFinder = ruleFinder; } private RuleKey calculateBuildRuleKey(BuildRule buildRule) { Builder<HashCode> builder = new Builder<>(RuleKeyBuilder.createDefaultHasher()); ruleKeyFieldLoader.setFields(builder, buildRule, RuleKeyType.CONTENT_AGNOSTIC); return builder.build(RuleKey::new); } private RuleKey calculateAppendableKey(RuleKeyAppendable appendable) { Builder<HashCode> subKeyBuilder = new Builder<>(RuleKeyBuilder.createDefaultHasher()); appendable.appendToRuleKey(subKeyBuilder); return subKeyBuilder.build(RuleKey::new); } @Override public RuleKey build(BuildRule buildRule) { return ruleKeyCache.get(buildRule, this::calculateBuildRuleKey); } private RuleKey buildAppendableKey(RuleKeyAppendable appendable) { return ruleKeyCache.get(appendable, this::calculateAppendableKey); } public class Builder<RULE_KEY> extends RuleKeyBuilder<RULE_KEY> { public Builder(RuleKeyHasher<RULE_KEY> hasher) { super(ruleFinder, pathResolver, fileHashLoader, hasher); } @Override protected RuleKeyBuilder<RULE_KEY> setBuildRule(BuildRule rule) { return setBuildRuleKey(ContentAgnosticRuleKeyFactory.this.build(rule)); } @Override protected RuleKeyBuilder<RULE_KEY> setAppendableRuleKey(RuleKeyAppendable appendable) { return setAppendableRuleKey( ContentAgnosticRuleKeyFactory.this.buildAppendableKey(appendable)); } @Override protected RuleKeyBuilder<RULE_KEY> setSourcePath(SourcePath sourcePath) throws IOException { if (sourcePath instanceof BuildTargetSourcePath) { return setSourcePathAsRule((BuildTargetSourcePath) sourcePath); } else { return setSourcePathDirectly(sourcePath); } } @Override protected RuleKeyBuilder<RULE_KEY> setNonHashingSourcePath(SourcePath sourcePath) { return setNonHashingSourcePathDirectly(sourcePath); } } }