cleanup [eel]: Report command line of process bound to scope.

`com.intellij.platform.eel.EelExecApi.ExecuteProcessOptions.scope` implementation had a bug: it reported process hash instead of a command line. It is now fixed.

We also cleaned up API a little.

GitOrigin-RevId: 900b1c8f671827bdddd7b893a5b13114aa4ab6a1
This commit is contained in:
Ilya.Kazakevich
2025-11-10 23:09:31 +00:00
committed by intellij-monorepo-bot
parent 8b011b1268
commit 35280ee3a1
4 changed files with 42 additions and 34 deletions
@@ -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()
@@ -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<Map<String, String>>()
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
}
@@ -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(
@@ -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() }
)
)
}