diff --git a/platform/execution/src/com/intellij/execution/target/EelTargetEnvironmentRequest.kt b/platform/execution/src/com/intellij/execution/target/EelTargetEnvironmentRequest.kt index 7e1da717626e..111ae8d514f2 100644 --- a/platform/execution/src/com/intellij/execution/target/EelTargetEnvironmentRequest.kt +++ b/platform/execution/src/com/intellij/execution/target/EelTargetEnvironmentRequest.kt @@ -3,6 +3,7 @@ package com.intellij.execution.target import com.intellij.execution.ExecutionException import com.intellij.execution.Platform +import com.intellij.openapi.components.BaseState import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.Service import com.intellij.openapi.components.service @@ -20,6 +21,8 @@ import com.intellij.platform.eel.fs.getPath import com.intellij.platform.eel.path.EelPath 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.toEelApiBlocking import com.intellij.platform.eel.provider.utils.* import com.intellij.platform.util.coroutines.childScope import com.intellij.ui.icons.EMPTY_ICON @@ -36,11 +39,12 @@ import java.nio.file.Path import java.util.* import java.util.concurrent.ConcurrentHashMap import javax.swing.Icon +import kotlin.io.path.Path import kotlin.io.path.isSameFileAs -private fun EelPlatform.toTargetPlatform(): TargetPlatform = when (this) { - is EelPlatform.Posix -> TargetPlatform(Platform.UNIX) - is EelPlatform.Windows -> TargetPlatform(Platform.WINDOWS) +private fun EelOsFamily.toTargetPlatform(): TargetPlatform = when (this) { + EelOsFamily.Posix -> TargetPlatform(Platform.UNIX) + EelOsFamily.Windows -> TargetPlatform(Platform.WINDOWS) } private fun LocalHostPort(port: Int) = HostPort("localhost", port) @@ -75,30 +79,68 @@ class EelTargetType : TargetEnvironmentType { - throw UnsupportedOperationException() + return config } override fun createDefaultConfig(): EelTargetEnvironmentRequest.Configuration { - throw UnsupportedOperationException() + return EelTargetEnvironmentRequest.Configuration() } override fun duplicateConfig(config: EelTargetEnvironmentRequest.Configuration): EelTargetEnvironmentRequest.Configuration { - return EelTargetEnvironmentRequest.Configuration(config.eel) + return EelTargetEnvironmentRequest.Configuration.create(config.descriptor).also { + it.projectRootOnTarget = config.projectRootOnTarget + } } } @ApiStatus.Internal -class EelTargetEnvironmentRequest(override val configuration: Configuration) : BaseTargetEnvironmentRequest(), VolumeCopyingRequest { - class Configuration(val eel: EelApi) : TargetEnvironmentConfiguration(TARGET_TYPE_NAME), TargetConfigurationWithLocalFsAccess { +class EelTargetEnvironmentRequest( + override val configuration: Configuration, +) : BaseTargetEnvironmentRequest(), VolumeCopyingRequest { + class Configuration private constructor( + eelDescriptor: EelDescriptor?, + ) : TargetEnvironmentConfiguration(TARGET_TYPE_NAME), TargetConfigurationWithLocalFsAccess, PersistentStateComponent { + internal constructor() : this(null) + + constructor(eelApi: EelApi) : this(eelApi.descriptor) + + private var myDescriptor = eelDescriptor + + val descriptor: EelDescriptor get() = myDescriptor ?: error("EEL descriptor is not set") + + companion object { + @JvmStatic + fun create(eelDescriptor: EelDescriptor): Configuration = Configuration( + eelDescriptor = eelDescriptor + ) + } + override var projectRootOnTarget: String = "" override val asTargetConfig: TargetEnvironmentConfiguration = this override fun getTargetPathIfLocalPathIsOnTarget(probablyPathOnTarget: Path): FullPathOnTarget? { - return probablyPathOnTarget.asEelPath().takeIf { it.descriptor == eel.descriptor }?.toString() + return probablyPathOnTarget.asEelPath().takeIf { it.descriptor == descriptor }?.toString() + } + + override fun getState(): PersistentState { + return PersistentState().also { + it.projectRootOnTarget = projectRootOnTarget + it.eelRootPath = (descriptor as? EelPathBoundDescriptor)?.rootPath.toString() + } + } + + override fun loadState(state: PersistentState) { + projectRootOnTarget = state.projectRootOnTarget ?: "" + myDescriptor = state.eelRootPath?.let(::Path)?.getEelDescriptor() ?: descriptor + } + + class PersistentState : BaseState() { + var projectRootOnTarget: String? by string() + var eelRootPath: String? by string() } } - override val targetPlatform: TargetPlatform = configuration.eel.platform.toTargetPlatform() + override val targetPlatform: TargetPlatform = configuration.descriptor.osFamily.toTargetPlatform() override fun prepareEnvironment(progressIndicator: TargetProgressIndicator): TargetEnvironment { val env = EelTargetEnvironment(this) @@ -116,9 +158,9 @@ class EelTargetEnvironment(override val request: EelTargetEnvironmentRequest) : private val myTargetPortBindings: MutableMap = HashMap() private val myLocalPortBindings: MutableMap = ConcurrentHashMap() - private val eel = request.configuration.eel + private val eel = request.configuration.descriptor.toEelApiBlocking() - private val forwardingScope by lazy { service().scope.childScope("Eel target forwarding scope: ${request.configuration.eel}") } + private val forwardingScope by lazy { service().scope.childScope("Eel target forwarding scope: ${request.configuration.descriptor}") } override val uploadVolumes: Map get() = Collections.unmodifiableMap(myUploadVolumes) diff --git a/platform/testFramework/junit5/eel/BUILD.bazel b/platform/testFramework/junit5/eel/BUILD.bazel index c9ce39794f6a..7fd6233e670c 100644 --- a/platform/testFramework/junit5/eel/BUILD.bazel +++ b/platform/testFramework/junit5/eel/BUILD.bazel @@ -29,6 +29,7 @@ jvm_library( "//platform/util", "//platform/util/coroutines", "//platform/util-ex", + "//platform/projectModel-api:projectModel", ] ) @@ -60,6 +61,7 @@ jvm_library( "//platform/util/coroutines", "//platform/util-ex", "//platform/execution", + "//platform/projectModel-api:projectModel", ] ) ### auto-generated section `build intellij.platform.testFramework.junit5.eel` end diff --git a/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml b/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml index 0e5c7de15b60..e148a5683286 100644 --- a/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml +++ b/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml @@ -28,5 +28,6 @@ + \ No newline at end of file diff --git a/platform/testFramework/junit5/eel/test/params/api/DockerTest.kt b/platform/testFramework/junit5/eel/test/params/api/DockerTest.kt index 3007c548398e..5f6ff77597ce 100644 --- a/platform/testFramework/junit5/eel/test/params/api/DockerTest.kt +++ b/platform/testFramework/junit5/eel/test/params/api/DockerTest.kt @@ -19,4 +19,4 @@ const val DEFAULT_EEL_TEST_DOCKER_IMAGE: String = "debian" @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @TestApplicationWithEel @Repeatable -annotation class DockerTest(val image: String = DEFAULT_EEL_TEST_DOCKER_IMAGE, val mandatory: Boolean = true) \ No newline at end of file +annotation class DockerTest(val image: String = DEFAULT_EEL_TEST_DOCKER_IMAGE, val mandatory: Boolean = true, val setupCommands: Array = []) \ No newline at end of file diff --git a/platform/testFramework/junit5/eel/test/params/api/EelHolder.kt b/platform/testFramework/junit5/eel/test/params/api/EelHolder.kt index 02f7a61f4fee..c991c1f5cdc3 100644 --- a/platform/testFramework/junit5/eel/test/params/api/EelHolder.kt +++ b/platform/testFramework/junit5/eel/test/params/api/EelHolder.kt @@ -1,11 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.testFramework.junit5.eel.params.api +import com.intellij.execution.target.EelTargetEnvironmentRequest import com.intellij.execution.target.TargetEnvironmentConfiguration import com.intellij.platform.eel.EelApi +import com.intellij.platform.eel.LocalEelApi import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.TestOnly -import org.opentest4j.TestAbortedException /** * Accept as an argument of your test, be sure to use [EelSource] @@ -35,7 +36,4 @@ sealed interface EelHolder { * Consider using [EelHolder.eel] in a new code. */ val EelHolder.target: TargetEnvironmentConfiguration? - get() = when (val t = type) { - is Docker, is Wsl -> t.target - Local -> null - } \ No newline at end of file + get() = if (eel is LocalEelApi) null else EelTargetEnvironmentRequest.Configuration(eel) \ No newline at end of file diff --git a/platform/testFramework/junit5/eel/test/params/api/EelType.kt b/platform/testFramework/junit5/eel/test/params/api/EelType.kt index eed5c55e334f..7bb5f9f61a36 100644 --- a/platform/testFramework/junit5/eel/test/params/api/EelType.kt +++ b/platform/testFramework/junit5/eel/test/params/api/EelType.kt @@ -6,11 +6,9 @@ import org.jetbrains.annotations.ApiStatus @ApiStatus.Internal sealed interface EelType -sealed interface RemoteEelType { - val target: TargetEnvironmentConfiguration -} +sealed interface RemoteEelType -class Wsl(override val target: TargetEnvironmentConfiguration) : EelType, RemoteEelType -class Docker(override val target: TargetEnvironmentConfiguration) : EelType, RemoteEelType +class Wsl : EelType, RemoteEelType +class Docker : EelType, RemoteEelType data object Local : EelType diff --git a/platform/testFramework/junit5/eel/test/showcase/EelParametrizedClassShowCaseTest.kt b/platform/testFramework/junit5/eel/test/showcase/EelParametrizedClassShowCaseTest.kt index 82361d24a6e0..108632acd395 100644 --- a/platform/testFramework/junit5/eel/test/showcase/EelParametrizedClassShowCaseTest.kt +++ b/platform/testFramework/junit5/eel/test/showcase/EelParametrizedClassShowCaseTest.kt @@ -28,7 +28,6 @@ class EelParametrizedClassShowCaseTest(val eelProvider: EelHolder) { when (val type = eelProvider.type) { is Docker -> { println("I am on docker") - type.target } Local -> Unit //no target for local is Wsl -> Unit diff --git a/python/python-exec-service/src/com/intellij/python/community/execService/impl/processLaunchers/targets.kt b/python/python-exec-service/src/com/intellij/python/community/execService/impl/processLaunchers/targets.kt index 2b8ec7d805c1..394b1d65b336 100644 --- a/python/python-exec-service/src/com/intellij/python/community/execService/impl/processLaunchers/targets.kt +++ b/python/python-exec-service/src/com/intellij/python/community/execService/impl/processLaunchers/targets.kt @@ -60,6 +60,9 @@ internal suspend fun createProcessLauncherOnTarget(binOnTarget: BinOnTarget, lau fileLogger().warn("Failed to start $target", e) // TODO: i18n return@withContext Result.failure(ExecuteGetProcessError.EnvironmentError(MessageError("Failed to start environment due to ${e.localizedMessage}"))) } + targetEnv.uploadVolumes.forEach { _, volume -> + volume.upload(".", TargetProgressIndicator.EMPTY) + } val args = launchRequest.args.getArgs { localFile -> targetEnv.getTargetPaths(localFile.pathString).first() }