org.gradle.internal.fingerprint.classpath.impl.ClasspathFingerprintingStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2018 the original author or authors.
*
* 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 org.gradle.internal.fingerprint.classpath.impl;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import org.gradle.api.GradleException;
import org.gradle.api.internal.cache.StringInterner;
import org.gradle.api.internal.changedetection.state.ResourceFilter;
import org.gradle.api.internal.changedetection.state.ResourceHasher;
import org.gradle.api.internal.changedetection.state.ResourceSnapshotterCacheService;
import org.gradle.api.internal.changedetection.state.RuntimeClasspathResourceHasher;
import org.gradle.api.internal.changedetection.state.ZipHasher;
import org.gradle.internal.Factory;
import org.gradle.internal.file.FileType;
import org.gradle.internal.fingerprint.FileSystemLocationFingerprint;
import org.gradle.internal.fingerprint.FingerprintHashingStrategy;
import org.gradle.internal.fingerprint.impl.AbstractFingerprintingStrategy;
import org.gradle.internal.fingerprint.impl.DefaultFileSystemLocationFingerprint;
import org.gradle.internal.fingerprint.impl.IgnoredPathFileSystemLocationFingerprint;
import org.gradle.internal.hash.HashCode;
import org.gradle.internal.hash.Hasher;
import org.gradle.internal.hash.Hashing;
import org.gradle.internal.snapshot.DirectorySnapshot;
import org.gradle.internal.snapshot.FileSystemLocationSnapshot;
import org.gradle.internal.snapshot.FileSystemSnapshot;
import org.gradle.internal.snapshot.FileSystemSnapshotVisitor;
import org.gradle.internal.snapshot.RegularFileSnapshot;
import org.gradle.internal.snapshot.RelativePathSegmentsTracker;
import org.gradle.internal.snapshot.RelativePathStringTracker;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.Map;
import static org.gradle.internal.fingerprint.classpath.impl.ClasspathFingerprintingStrategy.NonJarFingerprintingStrategy.IGNORE;
import static org.gradle.internal.fingerprint.classpath.impl.ClasspathFingerprintingStrategy.NonJarFingerprintingStrategy.USE_FILE_HASH;
/**
* Fingerprints classpath-like {@link org.gradle.api.file.FileCollection}s.
*
*
* This strategy uses a {@link ResourceHasher} to normalize the contents of files and a {@link ResourceFilter} to ignore resources in classpath entries. Zip files are treated as if the contents would be expanded on disk.
*
*
*
* The order of the entries in the classpath matters, paths do not matter for the entries.
* For the resources in each classpath entry, normalization takes the relative path of the resource and possibly normalizes its contents.
*
*/
public class ClasspathFingerprintingStrategy extends AbstractFingerprintingStrategy {
private final NonJarFingerprintingStrategy nonZipFingerprintingStrategy;
private final ResourceFilter classpathResourceFilter;
private final ResourceSnapshotterCacheService cacheService;
private final ResourceHasher classpathResourceHasher;
private final ZipHasher zipHasher;
private final StringInterner stringInterner;
private final HashCode zipHasherConfigurationHash;
private ClasspathFingerprintingStrategy(String identifier, NonJarFingerprintingStrategy nonZipFingerprintingStrategy, ResourceHasher classpathResourceHasher, ResourceFilter classpathResourceFilter, ResourceSnapshotterCacheService cacheService, StringInterner stringInterner) {
super(identifier);
this.nonZipFingerprintingStrategy = nonZipFingerprintingStrategy;
this.classpathResourceFilter = classpathResourceFilter;
this.classpathResourceHasher = classpathResourceHasher;
this.cacheService = cacheService;
this.stringInterner = stringInterner;
this.zipHasher = new ZipHasher(classpathResourceHasher, classpathResourceFilter);
Hasher hasher = Hashing.newHasher();
zipHasher.appendConfigurationToHasher(hasher);
this.zipHasherConfigurationHash = hasher.hash();
}
public static ClasspathFingerprintingStrategy runtimeClasspath(ResourceFilter classpathResourceFilter, RuntimeClasspathResourceHasher runtimeClasspathResourceHasher, ResourceSnapshotterCacheService cacheService, StringInterner stringInterner) {
return new ClasspathFingerprintingStrategy("CLASSPATH", USE_FILE_HASH, runtimeClasspathResourceHasher, classpathResourceFilter, cacheService, stringInterner);
}
public static ClasspathFingerprintingStrategy compileClasspath(ResourceHasher classpathResourceHasher, ResourceSnapshotterCacheService cacheService, StringInterner stringInterner) {
return new ClasspathFingerprintingStrategy("COMPILE_CLASSPATH", IGNORE, classpathResourceHasher, ResourceFilter.FILTER_NOTHING, cacheService, stringInterner);
}
@Override
public String normalizePath(FileSystemLocationSnapshot snapshot) {
return "";
}
@Override
public Map collectFingerprints(Iterable extends FileSystemSnapshot> roots) {
ImmutableMap.Builder builder = ImmutableMap.builder();
HashSet processedEntries = new HashSet();
for (FileSystemSnapshot root : roots) {
ClasspathFingerprintVisitor fingerprintVisitor = new ClasspathFingerprintVisitor(processedEntries, builder);
root.accept(new ClasspathContentFingerprintingVisitor(fingerprintVisitor));
}
return builder.build();
}
public enum NonJarFingerprintingStrategy {
IGNORE {
@Nullable
@Override
public HashCode determineNonJarFingerprint(HashCode original) {
return null;
}
},
USE_FILE_HASH {
@Override
public HashCode determineNonJarFingerprint(HashCode original) {
return original;
}
};
@Nullable
public abstract HashCode determineNonJarFingerprint(HashCode original);
}
private class ClasspathContentFingerprintingVisitor implements FileSystemSnapshotVisitor {
private final ClasspathFingerprintVisitor delegate;
private final RelativePathSegmentsTracker relativePathSegmentsTracker = new RelativePathSegmentsTracker();
private final Factory relativePathFactory = new Factory() {
@Override
public String[] create() {
return Iterables.toArray(relativePathSegmentsTracker.getRelativePath(), String.class);
}
};
public ClasspathContentFingerprintingVisitor(ClasspathFingerprintVisitor delegate) {
this.delegate = delegate;
}
@Override
public boolean preVisitDirectory(DirectorySnapshot directorySnapshot) {
relativePathSegmentsTracker.enter(directorySnapshot);
return delegate.preVisitDirectory(directorySnapshot);
}
@Override
public void visitFile(FileSystemLocationSnapshot fileSnapshot) {
if (fileSnapshot instanceof RegularFileSnapshot) {
HashCode normalizedContent = fingerprintFile((RegularFileSnapshot) fileSnapshot);
if (normalizedContent != null) {
delegate.visit(fileSnapshot, normalizedContent);
}
} else if (!relativePathSegmentsTracker.isRoot()) {
throw new GradleException(String.format("Couldn't read file content: '%s'.", fileSnapshot.getAbsolutePath()));
}
}
@Nullable
private HashCode fingerprintFile(RegularFileSnapshot fileSnapshot) {
return relativePathSegmentsTracker.isRoot() ? fingerprintRootFile(fileSnapshot) : fingerprintTreeFile(fileSnapshot);
}
@Nullable
private HashCode fingerprintTreeFile(RegularFileSnapshot fileSnapshot) {
relativePathSegmentsTracker.enter(fileSnapshot);
boolean shouldBeIgnored = classpathResourceFilter.shouldBeIgnored(relativePathFactory);
relativePathSegmentsTracker.leave();
if (shouldBeIgnored) {
return null;
}
return classpathResourceHasher.hash(fileSnapshot);
}
@Override
public void postVisitDirectory(DirectorySnapshot directorySnapshot) {
relativePathSegmentsTracker.leave();
delegate.postVisitDirectory();
}
}
@Nullable
private HashCode fingerprintRootFile(RegularFileSnapshot fileSnapshot) {
if (ZipHasher.isZipFile(fileSnapshot.getName())) {
return fingerprintZipContents(fileSnapshot);
}
return nonZipFingerprintingStrategy.determineNonJarFingerprint(fileSnapshot.getHash());
}
@Nullable
private HashCode fingerprintZipContents(RegularFileSnapshot fileSnapshot) {
return cacheService.hashFile(fileSnapshot, zipHasher, zipHasherConfigurationHash);
}
private class ClasspathFingerprintVisitor {
private final RelativePathStringTracker relativePathStringTracker;
private final HashSet processedEntries;
private final ImmutableMap.Builder builder;
public ClasspathFingerprintVisitor(HashSet processedEntries, ImmutableMap.Builder builder) {
this.processedEntries = processedEntries;
this.builder = builder;
this.relativePathStringTracker = new RelativePathStringTracker();
}
public boolean preVisitDirectory(FileSystemLocationSnapshot directorySnapshot) {
relativePathStringTracker.enter(directorySnapshot);
return true;
}
public void visit(FileSystemLocationSnapshot fileSnapshot, HashCode normalizedContentHash) {
String absolutePath = fileSnapshot.getAbsolutePath();
if (processedEntries.add(absolutePath)) {
FileSystemLocationFingerprint fingerprint = relativePathStringTracker.isRoot() ? IgnoredPathFileSystemLocationFingerprint.create(fileSnapshot.getType(), normalizedContentHash) : createFileFingerprint(fileSnapshot, normalizedContentHash);
builder.put(
absolutePath,
fingerprint);
}
}
private FileSystemLocationFingerprint createFileFingerprint(FileSystemLocationSnapshot snapshot, HashCode content) {
relativePathStringTracker.enter(snapshot);
FileSystemLocationFingerprint fingerprint = new DefaultFileSystemLocationFingerprint(stringInterner.intern(relativePathStringTracker.getRelativePathString()), FileType.RegularFile, content);
relativePathStringTracker.leave();
return fingerprint;
}
public void postVisitDirectory() {
relativePathStringTracker.leave();
}
}
@Override
public FingerprintHashingStrategy getHashingStrategy() {
return FingerprintHashingStrategy.KEEP_ORDER;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy