mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
introduce BuildTargetHashSupplier (simplify build target fingerprint calculation)
GitOrigin-RevId: f810aed3a678cb36212d68c7539f6893bbe68cf2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
81e490cd6f
commit
e3af69868a
@@ -56,11 +56,11 @@ public abstract class BuildTarget<R extends BuildRootDescriptor> {
|
||||
* Allows the build target to tag the current project settings relevant to the build of this target
|
||||
* (e.g., the language level of a Java module) so that the target is fully recompiled when those settings change.
|
||||
*
|
||||
* @param pd the complete state of a compilation invocation
|
||||
* @param projectDescriptor the complete state of a compilation invocation
|
||||
* @param out the print writer to which the project settings can be written (the settings are compared with the ones
|
||||
* written during the invocation of the same method in a previous compilation).
|
||||
*/
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor pd, @NotNull PrintWriter out) {
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor projectDescriptor, @NotNull PrintWriter out) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.builders
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.Internal
|
||||
interface BuildTargetHashSupplier {
|
||||
fun computeConfigurationDigest(projectDescriptor: ProjectDescriptor, hash: HashSink)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64
|
||||
import com.dynatrace.hash4j.hashing.HashSink
|
||||
import com.dynatrace.hash4j.hashing.Hashing
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
@@ -15,11 +15,15 @@ import java.nio.file.StandardOpenOption
|
||||
|
||||
@Internal
|
||||
@Throws(IOException::class)
|
||||
fun getFileHash(file: Path): Long = getFileHash(file, Hashing.komihash5_0().hashStream())
|
||||
fun getFileHash(file: Path): Long {
|
||||
val hash = Hashing.komihash5_0().hashStream()
|
||||
getFileHash(file, hash)
|
||||
return hash.asLong
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Throws(IOException::class)
|
||||
fun getFileHash(file: Path, hash: HashStream64): Long {
|
||||
fun getFileHash(file: Path, hash: HashSink) {
|
||||
FileChannel.open(file, StandardOpenOption.READ).use { channel ->
|
||||
val fileSize = channel.size()
|
||||
val buffer = ByteBuffer.allocate(256 * 1024)
|
||||
@@ -36,13 +40,12 @@ fun getFileHash(file: Path, hash: HashStream64): Long {
|
||||
offset += readBytes
|
||||
}
|
||||
hash.putLong(fileSize)
|
||||
return hash.asLong
|
||||
}
|
||||
}
|
||||
|
||||
/** path must be absolute ([Path.toAbsolutePath]), normalized ([Path.normalize]) and system-independent */
|
||||
@Internal
|
||||
fun normalizedPathHashCode(path: String, hash: HashStream64) {
|
||||
fun normalizedPathHashCode(path: String, hash: HashSink) {
|
||||
if (path.isEmpty()) {
|
||||
hash.putInt(0)
|
||||
return
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.FileCollectionFactory;
|
||||
@@ -11,10 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.builders.BuildTarget;
|
||||
import org.jetbrains.jps.builders.BuildTargetRegistry;
|
||||
import org.jetbrains.jps.builders.ModuleBasedTarget;
|
||||
import org.jetbrains.jps.builders.TargetOutputIndex;
|
||||
import org.jetbrains.jps.builders.*;
|
||||
import org.jetbrains.jps.builders.java.ExcludedJavaSourceRootProvider;
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
|
||||
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
|
||||
@@ -34,7 +31,10 @@ import org.jetbrains.jps.model.module.JpsModuleDependency;
|
||||
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@@ -49,7 +49,7 @@ import static org.jetbrains.jps.incremental.FileHashUtilKt.normalizedPathHashCod
|
||||
* Describes a step of compilation process which produces JVM *.class files from files in production/test source roots of a Java module.
|
||||
* These targets are built by {@link ModuleLevelBuilder} and they are the only targets that can have circular dependencies on each other.
|
||||
*/
|
||||
public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRootDescriptor> {
|
||||
public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRootDescriptor> implements BuildTargetHashSupplier {
|
||||
private static final Logger LOG = Logger.getInstance(ModuleBuildTarget.class);
|
||||
|
||||
public static final Boolean REBUILD_ON_DEPENDENCY_CHANGE = Boolean.valueOf(
|
||||
@@ -173,17 +173,15 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor pd, @NotNull PrintWriter out) {
|
||||
public void computeConfigurationDigest(@NotNull ProjectDescriptor projectDescriptor, @NotNull HashSink hash) {
|
||||
JpsModule module = getModule();
|
||||
PathRelativizerService relativizer = pd.dataManager.getRelativizer();
|
||||
PathRelativizerService relativizer = projectDescriptor.dataManager.getRelativizer();
|
||||
|
||||
StringBuilder logBuilder = LOG.isDebugEnabled() ? new StringBuilder() : null;
|
||||
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
|
||||
getDependenciesFingerprint(logBuilder, relativizer, hash);
|
||||
|
||||
List<JavaSourceRootDescriptor> roots = pd.getBuildRootIndex().getTargetRoots(this, null);
|
||||
List<JavaSourceRootDescriptor> roots = projectDescriptor.getBuildRootIndex().getTargetRoots(this, null);
|
||||
for (JavaSourceRootDescriptor root : roots) {
|
||||
String path = relativizer.toRelative(root.rootFile.toString());
|
||||
if (logBuilder != null) {
|
||||
@@ -216,7 +214,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
hash.putString(bytecodeTarget);
|
||||
}
|
||||
|
||||
CompilerEncodingConfiguration encodingConfig = pd.getEncodingConfiguration();
|
||||
CompilerEncodingConfiguration encodingConfig = projectDescriptor.getEncodingConfiguration();
|
||||
String encoding = encodingConfig.getPreferredModuleEncoding(module);
|
||||
if (encoding == null) {
|
||||
hash.putInt(0);
|
||||
@@ -228,13 +226,11 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
hash.putString(encoding);
|
||||
}
|
||||
|
||||
String hashString = Long.toUnsignedString(hash.getAsLong(), Character.MAX_RADIX);
|
||||
out.write(hashString);
|
||||
if (logBuilder == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Path configurationTextFile = pd.getTargetsState().getDataPaths().getTargetDataRoot(this).toPath().resolve("config.dat.debug.txt");
|
||||
Path configurationTextFile = projectDescriptor.getTargetsState().getDataPaths().getTargetDataRoot(this).toPath().resolve("config.dat.debug.txt");
|
||||
@NonNls String oldText;
|
||||
try {
|
||||
oldText = Files.readString(configurationTextFile);
|
||||
@@ -244,9 +240,9 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
}
|
||||
String newText = logBuilder.toString();
|
||||
if (!newText.equals(oldText)) {
|
||||
if (oldText != null) {
|
||||
if (oldText != null && hash instanceof HashStream64) {
|
||||
LOG.debug("Configuration differs from the last recorded one for " + getPresentableName() + ".\nRecorded configuration:\n" + oldText +
|
||||
"\nCurrent configuration (hash=" + hashString + "):\n" + newText);
|
||||
"\nCurrent configuration (hash=" + ((HashStream64)hash).getAsLong() + "):\n" + newText);
|
||||
}
|
||||
try {
|
||||
Files.createDirectories(configurationTextFile.getParent());
|
||||
@@ -260,7 +256,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
|
||||
private void getDependenciesFingerprint(@Nullable StringBuilder logBuilder,
|
||||
@NotNull PathRelativizerService relativizer,
|
||||
@NotNull HashStream64 hash) {
|
||||
@NotNull HashSink hash) {
|
||||
if (!REBUILD_ON_DEPENDENCY_CHANGE) {
|
||||
hash.putInt(0);
|
||||
return;
|
||||
@@ -282,7 +278,9 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
if (logBuilder != null) {
|
||||
logBuilder.append(path);
|
||||
// not a content hash, but the current hash value
|
||||
logBuilder.append(": ").append(hash.getAsLong());
|
||||
if (hash instanceof HashStream64) {
|
||||
logBuilder.append(": ").append((((HashStream64)hash).getAsLong()));
|
||||
}
|
||||
logBuilder.append("\n");
|
||||
}
|
||||
normalizedPathHashCode(path, hash);
|
||||
@@ -290,7 +288,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
hash.putInt(roots.size());
|
||||
}
|
||||
|
||||
private static void getContentHash(Path file, HashStream64 hash) {
|
||||
private static void getContentHash(Path file, HashSink hash) {
|
||||
if (!ProjectStamps.TRACK_LIBRARY_CONTENT) {
|
||||
hash.putInt(0);
|
||||
return;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.BuildTarget;
|
||||
import org.jetbrains.jps.builders.BuildTargetHashSupplier;
|
||||
import org.jetbrains.jps.builders.BuildTargetRegistry;
|
||||
import org.jetbrains.jps.builders.TargetOutputIndex;
|
||||
import org.jetbrains.jps.builders.java.ExcludedJavaSourceRootProvider;
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -37,7 +36,7 @@ import static org.jetbrains.jps.incremental.FileHashUtilKt.normalizedPathHashCod
|
||||
/**
|
||||
* Describes a step of compilation process which copies resource's files from source and resource roots of a Java module.
|
||||
*/
|
||||
public final class ResourcesTarget extends JVMModuleBuildTarget<ResourceRootDescriptor> {
|
||||
public final class ResourcesTarget extends JVMModuleBuildTarget<ResourceRootDescriptor> implements BuildTargetHashSupplier {
|
||||
private final @NotNull ResourcesTargetType targetType;
|
||||
|
||||
public ResourcesTarget(@NotNull JpsModule module, @NotNull ResourcesTargetType targetType) {
|
||||
@@ -115,8 +114,7 @@ public final class ResourcesTarget extends JVMModuleBuildTarget<ResourceRootDesc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor projectDescriptor, @NotNull PrintWriter out) {
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
public void computeConfigurationDigest(@NotNull ProjectDescriptor projectDescriptor, @NotNull HashSink hash) {
|
||||
PathRelativizerService relativizer = projectDescriptor.dataManager.getRelativizer();
|
||||
|
||||
List<ResourceRootDescriptor> roots = projectDescriptor.getBuildRootIndex().getTargetRoots(this, null);
|
||||
@@ -126,7 +124,5 @@ public final class ResourcesTarget extends JVMModuleBuildTarget<ResourceRootDesc
|
||||
hash.putString(root.getPackagePrefix());
|
||||
}
|
||||
hash.putInt(roots.size());
|
||||
|
||||
out.write(Long.toUnsignedString(hash.getAsLong(), Character.MAX_RADIX));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -21,22 +7,22 @@ import org.jetbrains.jps.builders.BuildTargetType;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
|
||||
|
||||
public abstract class ArtifactBasedBuildTarget extends BuildTarget<ArtifactRootDescriptor> {
|
||||
private final JpsArtifact myArtifact;
|
||||
private final JpsArtifact artifact;
|
||||
|
||||
protected ArtifactBasedBuildTarget(@NotNull BuildTargetType<? extends BuildTarget<ArtifactRootDescriptor>> targetType, @NotNull JpsArtifact artifact) {
|
||||
protected ArtifactBasedBuildTarget(@NotNull BuildTargetType<? extends BuildTarget<ArtifactRootDescriptor>> targetType,
|
||||
@NotNull JpsArtifact artifact) {
|
||||
super(targetType);
|
||||
myArtifact = artifact;
|
||||
this.artifact = artifact;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getId() {
|
||||
return myArtifact.getName();
|
||||
return artifact.getName();
|
||||
}
|
||||
|
||||
public JpsArtifact getArtifact() {
|
||||
return myArtifact;
|
||||
return artifact;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,11 +30,11 @@ public abstract class ArtifactBasedBuildTarget extends BuildTarget<ArtifactRootD
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
return myArtifact.equals(((ArtifactBasedBuildTarget)o).myArtifact);
|
||||
return artifact.equals(((ArtifactBasedBuildTarget)o).artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myArtifact.hashCode();
|
||||
return artifact.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.Strings;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -22,11 +21,10 @@ import org.jetbrains.jps.model.artifact.JpsArtifact;
|
||||
import org.jetbrains.jps.model.artifact.elements.JpsArtifactOutputPackagingElement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ArtifactBuildTarget extends ArtifactBasedBuildTarget {
|
||||
public final class ArtifactBuildTarget extends ArtifactBasedBuildTarget implements BuildTargetHashSupplier {
|
||||
public ArtifactBuildTarget(@NotNull JpsArtifact artifact) {
|
||||
super(ArtifactBuildTargetType.INSTANCE, artifact);
|
||||
}
|
||||
@@ -62,18 +60,16 @@ public final class ArtifactBuildTarget extends ArtifactBasedBuildTarget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor pd, @NotNull PrintWriter out) {
|
||||
PathRelativizerService relativizer = pd.dataManager.getRelativizer();
|
||||
public void computeConfigurationDigest(@NotNull ProjectDescriptor projectDescriptor, @NotNull HashSink hash) {
|
||||
PathRelativizerService relativizer = projectDescriptor.dataManager.getRelativizer();
|
||||
String outputPath = getArtifact().getOutputPath();
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
hash.putString(Strings.isEmpty(outputPath) ? "" : relativizer.toRelative(outputPath));
|
||||
BuildRootIndex rootIndex = pd.getBuildRootIndex();
|
||||
BuildRootIndex rootIndex = projectDescriptor.getBuildRootIndex();
|
||||
List<ArtifactRootDescriptor> targetRoots = rootIndex.getTargetRoots(this, null);
|
||||
for (ArtifactRootDescriptor descriptor : targetRoots) {
|
||||
descriptor.writeConfiguration(hash, relativizer);
|
||||
}
|
||||
hash.putInt(targetRoots.size());
|
||||
out.write(Long.toUnsignedString(hash.getAsLong(), Character.MAX_RADIX));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.BuildOutputConsumer;
|
||||
@@ -43,7 +43,7 @@ public abstract class ArtifactRootDescriptor extends BuildRootDescriptor {
|
||||
|
||||
protected abstract String getFullPath();
|
||||
|
||||
public void writeConfiguration(@NotNull HashStream64 hash, PathRelativizerService relativizer) {
|
||||
public void writeConfiguration(@NotNull HashSink hash, PathRelativizerService relativizer) {
|
||||
hash.putString(relativizer.toRelative(getFullPath()));
|
||||
hash.putString(relativizer.toRelative(myDestinationInfo.getOutputPath()));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.io.FileFilters;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -49,7 +49,7 @@ public final class FileBasedArtifactRootDescriptor extends ArtifactRootDescripto
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull HashStream64 hash, PathRelativizerService relativizer) {
|
||||
public void writeConfiguration(@NotNull HashSink hash, PathRelativizerService relativizer) {
|
||||
super.writeConfiguration(hash, relativizer);
|
||||
myCopyingHandler.writeConfiguration(hash);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.util.io.FileFilters;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @see ArtifactRootCopyingHandlerProvider
|
||||
@@ -21,12 +19,12 @@ public abstract class FileCopyingHandler {
|
||||
public abstract void copyFile(@NotNull File from, @NotNull File to, @NotNull CompileContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Write configuration on which this handler depends. If the output produced by this method changes, the corresponding artifact will be rebuilt
|
||||
* from the scratch.
|
||||
* Write configuration on which this handler depends.
|
||||
* If the output produced by this method changes, the corresponding artifact will be rebuilt from scratch.
|
||||
*
|
||||
* @see org.jetbrains.jps.builders.BuildTarget#writeConfiguration(ProjectDescriptor, PrintWriter)
|
||||
* @see org.jetbrains.jps.builders.BuildTargetHashSupplier
|
||||
*/
|
||||
public abstract void writeConfiguration(@NotNull HashStream64 hash);
|
||||
public abstract void writeConfiguration(@NotNull HashSink hash);
|
||||
|
||||
public @NotNull FileFilter createFileFilter() {
|
||||
return FileFilters.EVERYTHING;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.artifacts.instructions;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.util.io.FileFilters;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -28,7 +28,7 @@ public class FilterCopyHandler extends FileCopyingHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull HashStream64 hash) { }
|
||||
public void writeConfiguration(@NotNull HashSink hash) { }
|
||||
|
||||
@Override
|
||||
public @NotNull FileFilter createFileFilter() {
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.storage;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FileCollectionFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.BuildTarget;
|
||||
import org.jetbrains.jps.builders.BuildTargetHashSupplier;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.GlobalContextKey;
|
||||
@@ -18,7 +20,13 @@ import org.jetbrains.jps.incremental.ModuleBuildTarget;
|
||||
import org.jetbrains.jps.incremental.relativizer.PathRelativizerService;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public final class BuildTargetConfiguration {
|
||||
@@ -28,66 +36,67 @@ public final class BuildTargetConfiguration {
|
||||
private static final GlobalContextKey<Set<File>> ALL_DELETED_ROOTS_KEY = GlobalContextKey.create("_all_deleted_output_roots_");
|
||||
private static final String DIRTY_MARK = "$dirty_mark$";
|
||||
|
||||
private final BuildTarget<?> myTarget;
|
||||
private final BuildTarget<?> target;
|
||||
private final BuildTargetsState myTargetsState;
|
||||
private String myConfiguration;
|
||||
private volatile String myCurrentState;
|
||||
private @NotNull String configuration;
|
||||
private volatile String currentState;
|
||||
|
||||
public BuildTargetConfiguration(BuildTarget<?> target, BuildTargetsState targetsState) {
|
||||
myTarget = target;
|
||||
this.target = target;
|
||||
myTargetsState = targetsState;
|
||||
myConfiguration = load();
|
||||
configuration = load();
|
||||
}
|
||||
|
||||
private String load() {
|
||||
File configFile = getConfigFile();
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
return new String(FileUtil.loadFileText(configFile));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info("Cannot load configuration of " + myTarget);
|
||||
}
|
||||
private @NotNull String load() {
|
||||
try {
|
||||
return Files.readString(getConfigFile());
|
||||
}
|
||||
catch (NoSuchFileException ignore) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info("Cannot load configuration of " + target);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isTargetDirty(@NotNull ProjectDescriptor pd) {
|
||||
return DIRTY_MARK.equals(myConfiguration) || !getCurrentState(pd).equals(myConfiguration);
|
||||
public boolean isTargetDirty(@NotNull ProjectDescriptor projectDescriptor) {
|
||||
return DIRTY_MARK.equals(configuration) || !getCurrentState(projectDescriptor).equals(configuration);
|
||||
}
|
||||
|
||||
public void logDiagnostics(CompileContext context) {
|
||||
if (DIRTY_MARK.equals(myConfiguration)) {
|
||||
if (DIRTY_MARK.equals(configuration)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(myTarget + " has been marked dirty in the previous compilation session");
|
||||
LOG.debug(target + " has been marked dirty in the previous compilation session");
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String currentState = getCurrentState(context.getProjectDescriptor());
|
||||
if (!currentState.equals(myConfiguration)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(myTarget + " configuration was changed:");
|
||||
LOG.debug("Old:");
|
||||
LOG.debug(myConfiguration);
|
||||
LOG.debug("New:");
|
||||
LOG.debug(currentState);
|
||||
LOG.debug(myTarget + " will be recompiled");
|
||||
}
|
||||
if (myTarget instanceof ModuleBuildTarget) {
|
||||
final JpsModule module = ((ModuleBuildTarget)myTarget).getModule();
|
||||
synchronized (MODULES_WITH_TARGET_CONFIG_CHANGED_KEY) {
|
||||
Set<JpsModule> modules = MODULES_WITH_TARGET_CONFIG_CHANGED_KEY.get(context);
|
||||
if (modules == null) {
|
||||
MODULES_WITH_TARGET_CONFIG_CHANGED_KEY.set(context, modules = new HashSet<>());
|
||||
}
|
||||
modules.add(module);
|
||||
String currentState = getCurrentState(context.getProjectDescriptor());
|
||||
if (currentState.equals(configuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(target + " configuration was changed:");
|
||||
LOG.debug("Old:");
|
||||
LOG.debug(configuration);
|
||||
LOG.debug("New:");
|
||||
LOG.debug(currentState);
|
||||
LOG.debug(target + " will be recompiled");
|
||||
}
|
||||
if (target instanceof ModuleBuildTarget) {
|
||||
final JpsModule module = ((ModuleBuildTarget)target).getModule();
|
||||
synchronized (MODULES_WITH_TARGET_CONFIG_CHANGED_KEY) {
|
||||
Set<JpsModule> modules = MODULES_WITH_TARGET_CONFIG_CHANGED_KEY.get(context);
|
||||
if (modules == null) {
|
||||
MODULES_WITH_TARGET_CONFIG_CHANGED_KEY.set(context, modules = new HashSet<>());
|
||||
}
|
||||
modules.add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void save(CompileContext context) {
|
||||
public void save(@NotNull CompileContext context) {
|
||||
persist(getCurrentState(context.getProjectDescriptor()));
|
||||
}
|
||||
|
||||
@@ -95,64 +104,70 @@ public final class BuildTargetConfiguration {
|
||||
persist(DIRTY_MARK);
|
||||
}
|
||||
|
||||
private void persist(final String data) {
|
||||
private void persist(@NotNull String data) {
|
||||
try {
|
||||
File configFile = getConfigFile();
|
||||
FileUtil.createParentDirs(configFile);
|
||||
try (Writer out = new BufferedWriter(new FileWriter(configFile))) {
|
||||
out.write(data);
|
||||
myConfiguration = data;
|
||||
}
|
||||
Path configFile = getConfigFile();
|
||||
Files.createDirectories(configFile.getParent());
|
||||
Files.writeString(configFile, data);
|
||||
configuration = data;
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info("Cannot save configuration of " + myConfiguration, e);
|
||||
LOG.info("Cannot save configuration of " + configuration, e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getConfigFile() {
|
||||
return new File(myTargetsState.getDataPaths().getTargetDataRoot(myTarget), "config.dat");
|
||||
private Path getConfigFile() {
|
||||
return myTargetsState.getDataPaths().getTargetDataRoot(target).toPath().resolve("config.dat");
|
||||
}
|
||||
|
||||
private File getNonexistentOutputsFile() {
|
||||
return new File(myTargetsState.getDataPaths().getTargetDataRoot(myTarget), "nonexistent-outputs.dat");
|
||||
private Path getNonexistentOutputsFile() {
|
||||
return myTargetsState.getDataPaths().getTargetDataRoot(target).toPath().resolve("nonexistent-outputs.dat");
|
||||
}
|
||||
|
||||
private @NotNull String getCurrentState(@NotNull ProjectDescriptor pd) {
|
||||
String state = myCurrentState;
|
||||
if (state == null) {
|
||||
myCurrentState = state = saveToString(pd);
|
||||
String state = currentState;
|
||||
if (state != null) {
|
||||
return state;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
private @NotNull String saveToString(@NotNull ProjectDescriptor pd) {
|
||||
StringWriter out = new StringWriter();
|
||||
myTarget.writeConfiguration(pd, new PrintWriter(out));
|
||||
return out.toString();
|
||||
if (target instanceof BuildTargetHashSupplier) {
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
((BuildTargetHashSupplier)target).computeConfigurationDigest(pd, hash);
|
||||
state = Long.toUnsignedString(hash.getAsLong(), Character.MAX_RADIX);
|
||||
}
|
||||
else {
|
||||
StringWriter out = new StringWriter();
|
||||
target.writeConfiguration(pd, new PrintWriter(out));
|
||||
state = out.toString();
|
||||
}
|
||||
currentState = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
public void storeNonexistentOutputRoots(CompileContext context) throws IOException {
|
||||
PathRelativizerService relativizer = context.getProjectDescriptor().dataManager.getRelativizer();
|
||||
Collection<File> outputRoots = myTarget.getOutputRoots(context);
|
||||
List<String> nonexistentOutputRoots = new SmartList<>();
|
||||
Collection<File> outputRoots = target.getOutputRoots(context);
|
||||
List<String> nonexistentOutputRoots = new ArrayList<>();
|
||||
for (File root : outputRoots) {
|
||||
if (!root.exists()) {
|
||||
nonexistentOutputRoots.add(relativizer.toRelative(root.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
File file = getNonexistentOutputsFile();
|
||||
|
||||
Path file = getNonexistentOutputsFile();
|
||||
if (nonexistentOutputRoots.isEmpty()) {
|
||||
file.delete();
|
||||
Files.deleteIfExists(file);
|
||||
}
|
||||
else {
|
||||
FileUtil.writeToFile(file, StringUtil.join(nonexistentOutputRoots, "\n"));
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.writeString(file, String.join("\n", nonexistentOutputRoots));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean outputRootWasDeleted(CompileContext context) throws IOException {
|
||||
List<String> nonexistentOutputRoots = new SmartList<>();
|
||||
List<String> nonexistentOutputRoots = new ArrayList<>();
|
||||
|
||||
final Collection<File> targetRoots = myTarget.getOutputRoots(context);
|
||||
final Collection<File> targetRoots = target.getOutputRoots(context);
|
||||
synchronized (ALL_DELETED_ROOTS_KEY) {
|
||||
Set<File> allDeletedRoots = ALL_DELETED_ROOTS_KEY.get(context);
|
||||
for (File outputRoot : targetRoots) {
|
||||
@@ -168,7 +183,7 @@ public final class BuildTargetConfiguration {
|
||||
}
|
||||
}
|
||||
if (wasDeleted) {
|
||||
nonexistentOutputRoots.add(FileUtil.toSystemIndependentName(outputRoot.getAbsolutePath()));
|
||||
nonexistentOutputRoots.add(FileUtilRt.toSystemIndependentName(outputRoot.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,14 +193,13 @@ public final class BuildTargetConfiguration {
|
||||
}
|
||||
|
||||
Set<String> storedNonExistentOutputs;
|
||||
File file = getNonexistentOutputsFile();
|
||||
if (!file.exists()) {
|
||||
storedNonExistentOutputs = Collections.emptySet();
|
||||
Path file = getNonexistentOutputsFile();
|
||||
if (Files.notExists(file)) {
|
||||
storedNonExistentOutputs = Set.of();
|
||||
}
|
||||
else {
|
||||
PathRelativizerService relativizer = context.getProjectDescriptor().dataManager.getRelativizer();
|
||||
List<String> lines = ContainerUtil.map(StringUtil.split(FileUtil.loadFile(file), "\n"),
|
||||
s -> relativizer.toFull(s));
|
||||
List<String> lines = ContainerUtil.map(StringUtil.split(Files.readString(file), "\n"), s -> relativizer.toFull(s));
|
||||
storedNonExistentOutputs = CollectionFactory.createFilePathSet(lines);
|
||||
}
|
||||
return !storedNonExistentOutputs.containsAll(nonexistentOutputRoots);
|
||||
|
||||
@@ -334,7 +334,8 @@ public final class BuildTargetSourcesState implements BuildListener {
|
||||
|
||||
private static long getOutputFileHash(@NotNull Path file, @NotNull Path rootPath, @NotNull HashStream64 hashToReuse) throws IOException {
|
||||
// reduce GC - reuse hashToReuse - do not inline fileHash variable
|
||||
long fileHash = FileHashUtilKt.getFileHash(file, hashToReuse);
|
||||
FileHashUtilKt.getFileHash(file, hashToReuse.reset());
|
||||
long fileHash = hashToReuse.getAsLong();
|
||||
return hashToReuse
|
||||
.reset()
|
||||
.putLong(fileHash)
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
package com.intellij.devkit.runtimeModuleRepository.jps.build
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64
|
||||
import com.dynatrace.hash4j.hashing.Hashing
|
||||
import com.dynatrace.hash4j.hashing.HashSink
|
||||
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME
|
||||
import com.intellij.devkit.runtimeModuleRepository.jps.impl.DevkitRuntimeModuleRepositoryJpsBundle
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
@@ -26,10 +25,11 @@ import org.jetbrains.jps.model.module.JpsModuleReference
|
||||
import org.jetbrains.jps.model.serialization.JpsModelSerializationDataService
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
internal class RuntimeModuleRepositoryTarget(val project: JpsProject) : BuildTarget<BuildRootDescriptor?>(RuntimeModuleRepositoryTarget) {
|
||||
internal class RuntimeModuleRepositoryTarget(
|
||||
val project: JpsProject,
|
||||
) : BuildTarget<BuildRootDescriptor>(RuntimeModuleRepositoryTarget), BuildTargetHashSupplier {
|
||||
override fun getId(): String {
|
||||
return "project"
|
||||
}
|
||||
@@ -72,54 +72,52 @@ internal class RuntimeModuleRepositoryTarget(val project: JpsProject) : BuildTar
|
||||
return java.util.List.of(File(JpsPathUtil.urlToFile(outputUrl), JAR_REPOSITORY_FILE_NAME))
|
||||
}
|
||||
|
||||
override fun writeConfiguration(pd: ProjectDescriptor, out: PrintWriter) {
|
||||
val digest: Long
|
||||
override fun computeConfigurationDigest(projectDescriptor: ProjectDescriptor, hash: HashSink) {
|
||||
hash.putString(JarFileSerializer.SPECIFICATION_VERSION)
|
||||
hash.putInt(RuntimeModuleRepositoryBuildConstants.GENERATOR_VERSION)
|
||||
|
||||
val time = measureTimeMillis {
|
||||
digest = computeDependenciesDigest(pd)
|
||||
computeDependenciesDigest(projectDescriptor, hash)
|
||||
}
|
||||
LOG.info("Dependencies digest computed in ${time}ms")
|
||||
out.println("${JarFileSerializer.SPECIFICATION_VERSION}.${RuntimeModuleRepositoryBuildConstants.GENERATOR_VERSION}")
|
||||
out.println(java.lang.Long.toUnsignedString(digest, Character.MAX_RADIX))
|
||||
}
|
||||
|
||||
private fun computeDependenciesDigest(pd: ProjectDescriptor): Long {
|
||||
val digest = Hashing.komihash5_0().hashStream()
|
||||
private fun computeDependenciesDigest(pd: ProjectDescriptor, hash: HashSink) {
|
||||
val relativizer = pd.dataManager.relativizer
|
||||
|
||||
val modules = pd.project.modules
|
||||
for (module in modules) {
|
||||
digest.putString(module.name)
|
||||
hash.putString(module.name)
|
||||
val sourceRoots = module.sourceRoots
|
||||
for (sourceRoot in sourceRoots) {
|
||||
digest.putString(relativizer.toRelative(sourceRoot.path.toString()))
|
||||
hash.putString(relativizer.toRelative(sourceRoot.path.toString()))
|
||||
}
|
||||
digest.putInt(sourceRoots.size)
|
||||
hash.putInt(sourceRoots.size)
|
||||
|
||||
var counter = 0
|
||||
RuntimeModuleRepositoryBuilder.enumerateRuntimeDependencies(module).processModuleAndLibraries(
|
||||
{
|
||||
digest.putString(it.name)
|
||||
hash.putString(it.name)
|
||||
counter++
|
||||
},
|
||||
{ library ->
|
||||
digest.putString(library.name)
|
||||
hash.putString(library.name)
|
||||
if (library.createReference().parentReference is JpsModuleReference) {
|
||||
updateFromRoots(library, digest, relativizer)
|
||||
updateFromRoots(library, hash, relativizer)
|
||||
}
|
||||
counter++
|
||||
},
|
||||
)
|
||||
digest.putInt(counter)
|
||||
hash.putInt(counter)
|
||||
}
|
||||
digest.putInt(modules.size)
|
||||
hash.putInt(modules.size)
|
||||
|
||||
val libraries = pd.project.libraryCollection.libraries
|
||||
for (library in libraries) {
|
||||
digest.putString(library.name)
|
||||
updateFromRoots(library, digest, relativizer)
|
||||
hash.putString(library.name)
|
||||
updateFromRoots(library, hash, relativizer)
|
||||
}
|
||||
digest.putInt(libraries.size)
|
||||
return digest.asLong
|
||||
hash.putInt(libraries.size)
|
||||
}
|
||||
|
||||
companion object : BuildTargetType<RuntimeModuleRepositoryTarget?>(RuntimeModuleRepositoryBuildConstants.TARGET_TYPE_ID), ModuleInducedTargetType {
|
||||
@@ -152,7 +150,7 @@ internal class RuntimeModuleRepositoryTarget(val project: JpsProject) : BuildTar
|
||||
return project.modules.any { it.name == "intellij.idea.community.main" || it.name == "intellij.platform.commercial" }
|
||||
}
|
||||
|
||||
private fun updateFromRoots(library: JpsLibrary, digest: HashStream64, relativizer: PathRelativizerService) {
|
||||
private fun updateFromRoots(library: JpsLibrary, digest: HashSink, relativizer: PathRelativizerService) {
|
||||
val roots = library.getRoots(JpsOrderRootType.COMPILED)
|
||||
for (root in roots) {
|
||||
digest.putString(relativizer.toRelative(JpsPathUtil.urlToPath(root.url)))
|
||||
|
||||
@@ -48,5 +48,7 @@
|
||||
<orderEntry type="library" name="opentelemetry" level="project" />
|
||||
<orderEntry type="library" name="opentelemetry-semconv" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.observation" />
|
||||
<orderEntry type="library" name="hash4j" level="project" />
|
||||
<orderEntry type="library" name="fastutil-min" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -73,7 +73,6 @@
|
||||
|
||||
<compiler.updateResourcesBuildContributor
|
||||
implementation="org.jetbrains.plugins.gradle.execution.build.GradleUpdateResourcesBuildContributor"/>
|
||||
<projectService serviceImplementation="org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator"/>
|
||||
<compiler.task execute="BEFORE" implementation="org.jetbrains.plugins.gradle.config.GradleResourceConfigurationGeneratorCompileTask"/>
|
||||
|
||||
<attachSourcesProvider implementation="org.jetbrains.plugins.gradle.action.GradleAttachSourcesProvider"/>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.config;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory;
|
||||
import com.intellij.openapi.components.Service;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemExecutionAware;
|
||||
@@ -28,6 +31,7 @@ import com.intellij.util.PathMapper;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -45,27 +49,24 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
public class GradleResourceCompilerConfigurationGenerator {
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
@Service(Service.Level.PROJECT)
|
||||
public final class GradleResourceCompilerConfigurationGenerator {
|
||||
private static final Logger LOG = Logger.getInstance(GradleResourceCompilerConfigurationGenerator.class);
|
||||
|
||||
private final @NotNull Project myProject;
|
||||
private final @NotNull Map<String, Integer> myModulesConfigurationHash;
|
||||
private final @NotNull Map<String, Long> modulesConfigurationHash = new ConcurrentHashMap<>();
|
||||
private final ExternalProjectDataCache externalProjectDataCache;
|
||||
|
||||
public GradleResourceCompilerConfigurationGenerator(final @NotNull Project project) {
|
||||
myProject = project;
|
||||
myModulesConfigurationHash = new ConcurrentHashMap<>();
|
||||
externalProjectDataCache = ExternalProjectDataCache.getInstance(project);
|
||||
assert externalProjectDataCache != null;
|
||||
|
||||
project.getMessageBus().connect().subscribe(ModuleListener.TOPIC, new ModuleListener() {
|
||||
@Override
|
||||
public void moduleRemoved(@NotNull Project project, @NotNull Module module) {
|
||||
myModulesConfigurationHash.remove(module.getName());
|
||||
modulesConfigurationHash.remove(module.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,40 +80,40 @@ public class GradleResourceCompilerConfigurationGenerator {
|
||||
});
|
||||
}
|
||||
|
||||
public void generateBuildConfiguration(final @NotNull CompileContext context) {
|
||||
public void generateBuildConfiguration(@NotNull CompileContext context) {
|
||||
if (shouldBeBuiltByExternalSystem(myProject) || !hasGradleModules(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldBeBuiltByExternalSystem(myProject)) return;
|
||||
BuildManager buildManager = BuildManager.getInstance();
|
||||
File projectSystemDir = buildManager.getProjectSystemDirectory(myProject);
|
||||
|
||||
if (!hasGradleModules(context)) return;
|
||||
File gradleConfigFile = new File(projectSystemDir, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH);
|
||||
|
||||
final BuildManager buildManager = BuildManager.getInstance();
|
||||
final File projectSystemDir = buildManager.getProjectSystemDirectory(myProject);
|
||||
|
||||
final File gradleConfigFile = new File(projectSystemDir, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH);
|
||||
|
||||
final Map<String, GradleModuleResourceConfiguration> affectedGradleModuleConfigurations =
|
||||
generateAffectedGradleModulesConfiguration(context);
|
||||
Map<String, GradleModuleResourceConfiguration> affectedGradleModuleConfigurations = generateAffectedGradleModulesConfiguration(context);
|
||||
|
||||
if (affectedGradleModuleConfigurations.isEmpty()) return;
|
||||
|
||||
boolean configurationUpdateRequired = context.isRebuild() || !gradleConfigFile.exists();
|
||||
|
||||
final Map<String, Integer> affectedConfigurationHash = new HashMap<>();
|
||||
Object2LongOpenHashMap<String> affectedConfigurationHash = new Object2LongOpenHashMap<>();
|
||||
for (Map.Entry<String, GradleModuleResourceConfiguration> entry : affectedGradleModuleConfigurations.entrySet()) {
|
||||
Integer moduleLastConfigurationHash = myModulesConfigurationHash.get(entry.getKey());
|
||||
int moduleCurrentConfigurationHash = entry.getValue().computeConfigurationHash();
|
||||
if (moduleLastConfigurationHash == null || moduleLastConfigurationHash.intValue() != moduleCurrentConfigurationHash) {
|
||||
Long moduleLastConfigurationHash = modulesConfigurationHash.get(entry.getKey());
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
entry.getValue().computeConfigurationHash(hash);
|
||||
long moduleCurrentConfigurationHash = hash.getAsLong();
|
||||
if (moduleLastConfigurationHash == null || moduleLastConfigurationHash.longValue() != moduleCurrentConfigurationHash) {
|
||||
configurationUpdateRequired = true;
|
||||
}
|
||||
affectedConfigurationHash.put(entry.getKey(), moduleCurrentConfigurationHash);
|
||||
}
|
||||
|
||||
final GradleProjectConfiguration projectConfig = loadLastConfiguration(gradleConfigFile);
|
||||
GradleProjectConfiguration projectConfig = loadLastConfiguration(gradleConfigFile);
|
||||
projectConfig.moduleConfigurations.putAll(affectedGradleModuleConfigurations);
|
||||
|
||||
final Element element = new Element("gradle-project-configuration");
|
||||
Element element = new Element("gradle-project-configuration");
|
||||
XmlSerializer.serializeInto(projectConfig, element);
|
||||
final boolean finalConfigurationUpdateRequired = configurationUpdateRequired;
|
||||
boolean finalConfigurationUpdateRequired = configurationUpdateRequired;
|
||||
buildManager.runCommand(() -> {
|
||||
if (finalConfigurationUpdateRequired) {
|
||||
buildManager.clearState(myProject);
|
||||
@@ -120,7 +121,7 @@ public class GradleResourceCompilerConfigurationGenerator {
|
||||
FileUtil.createIfDoesntExist(gradleConfigFile);
|
||||
try {
|
||||
JDOMUtil.write(element, gradleConfigFile.toPath());
|
||||
myModulesConfigurationHash.putAll(affectedConfigurationHash);
|
||||
modulesConfigurationHash.putAll(affectedConfigurationHash);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -129,13 +130,13 @@ public class GradleResourceCompilerConfigurationGenerator {
|
||||
}
|
||||
|
||||
private @NotNull GradleProjectConfiguration loadLastConfiguration(@NotNull File gradleConfigFile) {
|
||||
final GradleProjectConfiguration projectConfig = new GradleProjectConfiguration();
|
||||
GradleProjectConfiguration projectConfig = new GradleProjectConfiguration();
|
||||
if (gradleConfigFile.exists()) {
|
||||
try {
|
||||
XmlSerializer.deserializeInto(projectConfig, JDOMUtil.load(gradleConfigFile));
|
||||
|
||||
// filter orphan modules
|
||||
final Set<String> actualModules = myModulesConfigurationHash.keySet();
|
||||
Set<String> actualModules = modulesConfigurationHash.keySet();
|
||||
for (Iterator<Map.Entry<String, GradleModuleResourceConfiguration>> iterator =
|
||||
projectConfig.moduleConfigurations.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<String, GradleModuleResourceConfiguration> configurationEntry = iterator.next();
|
||||
|
||||
@@ -38,5 +38,6 @@
|
||||
<orderEntry type="library" name="fastutil-min" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.jdom" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.build.tests" scope="TEST" />
|
||||
<orderEntry type="library" name="hash4j" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.gradle.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xmlb.annotations.OptionTag;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
@@ -17,14 +16,10 @@ import java.util.List;
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
public class GradleModuleResourceConfiguration {
|
||||
@NotNull
|
||||
@Tag("id")
|
||||
public ModuleVersion id;
|
||||
public final class GradleModuleResourceConfiguration {
|
||||
@Tag("id") public @NotNull ModuleVersion id;
|
||||
|
||||
@Nullable
|
||||
@Tag("parentId")
|
||||
public ModuleVersion parentId;
|
||||
@Tag("parentId") public @Nullable ModuleVersion parentId;
|
||||
|
||||
@OptionTag
|
||||
public boolean overwrite;
|
||||
@@ -38,34 +33,42 @@ public class GradleModuleResourceConfiguration {
|
||||
@XCollection(propertyElementName = "test-resources", elementName = "resource")
|
||||
public List<ResourceRootConfiguration> testResources = new ArrayList<>();
|
||||
|
||||
public int computeConfigurationHash(boolean forTestResources, PathRelativizerService pathRelativizerService) {
|
||||
int result = computeModuleConfigurationHash();
|
||||
public void computeConfigurationHash(boolean forTestResources, PathRelativizerService pathRelativizerService, @NotNull HashSink hash) {
|
||||
computeModuleConfigurationHash(hash);
|
||||
|
||||
final List<ResourceRootConfiguration> _resources = forTestResources ? testResources : resources;
|
||||
result = 31 * result;
|
||||
List<ResourceRootConfiguration> _resources = forTestResources ? testResources : resources;
|
||||
for (ResourceRootConfiguration resource : _resources) {
|
||||
result += resource.computeConfigurationHash(pathRelativizerService);
|
||||
resource.computeConfigurationHash(pathRelativizerService, hash);
|
||||
}
|
||||
return result;
|
||||
hash.putInt(_resources.size());
|
||||
}
|
||||
|
||||
public int computeConfigurationHash() {
|
||||
int result = computeModuleConfigurationHash();
|
||||
public void computeConfigurationHash(@NotNull HashSink hash) {
|
||||
computeModuleConfigurationHash(hash);
|
||||
|
||||
final List<ResourceRootConfiguration> _resources = ContainerUtil.concat(testResources, resources);
|
||||
result = 31 * result;
|
||||
List<ResourceRootConfiguration> _resources = ContainerUtil.concat(testResources, resources);
|
||||
for (ResourceRootConfiguration resource : _resources) {
|
||||
result += resource.computeConfigurationHash(null);
|
||||
resource.computeConfigurationHash(null, hash);
|
||||
}
|
||||
return result;
|
||||
hash.putInt(_resources.size());
|
||||
}
|
||||
|
||||
public int computeModuleConfigurationHash() {
|
||||
int result = id.hashCode();
|
||||
result = 31 * result + (parentId != null ? parentId.hashCode() : 0);
|
||||
result = 31 * result + (outputDirectory != null ? outputDirectory.hashCode() : 0);
|
||||
result = 31 * result + (overwrite ? 1 : 0);
|
||||
return result;
|
||||
public void computeModuleConfigurationHash(@NotNull HashSink hash) {
|
||||
hash.putInt(id.hashCode());
|
||||
if (parentId == null) {
|
||||
hash.putBoolean(false);
|
||||
}
|
||||
else {
|
||||
hash.putBoolean(true);
|
||||
parentId.computeHash(hash);
|
||||
}
|
||||
if (outputDirectory == null) {
|
||||
hash.putInt(-1);
|
||||
}
|
||||
else {
|
||||
hash.putString(outputDirectory);
|
||||
}
|
||||
hash.putBoolean(overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.gradle.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.FileCollectionFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -20,13 +20,12 @@ import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.util.JpsPathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourceRootDescriptor> {
|
||||
public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourceRootDescriptor> implements BuildTargetHashSupplier {
|
||||
GradleResourcesTarget(@NotNull GradleResourcesTargetType type, @NotNull JpsModule module) {
|
||||
super(type, module);
|
||||
}
|
||||
@@ -46,9 +45,8 @@ public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourc
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<GradleResourceRootDescriptor> computeRootDescriptors(@NotNull JpsModel model, @NotNull ModuleExcludeIndex index, @NotNull IgnoredFileIndex ignoredFileIndex, @NotNull BuildDataPaths dataPaths) {
|
||||
public @NotNull List<GradleResourceRootDescriptor> computeRootDescriptors(@NotNull JpsModel model, @NotNull ModuleExcludeIndex index, @NotNull IgnoredFileIndex ignoredFileIndex, @NotNull BuildDataPaths dataPaths) {
|
||||
final List<GradleResourceRootDescriptor> result = new ArrayList<>();
|
||||
|
||||
GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths);
|
||||
@@ -80,9 +78,8 @@ public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourc
|
||||
return ((GradleResourcesTargetType)getTargetType()).isTests();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public GradleResourceRootDescriptor findRootDescriptor(@NotNull String rootId, @NotNull BuildRootIndex rootIndex) {
|
||||
public @Nullable GradleResourceRootDescriptor findRootDescriptor(@NotNull String rootId, @NotNull BuildRootIndex rootIndex) {
|
||||
for (GradleResourceRootDescriptor descriptor : rootIndex.getTargetRoots(this, null)) {
|
||||
if (descriptor.getRootId().equals(rootId)) {
|
||||
return descriptor;
|
||||
@@ -91,15 +88,13 @@ public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourc
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
public @NotNull String getPresentableName() {
|
||||
return getTargetType().getTypeId() + ":" + myModule.getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<File> getOutputRoots(@NotNull CompileContext context) {
|
||||
public @NotNull Collection<File> getOutputRoots(@NotNull CompileContext context) {
|
||||
GradleModuleResourceConfiguration configuration =
|
||||
getModuleResourcesConfiguration(context.getProjectDescriptor().dataManager.getDataPaths());
|
||||
final Set<File> result = FileCollectionFactory.createCanonicalFileSet();
|
||||
@@ -113,13 +108,11 @@ public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourc
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public File getModuleOutputDir() {
|
||||
public @Nullable File getModuleOutputDir() {
|
||||
return JpsJavaExtensionService.getInstance().getOutputDirectory(myModule, isTests());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getOutputDir(@Nullable File moduleOutput, ResourceRootConfiguration config, @Nullable String outputDirectory) {
|
||||
public static @Nullable File getOutputDir(@Nullable File moduleOutput, ResourceRootConfiguration config, @Nullable String outputDirectory) {
|
||||
if(outputDirectory != null) {
|
||||
moduleOutput = JpsPathUtil.urlToFile(outputDirectory);
|
||||
}
|
||||
@@ -128,21 +121,26 @@ public final class GradleResourcesTarget extends ModuleBasedTarget<GradleResourc
|
||||
return null;
|
||||
}
|
||||
String targetPath = config.targetPath;
|
||||
if (StringUtil.isEmptyOrSpaces(targetPath)) {
|
||||
if (targetPath == null || targetPath.isBlank()) {
|
||||
return moduleOutput;
|
||||
}
|
||||
final File targetPathFile = new File(targetPath);
|
||||
final File outputFile = targetPathFile.isAbsolute() ? targetPathFile : new File(moduleOutput, targetPath);
|
||||
|
||||
File targetPathFile = new File(targetPath);
|
||||
File outputFile = targetPathFile.isAbsolute() ? targetPathFile : new File(moduleOutput, targetPath);
|
||||
return new File(FileUtil.toCanonicalPath(outputFile.getPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor pd, @NotNull PrintWriter out) {
|
||||
final BuildDataPaths dataPaths = pd.getTargetsState().getDataPaths();
|
||||
final GradleModuleResourceConfiguration configuration = getModuleResourcesConfiguration(dataPaths);
|
||||
if (configuration != null) {
|
||||
PathRelativizerService pathRelativizerService = pd.dataManager.getRelativizer();
|
||||
out.write(Integer.toHexString(configuration.computeConfigurationHash(isTests(), pathRelativizerService)));
|
||||
public void computeConfigurationDigest(@NotNull ProjectDescriptor projectDescriptor, @NotNull HashSink hash) {
|
||||
BuildDataPaths dataPaths = projectDescriptor.getTargetsState().getDataPaths();
|
||||
GradleModuleResourceConfiguration configuration = getModuleResourcesConfiguration(dataPaths);
|
||||
if (configuration == null) {
|
||||
hash.putBoolean(false);
|
||||
}
|
||||
else {
|
||||
hash.putBoolean(true);
|
||||
PathRelativizerService pathRelativizerService = projectDescriptor.dataManager.getRelativizer();
|
||||
configuration.computeConfigurationHash(isTests(), pathRelativizerService, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.gradle.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
public class ModuleVersion {
|
||||
public final class ModuleVersion {
|
||||
@Tag("groupId")
|
||||
public String groupId;
|
||||
|
||||
@@ -60,4 +49,19 @@ public class ModuleVersion {
|
||||
result = 31 * result + (version != null ? version.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void computeHash(@NotNull HashSink hash) {
|
||||
hashNullableString(groupId, hash);
|
||||
hashNullableString(artifactId, hash);
|
||||
hashNullableString(version, hash);
|
||||
}
|
||||
|
||||
private static void hashNullableString(@Nullable String s, @NotNull HashSink hash) {
|
||||
if (s == null) {
|
||||
hash.putInt(-1);
|
||||
}
|
||||
else {
|
||||
hash.putString(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.gradle.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashFunnel;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import com.intellij.util.xmlb.annotations.XCollection;
|
||||
@@ -17,14 +18,10 @@ import java.util.List;
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
@Tag("resource")
|
||||
public class ResourceRootConfiguration extends FilePattern {
|
||||
@Tag("directory")
|
||||
@NotNull
|
||||
public String directory;
|
||||
public final class ResourceRootConfiguration extends FilePattern {
|
||||
@Tag("directory") public @NotNull String directory;
|
||||
|
||||
@Tag("targetPath")
|
||||
@Nullable
|
||||
public String targetPath;
|
||||
@Tag("targetPath") public @Nullable String targetPath;
|
||||
|
||||
@Attribute("filtered")
|
||||
public boolean isFiltered;
|
||||
@@ -32,22 +29,33 @@ public class ResourceRootConfiguration extends FilePattern {
|
||||
@XCollection(propertyElementName = "filters", elementName = "filter")
|
||||
public List<ResourceRootFilter> filters = new ArrayList<>();
|
||||
|
||||
public int computeConfigurationHash(@Nullable PathRelativizerService pathRelativizerService) {
|
||||
int result;
|
||||
if(pathRelativizerService == null) {
|
||||
result = directory.hashCode();
|
||||
result = 31 * result + (targetPath != null ? targetPath.hashCode() : 0);
|
||||
} else {
|
||||
result = pathRelativizerService.toRelative(directory).hashCode();
|
||||
result = 31 * result + (targetPath != null ? pathRelativizerService.toRelative(targetPath).hashCode() : 0);
|
||||
public void computeConfigurationHash(@Nullable PathRelativizerService pathRelativizerService, @NotNull HashSink hash) {
|
||||
if (pathRelativizerService == null) {
|
||||
hash.putString(directory);
|
||||
if (targetPath == null) {
|
||||
hash.putInt(-1);
|
||||
}
|
||||
else {
|
||||
hash.putString(targetPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
hash.putString(pathRelativizerService.toRelative(directory));
|
||||
if (targetPath == null) {
|
||||
hash.putInt(-1);
|
||||
}
|
||||
else {
|
||||
hash.putString(pathRelativizerService.toRelative(targetPath));
|
||||
}
|
||||
}
|
||||
|
||||
result = 31 * result + (isFiltered ? 1 : 0);
|
||||
result = 31 * result + includes.hashCode();
|
||||
result = 31 * result + excludes.hashCode();
|
||||
hash.putBoolean(isFiltered);
|
||||
hash.putUnorderedIterable(includes, HashFunnel.forString(), Hashing.komihash5_0());
|
||||
hash.putUnorderedIterable(excludes, HashFunnel.forString(), Hashing.komihash5_0());
|
||||
|
||||
for (ResourceRootFilter filter : filters) {
|
||||
result = 31 * result + filter.computeConfigurationHash();
|
||||
filter.computeConfigurationHash(hash);
|
||||
}
|
||||
return result;
|
||||
hash.putInt(filters.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.gradle.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
@@ -32,25 +19,18 @@ import java.util.regex.Pattern;
|
||||
* @author Vladislav.Soroka
|
||||
*/
|
||||
@Tag("filter")
|
||||
public class ResourceRootFilter {
|
||||
@Tag("filterType")
|
||||
@NotNull
|
||||
@NlsSafe
|
||||
public String filterType;
|
||||
@Tag("properties")
|
||||
@NotNull
|
||||
public String properties;
|
||||
public final class ResourceRootFilter {
|
||||
@Tag("filterType") public @NotNull @NlsSafe String filterType;
|
||||
@Tag("properties") public @NotNull String properties;
|
||||
|
||||
private transient Map<Object, Object> propertiesMap;
|
||||
|
||||
public int computeConfigurationHash() {
|
||||
int result = filterType.hashCode();
|
||||
result = 31 * result + getProperties().hashCode();
|
||||
return result;
|
||||
public void computeConfigurationHash(@NotNull HashSink hash) {
|
||||
hash.putString(filterType);
|
||||
hash.putString(properties);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Object, Object> getProperties() {
|
||||
public @NotNull Map<Object, Object> getProperties() {
|
||||
if (propertiesMap == null) {
|
||||
try {
|
||||
Gson gson = new GsonBuilder().create();
|
||||
@@ -59,16 +39,16 @@ public class ResourceRootFilter {
|
||||
new TypeToken<Map<Object, Object>>() {
|
||||
}.getType());
|
||||
|
||||
if("RenamingCopyFilter".equals(filterType)) {
|
||||
if ("RenamingCopyFilter".equals(filterType)) {
|
||||
final Object pattern = propertiesMap.get("pattern");
|
||||
final Matcher matcher = Pattern.compile(pattern instanceof String ? (String)pattern : "").matcher("");
|
||||
propertiesMap.put("matcher", matcher);
|
||||
}
|
||||
}
|
||||
catch (JsonParseException e) {
|
||||
throw new RuntimeException("Unsupported filter: " + properties , e);
|
||||
throw new RuntimeException("Unsupported filter: " + properties, e);
|
||||
}
|
||||
if(propertiesMap == null) {
|
||||
if (propertiesMap == null) {
|
||||
propertiesMap = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package org.jetbrains.jps.maven.compiler;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashFunnel;
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -90,7 +90,6 @@ public final class MavenWebArtifactRootCopyingHandlerProvider extends ArtifactRo
|
||||
}
|
||||
|
||||
private static class MavenWebArtifactCopyingHandler extends FilterCopyHandler {
|
||||
|
||||
private final ResourceRootConfiguration myWarRootConfig;
|
||||
private final MavenModuleResourceConfiguration myModuleResourceConfig;
|
||||
|
||||
@@ -116,12 +115,12 @@ public final class MavenWebArtifactRootCopyingHandlerProvider extends ArtifactRo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull HashStream64 hash) {
|
||||
public void writeConfiguration(@NotNull HashSink hash) {
|
||||
hash.putString("maven hash:");
|
||||
configurationHash(hash);
|
||||
}
|
||||
|
||||
protected void configurationHash(@NotNull HashStream64 hash) {
|
||||
protected void configurationHash(@NotNull HashSink hash) {
|
||||
hash.putUnorderedIterable(myWarRootConfig.includes, HashFunnel.forString(), Hashing.komihash5_0());
|
||||
hash.putUnorderedIterable(myWarRootConfig.excludes, HashFunnel.forString(), Hashing.komihash5_0());
|
||||
myWarRootConfig.computeConfigurationHash(hash);
|
||||
@@ -181,7 +180,7 @@ public final class MavenWebArtifactRootCopyingHandlerProvider extends ArtifactRo
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configurationHash(@NotNull HashStream64 hash) {
|
||||
protected void configurationHash(@NotNull HashSink hash) {
|
||||
super.configurationHash(hash);
|
||||
|
||||
FileHashUtilKt.normalizedPathHashCode(myTargetDir.toPath().toAbsolutePath().normalize().toString(), hash);
|
||||
@@ -246,7 +245,8 @@ public final class MavenWebArtifactRootCopyingHandlerProvider extends ArtifactRo
|
||||
FileFilter superFileFilter = super.createFileFilter();
|
||||
FileFilter rootFileFilter = new MavenResourceFileFilter(root, myRootConfiguration).acceptingWebXml();
|
||||
|
||||
//for additional resource directory 'exclude' means 'exclude from copying' but for the default webapp resource it mean 'exclude from filtering'
|
||||
// for additional resource directory 'exclude' means 'exclude from copying'
|
||||
// but for the default webapp resource it means 'exclude from filtering'
|
||||
boolean isMainWebAppRoot = FileUtil.pathsEqual(artifactConfiguration.warSourceDirectory, rootConfiguration.directory);
|
||||
|
||||
if (isMainWebAppRoot) {
|
||||
@@ -272,7 +272,7 @@ public final class MavenWebArtifactRootCopyingHandlerProvider extends ArtifactRo
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configurationHash(@NotNull HashStream64 hash) {
|
||||
protected void configurationHash(@NotNull HashSink hash) {
|
||||
myRootConfiguration.computeConfigurationHash(hash);
|
||||
super.configurationHash(hash);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package org.jetbrains.jps.maven.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashFunnel;
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import com.intellij.util.xmlb.annotations.MapAnnotation;
|
||||
@@ -74,7 +74,7 @@ public final class MavenModuleResourceConfiguration {
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
public void computeConfigurationHash(boolean forTestResources, @NotNull HashStream64 hash) {
|
||||
public void computeConfigurationHash(boolean forTestResources, @NotNull HashSink hash) {
|
||||
computeModuleConfigurationHash(hash);
|
||||
|
||||
List<ResourceRootConfiguration> _resources = forTestResources? testResources : resources;
|
||||
@@ -84,7 +84,7 @@ public final class MavenModuleResourceConfiguration {
|
||||
hash.putInt(_resources.size());
|
||||
}
|
||||
|
||||
public void computeModuleConfigurationHash(@NotNull HashStream64 hash) {
|
||||
public void computeModuleConfigurationHash(@NotNull HashSink hash) {
|
||||
hash.putInt(parentId == null ? 0 : parentId.hashCode());
|
||||
hash.putString(directory);
|
||||
hashNullableString(manifest, hash);
|
||||
@@ -105,7 +105,7 @@ public final class MavenModuleResourceConfiguration {
|
||||
hash.putBoolean(overwrite);
|
||||
}
|
||||
|
||||
private static void hashNullableString(@Nullable String s, @NotNull HashStream64 hash) {
|
||||
private static void hashNullableString(@Nullable String s, @NotNull HashSink hash) {
|
||||
if (s == null) {
|
||||
hash.putInt(-1);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.maven.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.Hashing;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.containers.FileCollectionFactory;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -21,14 +20,13 @@ import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.util.JpsPathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public final class MavenResourcesTarget extends ModuleBasedTarget<MavenResourceRootDescriptor> {
|
||||
public final class MavenResourcesTarget extends ModuleBasedTarget<MavenResourceRootDescriptor> implements BuildTargetHashSupplier {
|
||||
MavenResourcesTarget(@NotNull MavenResourcesTargetType type, @NotNull JpsModule module) {
|
||||
super(type, module);
|
||||
}
|
||||
@@ -137,13 +135,15 @@ public final class MavenResourcesTarget extends ModuleBasedTarget<MavenResourceR
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfiguration(@NotNull ProjectDescriptor pd, @NotNull PrintWriter out) {
|
||||
BuildDataPaths dataPaths = pd.getTargetsState().getDataPaths();
|
||||
public void computeConfigurationDigest(@NotNull ProjectDescriptor projectDescriptor, @NotNull HashSink hash) {
|
||||
BuildDataPaths dataPaths = projectDescriptor.getTargetsState().getDataPaths();
|
||||
MavenModuleResourceConfiguration configuration = getModuleResourcesConfiguration(dataPaths);
|
||||
HashStream64 hash = Hashing.komihash5_0().hashStream();
|
||||
if (configuration != null) {
|
||||
if (configuration == null) {
|
||||
hash.putBoolean(false);
|
||||
}
|
||||
else {
|
||||
hash.putBoolean(true);
|
||||
configuration.computeConfigurationHash(isTests(), hash);
|
||||
out.write(Long.toUnsignedString(hash.getAsLong(), Character.MAX_RADIX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.maven.model.impl;
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64;
|
||||
import com.dynatrace.hash4j.hashing.HashSink;
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -21,7 +21,7 @@ public final class ResourceRootConfiguration extends FilePattern {
|
||||
@Attribute("filtered")
|
||||
public boolean isFiltered;
|
||||
|
||||
public void computeConfigurationHash(@NotNull HashStream64 hash) {
|
||||
public void computeConfigurationHash(@NotNull HashSink hash) {
|
||||
hash.putString(directory);
|
||||
if (targetPath == null) {
|
||||
hash.putInt(-1);
|
||||
|
||||
Reference in New Issue
Block a user