From 417dcc73366d95686f293856de7170ce7514b84c Mon Sep 17 00:00:00 2001 From: "Alexander.Glukhov" Date: Wed, 3 Sep 2025 18:26:03 +0200 Subject: [PATCH] [maven][eel][jps][IDEA-375248] fix stale JPS compilation cache on a remote target The error was caused by reusing the old cache for compilation. As a result, the file with the compiler settings did not match the current state of the project. This led to the module being compiled with the version of the target Java bytecode that was used for the first compilation. GitOrigin-RevId: 3a5e40192f664ca842750b2d276b7b4b44d67eaa --- .../server/BuildCommandLineBuilder.java | 11 ++++++++ .../compiler/server/BuildManager.java | 2 +- .../server/EelBuildCommandLineBuilder.kt | 28 +++++++++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java index bcd4f77eac13..280fef56a30f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java @@ -75,4 +75,15 @@ interface BuildCommandLineBuilder { default @NotNull Path copyProjectSpecificPathToTargetIfRequired(@NotNull Project project, @NotNull Path path) throws FileSystemException { return path; } + + /** + * Synchronize the content of the path with the remote. This method replaces all the files located on the remote path with the content + * from the local machine. + * @param path a path to a project-specific which is available locally to the IDE that can be used only with specific {@link project}. + * @return a path which points to a copy on a remote machine. + */ + @ApiStatus.Experimental + default @NotNull Path syncProjectSpecificPathWithTarget(@NotNull Project project, @NotNull Path path) throws FileSystemException { + return path; + } } diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 881f0b547efb..31f9598fe1c3 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1533,7 +1533,7 @@ public final class BuildManager implements Disposable { try { cmdLine.addPathParameter( "-D" + GlobalOptions.EXTERNAL_PROJECT_CONFIG + '=', - cmdLine.copyProjectSpecificPathToTargetIfRequired(project, externalProjectConfig) + cmdLine.syncProjectSpecificPathWithTarget(project, externalProjectConfig) ); } catch (NoSuchFileException ignored) { diff --git a/java/compiler/impl/src/com/intellij/compiler/server/EelBuildCommandLineBuilder.kt b/java/compiler/impl/src/com/intellij/compiler/server/EelBuildCommandLineBuilder.kt index 55545bbe3587..644dd2a7ffef 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/EelBuildCommandLineBuilder.kt +++ b/java/compiler/impl/src/com/intellij/compiler/server/EelBuildCommandLineBuilder.kt @@ -22,6 +22,9 @@ import kotlinx.coroutines.future.asCompletableFuture import java.nio.charset.Charset import java.nio.file.FileSystems import java.nio.file.Path +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.deleteRecursively +import kotlin.io.path.exists import kotlin.io.path.name internal class EelBuildCommandLineBuilder(val project: Project, exePath: Path) : BuildCommandLineBuilder { @@ -34,9 +37,11 @@ internal class EelBuildCommandLineBuilder(val project: Project, exePath: Path) : private val workingDirectory: Path = getSystemSubfolder(BuildManager.SYSTEM_ROOT) private val cacheDirectory: Path = getSystemSubfolder("jps-${ApplicationInfo.getInstance().getBuild()}") + .resolve(project.getProjectCacheFileName()) init { workingDirectory.createDirectories() // Ijent doesn't support running anything in non-existing directory + cacheDirectory.createDirectories() } override fun addParameter(parameter: String) { @@ -80,13 +85,26 @@ internal class EelBuildCommandLineBuilder(val project: Project, exePath: Path) : return EelPathUtils.transferLocalContentToRemote(path, EelPathUtils.TransferTarget.Explicit(remotePath)) } - override fun copyProjectSpecificPathToTargetIfRequired(project: Project, path: Path): Path { - if (path.getEelDescriptor() != LocalEelDescriptor) { + override fun copyProjectSpecificPathToTargetIfRequired(project: Project, path: Path): Path = EelPathUtils.transferLocalContentToRemote( + path, + EelPathUtils.TransferTarget.Explicit(cacheDirectory.resolve(path.name)) + ) + + @OptIn(ExperimentalPathApi::class) + override fun syncProjectSpecificPathWithTarget(project: Project, path: Path): Path { + val target = cacheDirectory.resolve(path.name) + if (target.getEelDescriptor() == LocalEelDescriptor) { return path } - val cacheFileName = project.getProjectCacheFileName() - val target = cacheDirectory.resolve(cacheFileName).resolve(path.name) - return EelPathUtils.transferLocalContentToRemote(path, EelPathUtils.TransferTarget.Explicit(target)) + // this code should be replaced with com.intellij.platform.eel.provider.utils.EelPathUtils.incrementalWalkingTransfer when + // it's ready for production + if (target.exists()) { + target.deleteRecursively() + } + return EelPathUtils.transferLocalContentToRemote( + path, + EelPathUtils.TransferTarget.Explicit(target) + ) } override fun getYjpAgentPath(yourKitProfilerService: YourKitProfilerService?): String? {