[eel] IJPL-175013: Pass external project data to foreign environment

GitOrigin-RevId: 0dfec1a225b60d8aa1db4294ae20e7d999ba8b7b
This commit is contained in:
Konstantin.Nisht
2025-01-29 18:22:15 +00:00
committed by intellij-monorepo-bot
parent c0534f3509
commit aa5ce94adb
3 changed files with 64 additions and 25 deletions
@@ -1468,7 +1468,16 @@ public final class BuildManager implements Disposable {
}
if (ProjectUtilCore.isExternalStorageEnabled(project)) {
cmdLine.addPathParameter("-D" + GlobalOptions.EXTERNAL_PROJECT_CONFIG + '=', ProjectUtil.getExternalConfigurationDir(project));
Path externalProjectConfig = ProjectUtil.getExternalConfigurationDir(project);
String pathToExternalStorage;
if (canUseEel() && !EelPathUtils.isProjectLocal(project)) {
pathToExternalStorage = cmdLine.copyPathToHostIfRequired(externalProjectConfig);
cmdLine.addParameter("-D" + GlobalOptions.EXTERNAL_PROJECT_CONFIG + '=' + pathToExternalStorage);
}
else {
pathToExternalStorage = externalProjectConfig.toString();
cmdLine.addPathParameter("-D" + GlobalOptions.EXTERNAL_PROJECT_CONFIG + '=', pathToExternalStorage);
}
}
cmdLine.addParameter("-D" + GlobalOptions.COMPILE_PARALLEL_OPTION + '=' + projectConfig.isParallelCompilationEnabled());
@@ -16,6 +16,7 @@ import kotlinx.coroutines.future.asCompletableFuture
import java.nio.charset.Charset
import java.nio.file.FileSystems
import java.nio.file.Path
import kotlin.io.path.isDirectory
import kotlin.io.path.name
class EelBuildCommandLineBuilder(val project: Project, exePath: Path) : BuildCommandLineBuilder {
@@ -59,7 +60,15 @@ class EelBuildCommandLineBuilder(val project: Project, exePath: Path) : BuildCom
}
override fun copyPathToTargetIfRequired(path: Path): Path {
return EelPathUtils.transferContentsIfNonLocal(eel, path, workingDirectory.resolve("build-cache").resolve(path.name))
if (path.getEelDescriptor() != LocalEelDescriptor) return path
val remotePath = workingDirectory.resolve("build-cache").resolve(path.name)
if (path.isDirectory()) {
EelPathUtils.transferContentsIfNonLocal(eel, path, remotePath)
}
else if (path.getEelDescriptor() == LocalEelDescriptor) {
EelPathUtils.transferLocalContentToRemotePathIfNeeded(path, remotePath)
}
return remotePath
}
override fun copyPathToHostIfRequired(path: Path): String {
@@ -10,10 +10,7 @@ import com.intellij.platform.eel.*
import com.intellij.platform.eel.fs.EelFileSystemApi
import com.intellij.platform.eel.fs.EelFileSystemApi.CreateTemporaryEntryOptions
import com.intellij.platform.eel.path.EelPath
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.asEelPath
import com.intellij.platform.eel.provider.asNioPath
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.*
import com.intellij.util.awaitCancellationAndInvoke
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import kotlinx.coroutines.*
@@ -219,31 +216,34 @@ object EelPathUtils {
}
}
@JvmStatic
fun transferLocalContentToRemotePathIfNeeded(source: Path, remotePath: Path) {
val sourceDescriptor = source.getEelDescriptor()
check(sourceDescriptor is LocalEelDescriptor)
val sourceHash = calculateFileHash(source)
val remoteHash = if (Files.exists(remotePath)) {
calculateFileHash(remotePath)
}
else {
""
}
if (sourceHash != remoteHash) {
if (remoteHash.isNotEmpty()) {
Files.delete(remotePath)
}
transferContentsIfNonLocal(remotePath.getEelDescriptor().upgradeBlocking(), source, remotePath)
}
}
@Service
private class TransferredContentHolder(private val scope: CoroutineScope) {
// eel descriptor -> source path string ->> source hash -> transferred file
private val cache = ConcurrentHashMap<Pair<EelDescriptor, String>, Deferred<Pair<String, Path>>>()
private fun calculateFileHash(path: Path): String {
val digest = MessageDigest.getInstance("SHA-256")
val attributes = Files.readAttributes(path, BasicFileAttributes::class.java)
val fileSize = attributes.size()
val lastModified = attributes.lastModifiedTime().toMillis()
digest.update(fileSize.toString().toByteArray())
digest.update(lastModified.toString().toByteArray())
FileChannel.open(path, StandardOpenOption.READ).use { channel ->
val buffer = java.nio.ByteBuffer.allocateDirect(1024 * 1024)
while (channel.read(buffer) > 0) {
buffer.flip()
digest.update(buffer)
buffer.clear()
}
}
return digest.digest().joinToString("") { "%02x".format(it) }
}
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun transferIfNeeded(eel: EelApi, source: Path): Path {
@@ -278,6 +278,27 @@ object EelPathUtils {
}
}
private fun calculateFileHash(path: Path): String {
val digest = MessageDigest.getInstance("SHA-256")
val attributes = Files.readAttributes(path, BasicFileAttributes::class.java)
val fileSize = attributes.size()
val lastModified = attributes.lastModifiedTime().toMillis()
digest.update(fileSize.toString().toByteArray())
digest.update(lastModified.toString().toByteArray())
FileChannel.open(path, StandardOpenOption.READ).use { channel ->
val buffer = java.nio.ByteBuffer.allocateDirect(1024 * 1024)
while (channel.read(buffer) > 0) {
buffer.flip()
digest.update(buffer)
buffer.clear()
}
}
return digest.digest().joinToString("") { "%02x".format(it) }
}
@JvmStatic
fun getHomePath(descriptor: EelDescriptor): Path {
// usually eel is already initialized to this moment