diff --git a/platform/eel-impl/src/com/intellij/platform/eel/impl/ExecuteProcessOptionsExt.kt b/platform/eel-impl/src/com/intellij/platform/eel/impl/ExecuteProcessOptionsExt.kt new file mode 100644 index 000000000000..c83f355a3e1e --- /dev/null +++ b/platform/eel-impl/src/com/intellij/platform/eel/impl/ExecuteProcessOptionsExt.kt @@ -0,0 +1,31 @@ +// 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.eel.impl + +import com.intellij.openapi.diagnostic.fileLogger +import com.intellij.platform.eel.EelExecApi +import com.intellij.platform.eel.EelProcess +import com.intellij.platform.eel.provider.utils.ProcessFunctions +import com.intellij.platform.eel.provider.utils.bindProcessToScopeImpl +import org.jetbrains.annotations.ApiStatus + +/** + * If [scope] is set, bind [process] to it, so it gets killed as soon as the scope finishes. + * Used by implementors to support [EelExecApi.ExecuteProcessOptions.scope] + */ +@ApiStatus.Internal +fun EelExecApi.ExecuteProcessOptions.bindProcessToScopeIfSet(process: EelProcess) { + scope?.bindProcessToScopeImpl( + logger = logger, + processNameForDebug = commandLineForDebug, + ProcessFunctions( + waitForExit = { process.exitCode.await() }, + killProcess = { process.kill() } + ) + ) +} + +@get:ApiStatus.Internal +internal val EelExecApi.ExecuteProcessOptions.commandLineForDebug: String + get() = // Note: args aren't escaped, hence this command line can't be used. It is here for debug purposes only. + (listOf(exe) + args).joinToString(" ") +private val logger = fileLogger() diff --git a/platform/eel-impl/src/com/intellij/platform/eel/impl/local/EelLocalExecApi.kt b/platform/eel-impl/src/com/intellij/platform/eel/impl/local/EelLocalExecApi.kt index 9b38f212314a..e1a9a11906dc 100644 --- a/platform/eel-impl/src/com/intellij/platform/eel/impl/local/EelLocalExecApi.kt +++ b/platform/eel-impl/src/com/intellij/platform/eel/impl/local/EelLocalExecApi.kt @@ -15,10 +15,11 @@ import com.intellij.openapi.util.SystemInfo import com.intellij.platform.eel.* import com.intellij.platform.eel.EelExecApi.EnvironmentVariablesDeferred import com.intellij.platform.eel.channels.EelDelicateApi +import com.intellij.platform.eel.impl.bindProcessToScopeIfSet +import com.intellij.platform.eel.impl.commandLineForDebug import com.intellij.platform.eel.path.EelPath import com.intellij.platform.eel.provider.LocalEelDescriptor import com.intellij.platform.eel.provider.utils.awaitProcessResult -import com.intellij.platform.eel.provider.utils.bindToScope import com.intellij.platform.eel.provider.utils.stdoutString import com.intellij.util.EnvironmentUtil import com.intellij.util.ShellEnvironmentReader @@ -50,7 +51,7 @@ class EelLocalExecPosixApi( LocalEelPosixProcess.create(process, process::setWinSize) else LocalEelPosixProcess.create(process, null) - generatedBuilder.scope?.let { r.bindToScope(it) } + generatedBuilder.bindProcessToScopeIfSet(r) return r } @@ -83,10 +84,10 @@ class EelLocalExecPosixApi( val result = CompletableDeferred>() loginNonInteractive.job.invokeOnCompletion { error -> result.completeWith(when (error) { - null -> Result.success(loginNonInteractive.getCompleted()) - is EelExecApi.EnvironmentVariablesException -> Result.success(EnvironmentUtil.getSystemEnv()) - else -> Result.failure(error) - }) + null -> Result.success(loginNonInteractive.getCompleted()) + is EelExecApi.EnvironmentVariablesException -> Result.success(EnvironmentUtil.getSystemEnv()) + else -> Result.failure(error) + }) } return EnvironmentVariablesDeferred(result) @@ -223,12 +224,12 @@ class EelLocalExecWindowsApi : EelExecWindowsApi, LocalEelExecApi { generatedBuilder: EelExecApi.ExecuteProcessOptions, ): EelWindowsProcess { val process = executeImpl(generatedBuilder) - val commandLineForDebug = (listOf(generatedBuilder.exe) + generatedBuilder.args).joinToString(" ") + val commandLineForDebug = generatedBuilder.commandLineForDebug val r = if (process is PtyProcess) LocalEelWindowsProcess.create(process, process::setWinSize, commandLineForDebug) else LocalEelWindowsProcess.create(process, null, commandLineForDebug) - generatedBuilder.scope?.let { r.bindToScope(it) } + generatedBuilder.bindProcessToScopeIfSet(r) return r } diff --git a/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/impl.kt b/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/impl.kt index 29a19757788a..543edf6a9de3 100644 --- a/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/impl.kt +++ b/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/impl.kt @@ -16,7 +16,7 @@ class ProcessFunctions( withContext(NonCancellable) { logger.warn("Sending kill to $processNameForDebug") killProcess() - logger.warn("Kill send to $processNameForDebug, waiting") + logger.warn("Kill sent to $processNameForDebug, waiting") waitForExit() logger.warn("Process $processNameForDebug died") } @@ -25,7 +25,7 @@ class ProcessFunctions( /** * This is an implementation detail to be reused by other parts of a system. - * Do not call it directly, use [bindToScope] + * Do not call it directly. Use [com.intellij.platform.eel.EelExecApi.ExecuteProcessOptions.scope] */ @ApiStatus.Internal fun CoroutineScope.bindProcessToScopeImpl( diff --git a/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/processScopeUtil.kt b/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/processScopeUtil.kt deleted file mode 100644 index 2fea7dc5a754..000000000000 --- a/platform/eel-provider/src/com/intellij/platform/eel/provider/utils/processScopeUtil.kt +++ /dev/null @@ -1,24 +0,0 @@ -// 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.eel.provider.utils - -import com.intellij.openapi.diagnostic.fileLogger -import com.intellij.platform.eel.EelProcess -import kotlinx.coroutines.CoroutineScope -import org.jetbrains.annotations.ApiStatus - -private val logger = fileLogger() - -/** - * Kills process when scope finishes - */ -@ApiStatus.Internal -fun EelProcess.bindToScope(scope: CoroutineScope) { - scope.bindProcessToScopeImpl( - logger = logger, - processNameForDebug = this.toString(), - ProcessFunctions( - waitForExit = { exitCode.await() }, - killProcess = { kill() } - ) - ) -}