[eel] IJPL-172897: cleanup: remove deprecated exec api builder

GitOrigin-RevId: 4eee2a51401f229a57ac4f5057e078f57fc9bcb9
This commit is contained in:
Andrii Zinchenko
2025-04-08 16:10:58 +00:00
committed by intellij-monorepo-bot
parent e3fa322176
commit a7e22b196b
18 changed files with 44 additions and 137 deletions
@@ -78,7 +78,7 @@ suspend fun EelExecApi.where(exe: String): EelPath? {
@ApiStatus.Experimental
suspend fun Path.exec(vararg args: String, timeout: Duration = Int.MAX_VALUE.days): EelResult<EelProcessExecutionResult, EelExecApi.ExecuteProcessError?> {
val process = getEelDescriptor().upgrade().exec.executeProcess(pathString, *args).getOr { return it }
val process = getEelDescriptor().upgrade().exec.execute(pathString, *args).eelIt().getOr { return it }
val output = withTimeoutOrNull(timeout) {
process.awaitProcessResult()
}
@@ -59,45 +59,6 @@ interface EelExecApi {
* [ExecuteProcessOptions.workingDirectory] is the path on the Linux host. There's no automatic path mapping in this interface.
*/
val exe: String
@Deprecated("Use generated builders. See usages of com.intellij.platform.eel.GeneratedBuilder.Result")
interface Builder {
fun args(args: List<String>): Builder
fun env(env: Map<String, String>): Builder
/**
* When set pty, be sure to accept esc codes for a terminal you are emulating.
* This terminal should also be set in `TERM` environment variable, so setting it in [env] worth doing.
* If not set, `xterm` will be used as a most popular one.
*
* See `termcap(2)`, `terminfo(2)`, `ncurses(3X)` and ISBN `0937175226`.
*/
fun ptyOrStdErrSettings(pty: PtyOrStdErrSettings?): Builder
fun workingDirectory(workingDirectory: EelPath?): Builder
fun build(): ExecuteProcessOptions
}
companion object {
/**
* Creates builder to start a process on a local or remote machine.
* stdin, stdout and stderr of the process are always forwarded, if there are.
*
* Beware that processes with [ExecuteProcessOptions.ptyOrStdErrSettings] usually don't have stderr.
* The [EelProcess.stderr] must be an empty stream in such case.
*
* By default, environment is always inherited, which may be unwanted. [ExecuteProcessOptions.env] allows
* to alter some environment variables, it doesn't clear the variables from the parent. When the process should be started in an
* environment like in a terminal, the response of [fetchLoginShellEnvVariables] should be put into [ExecuteProcessOptions.env].
*
* All argument, all paths, should be valid for the remote machine. F.i., if the IDE runs on Windows, but IJent runs on Linux,
* [ExecuteProcessOptions.workingDirectory] is the path on the Linux host. There's no automatic path mapping in this interface.
*/
@Deprecated("Use generated builders. See usages of com.intellij.platform.eel.GeneratedBuilder.Result")
fun Builder(exe: String): Builder = ExecuteProcessBuilderImpl(exe)
@Deprecated("Use generated builders. See usages of com.intellij.platform.eel.GeneratedBuilder.Result")
fun Builder(exe: String, arg1: String, vararg args: String): Builder = Builder(exe).args(listOf(arg1, *args))
}
}
/**
@@ -151,60 +112,5 @@ interface EelExecApi {
data object RedirectStdErr : PtyOrStdErrSettings
}
/** Docs: [EelExecApi.executeProcessBuilder] */
@CheckReturnValue
suspend inline fun EelExecApi.execute(exe: String, setup: (EelExecApi.ExecuteProcessOptions.Builder).() -> Unit): EelResult<EelProcess, EelExecApi.ExecuteProcessError> {
val builder = EelExecApi.ExecuteProcessOptions.Builder(exe).apply(setup).build()
return execute(builder)
}
fun EelExecApi.execute(exe: String, vararg args: String): EelExecApiHelpers.Execute =
execute(exe).args(*args)
/** Docs: [EelExecApi.executeProcessBuilder] */
@CheckReturnValue
suspend fun EelExecApi.executeProcess(exe: String, vararg args: String): EelResult<EelProcess, EelExecApi.ExecuteProcessError> =
execute(EelExecApi.ExecuteProcessOptions.Builder(exe).args(listOf(*args)).build())
fun EelExecApi.ExecuteProcessOptions.Builder.args(first: String, vararg other: String): EelExecApi.ExecuteProcessOptions.Builder =
args(listOf(first, *other))
private data class ExecuteProcessBuilderImpl(
override val exe: String,
override var args: List<String> = listOf(),
override var env: Map<String, String> = mapOf(),
override var ptyOrStdErrSettings: PtyOrStdErrSettings? = null,
override var workingDirectory: EelPath? = null,
) : EelExecApi.ExecuteProcessOptions, EelExecApi.ExecuteProcessOptions.Builder {
override fun toString(): String =
"GrpcExecuteProcessBuilder(" +
"exe='$exe', " +
"args=$args, " +
"env=$env, " +
"ptyOrStdErrSettings=$ptyOrStdErrSettings, " +
"workingDirectory=$workingDirectory" +
")"
override fun args(args: List<String>): ExecuteProcessBuilderImpl = apply {
this.args = args
}
override fun env(env: Map<String, String>): ExecuteProcessBuilderImpl = apply {
this.env = env
}
override fun ptyOrStdErrSettings(ptyOrStderrSettings: PtyOrStdErrSettings?): ExecuteProcessBuilderImpl = apply {
this.ptyOrStdErrSettings = ptyOrStderrSettings
}
override fun workingDirectory(workingDirectory: EelPath?): ExecuteProcessBuilderImpl = apply {
this.workingDirectory = workingDirectory
}
override fun build(): EelExecApi.ExecuteProcessOptions {
return copy()
}
}
execute(exe).args(*args)
@@ -7,7 +7,7 @@ import com.intellij.platform.eel.channels.EelSendChannel
import kotlinx.coroutines.Deferred
/**
* Represents some process that was launched via [EelExecApi.executeProcess].
* Represents some process that was launched via [EelExecApi.execute].
*
*/
interface EelProcess: KillableProcess {
@@ -279,13 +279,13 @@ private class EelTargetEnvironment(override val request: EelTargetEnvironmentReq
override fun createProcess(commandLine: TargetedCommandLine, indicator: ProgressIndicator): Process {
val command = commandLine.collectCommandsSynchronously()
val builder = EelExecApi.ExecuteProcessOptions.Builder(command.first())
val builder = eel.exec.execute(command.first())
builder.args(command.drop(1))
builder.env(commandLine.environmentVariables)
builder.workingDirectory(commandLine.workingDirectory?.let { EelPath.parse(it, eel.descriptor) })
return runBlockingCancellable { eel.exec.execute(builder.build()).getOrThrow().convertToJavaProcess() }
return runBlockingCancellable { builder.getOrThrow().convertToJavaProcess() }
}
override val targetPlatform: TargetPlatform = request.targetPlatform
@@ -15,8 +15,8 @@ import com.intellij.openapi.diagnostic.runAndLogException
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.ui.Messages
import com.intellij.platform.eel.EelResult
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.provider.utils.copy
import com.intellij.platform.eel.executeProcess
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.provider.utils.asEelChannel
import com.intellij.platform.ide.progress.ModalTaskOwner
@@ -78,7 +78,7 @@ abstract class AbstractIjentVerificationAction : DumbAwareAction() {
}
launch {
val process = when (val p = ijent.exec.executeProcess("uname", "-a")) {
val process = when (val p = ijent.exec.execute("uname", "-a").eelIt()) {
is EelResult.Error -> error(p)
is EelResult.Ok -> p.value
}
@@ -89,7 +89,7 @@ internal fun javaHomeFinderEel(descriptor: EelDescriptor): JavaHomeFinderBasic {
processRunner = { cmd ->
runBlockingMaybeCancellable {
// TODO Introduce Windows Registry access in EelApi
val process = eel.exec.execute(EelExecApi.ExecuteProcessOptions.Builder(cmd.first()).args(cmd.drop(1)).build()).getOr {
val process = eel.exec.execute(cmd.first()).args(cmd.drop(1)).eelIt().getOr {
// registry reading can fail, in this case we return no output just like `com.intellij.openapi.util.io.WindowsRegistryUtil.readRegistry`
return@runBlockingMaybeCancellable ""
}
@@ -133,12 +133,10 @@ class JdkInstaller : JdkInstallerBase() {
path.asEelPath().toString()
override fun execute(command: List<String>, dir: String, timeout: Int): ProcessOutput = runBlockingCancellable {
val builder = EelExecApi
.ExecuteProcessOptions.Builder(command.first())
val builder = eel.exec.execute(command.first())
.args(command.drop(1))
.workingDirectory(EelPath.parse(dir, eel.descriptor))
.build()
val process = eel.exec.execute(builder).getOrThrow()
val process = builder.getOrThrow()
try {
withTimeout(timeout.milliseconds) {
process.awaitProcessResult().let { ProcessOutput(it.stdoutString, it.stderrString, it.exitCode, false, false) }
@@ -16,6 +16,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelResult
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.path.EelPath
import com.intellij.platform.ijent.IjentChildProcess
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
@@ -136,13 +137,13 @@ fun runProcessBlocking(
}
val scope = @OptIn(DelicateCoroutinesApi::class) (wslIjentManager.processAdapterScope)
when (val processResult = ijentApi.exec.execute(EelExecApi.ExecuteProcessOptions.Builder(exePath)
when (val processResult = ijentApi.exec.execute(exePath)
.args(args)
.env(explicitEnvironmentVariables)
.ptyOrStdErrSettings(ptyOrStdErrSettings)
.workingDirectory(workingDirectory?.let { EelPath.parse(it, ijentApi.descriptor) })
.build()
)) {
.eelIt()
) {
is EelResult.Ok ->
(processResult.value as IjentChildProcess).toProcess(
coroutineScope = scope,
@@ -56,7 +56,7 @@ class EelLocalExecApiTest {
@Test
fun testExitCode(): Unit = timeoutRunBlocking {
when (val r = localEel.exec.executeProcess("something that doesn't exist for sure")) {
when (val r = localEel.exec.execute("something that doesn't exist for sure").eelIt()) {
is EelResult.Error ->
// **nix: ENOENT 2 No such file or directory
// win: ERROR_FILE_NOT_FOUND 2 winerror.h
@@ -74,13 +74,13 @@ class EelLocalExecApiTest {
@CartesianTest.Enum ptyManagement: PTYManagement,
): Unit = timeoutRunBlocking(1.minutes) {
val builder = executor.createBuilderToExecuteMain()
val builder = executor.createBuilderToExecuteMain(localEel.exec)
builder.ptyOrStdErrSettings(when (ptyManagement) {
PTYManagement.NO_PTY -> null
PTYManagement.PTY_SIZE_FROM_START -> Pty(PTY_COLS, PTY_ROWS, true)
PTYManagement.PTY_RESIZE_LATER -> Pty(PTY_COLS - 1, PTY_ROWS - 1, true) // wrong tty size: will resize in the test
})
when (val r = localEel.exec.execute(builder.build())) {
when (val r = builder.eelIt()) {
is EelResult.Error -> Assertions.fail(r.error.message)
is EelResult.Ok -> {
val process = r.value
@@ -85,7 +85,7 @@ class EelLocalTunnelApiTest {
@Test
fun testServerListensForConnection(): Unit = timeoutRunBlocking(1.minutes) {
val helper = localEel.exec.execute(clientExecutor.createBuilderToExecuteMain().build()).getOrThrow()
val helper = clientExecutor.createBuilderToExecuteMain(localEel.exec).getOrThrow()
val acceptor = localEel.tunnels.getAcceptorForRemotePort().getOrThrow()
helper.stdin.sendWholeText(acceptor.boundAddress.port.toString() + "\n").getOrThrow()
val conn = acceptor.incomingConnections.receive()
@@ -141,7 +141,7 @@ class EelLocalTunnelApiTest {
private suspend fun withServer(block: suspend CoroutineScope.(EelTunnelsApi.Connection, EelProcess) -> Unit) {
val helper = localEel.exec.execute(serverExecutor.createBuilderToExecuteMain().build()).getOrThrow()
val helper = serverExecutor.createBuilderToExecuteMain(localEel.exec).getOrThrow()
try {
val port = helper.stdout.consumeAsInputStream().bufferedReader().readLine().trim().toInt()
val connection = localEel.tunnels.getConnectionToRemotePort().port(port.toUShort()).preferV4().getOrThrow()
@@ -6,6 +6,8 @@ import com.intellij.openapi.application.PathManager
import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.util.NlsSafe
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelExecApiHelpers
import com.intellij.platform.eel.execute
import com.intellij.util.PathUtil
import com.intellij.util.SystemProperties
import org.jetbrains.jps.model.java.JpsJavaExtensionService
@@ -32,7 +34,7 @@ internal class JavaMainClassExecutor(clazz: Class<*>, vararg args: String) {
/**
* Execute `main` method
*/
fun createBuilderToExecuteMain(): EelExecApi.ExecuteProcessOptions.Builder = EelExecApi.ExecuteProcessOptions.Builder(exe).env(env).args(args)
fun createBuilderToExecuteMain(exec: EelExecApi): EelExecApiHelpers.Execute = exec.execute(exe).env(env).args(args)
private companion object {
private fun getClassPathForClass(clazz: Class<*>): String {
@@ -14,6 +14,7 @@ import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.PathExecLazyValue
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.provider.asEelPath
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
@@ -216,14 +217,14 @@ object ExecUtil {
val env = builder.environment()
val workingDir = builder.directory()?.toPath()?.asEelPath()
@Suppress("DEPRECATION") val options = EelExecApi.ExecuteProcessOptions.Builder(exe)
val options = execute(exe)
.args(rest)
.workingDirectory(workingDir)
.env(env)
.ptyOrStdErrSettings(pty?.run { EelExecApi.Pty(initialColumns, initialRows, !consoleMode) })
return runBlockingMaybeCancellable {
execute(options.build()).getOrThrow().convertToJavaProcess()
options.getOrThrow().convertToJavaProcess()
}
}
}
@@ -32,6 +32,7 @@ import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelExecApi.Pty
import com.intellij.platform.eel.EelResult
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.path.EelPath
import com.intellij.platform.eel.provider.asEelPath
import com.intellij.platform.eel.provider.getEelDescriptor
@@ -72,7 +73,7 @@ class MavenShCommandLineState(val environment: ExecutionEnvironment, private val
return runWithModalProgressBlocking(myConfiguration.project, RunnerBundle.message("maven.target.run.label")) {
val eelApi = myConfiguration.project.getEelDescriptor().upgrade()
val processOptions = EelExecApi.ExecuteProcessOptions.Builder(if (isWindows()) "cmd.exe" else "/bin/sh")
val processOptions = eelApi.exec.execute(if (isWindows()) "cmd.exe" else "/bin/sh")
.env(getEnv(eelApi.exec.fetchLoginShellEnvVariables(), debug))
.workingDirectory(Path(myConfiguration.runnerParameters.workingDirPath).asEelPath())
.args(getArgs(eelApi)).let {
@@ -80,9 +81,9 @@ class MavenShCommandLineState(val environment: ExecutionEnvironment, private val
it.ptyOrStdErrSettings(Pty(-1, -1, true))
}
else it
}.build()
}
val result = eelApi.exec.execute(processOptions)
val result = processOptions.eelIt()
return@runWithModalProgressBlocking when (result) {
is EelResult.Error -> {
@@ -20,6 +20,7 @@ import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelTunnelsApi
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.fs.pathSeparator
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.path.EelPath
@@ -202,12 +203,12 @@ private class EelMavenCmdState(
* @see [com.intellij.execution.eel.EelApiWithPathsNormalization]
*/
val exe = Path.of(cmd.exePath).asEelPath()
val builder = EelExecApi.ExecuteProcessOptions.Builder(exe.toString())
val builder = eel.exec.execute(exe.toString())
.args(cmd.parametersList.parameters)
.env(cmd.environment)
.workingDirectory(EelPath.parse(getWorkingDirectory(), eel.descriptor))
eel.exec.execute(builder.build()).getOrThrow()
builder.getOrThrow()
}
return object : KillableColoredProcessHandler(eelProcess.convertToJavaProcess(), cmd) {
@@ -12,6 +12,7 @@ import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelExecApi.ExecuteProcessError
import com.intellij.platform.eel.EelResult
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.provider.asEelPath
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.util.PathUtil
@@ -114,15 +115,12 @@ private suspend fun doStartProcess(
workingDirectory: Path,
initialTermSize: TermSize,
): PtyProcess {
// TODO migrate to generated builders in 252 (not available in 251)
@Suppress("DEPRECATION")
val execOptions = EelExecApi.ExecuteProcessOptions.Builder(command.first())
val execOptions = eelApi.exec.execute(command.first())
.args(command.takeLast(command.size - 1))
.env(envs)
.workingDirectory(workingDirectory.asEelPath())
.ptyOrStdErrSettings(EelExecApi.Pty(initialTermSize.columns, initialTermSize.rows, true))
.build()
val processResult = eelApi.exec.execute(execOptions)
val processResult = execOptions.eelIt()
return when (processResult) {
is EelResult.Ok -> processResult.value.convertToJavaProcess() as PtyProcess
is EelResult.Error -> throw ErrnoException(processResult.error)
@@ -126,11 +126,10 @@ private suspend fun WhatToExec.buildExecutableProcess(args: List<String>, option
@CheckReturnValue
private suspend fun EelExecutableProcess.run(): Result<EelProcess, ExecException> {
val workDirectoryEelPath = workingDirectory?.let { EelPath.parse(it.toString(), eel.descriptor) }
val executionResult = eel.exec.execute(exe) {
args(args)
env(env)
workingDirectory(workDirectoryEelPath)
}
val executionResult = eel.exec.execute(exe)
.args(args)
.env(env)
.workingDirectory(workDirectoryEelPath).eelIt()
val process = executionResult.getOr { err ->
return failAsCantStart(err.error)
@@ -10,6 +10,7 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.provider.localEel
import com.intellij.platform.eel.provider.utils.readWholeText
@@ -138,13 +139,12 @@ class PyVirtualEnvTerminalCustomizerTest {
val exe = command[0]
val args = if (command.size == 1) emptyList() else command.subList(1, command.size)
val execOptions = EelExecApi.ExecuteProcessOptions.Builder(exe)
val execOptions = localEel.exec.execute(exe)
.args(args)
.env(shellOptions.envVariables + mapOf(Pair("TERM", "dumb")))
// Unix shells do not activate with out tty
.ptyOrStdErrSettings(if (SystemInfo.isWindows) null else EelExecApi.Pty(100, 100, true))
.build()
val process = localEel.exec.execute(execOptions).getOrThrow()
val process = execOptions.getOrThrow()
try {
val stderr = async {
process.stderr.readWholeText().getOrThrow()
@@ -5,7 +5,7 @@ import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.eel.executeProcess
import com.intellij.platform.eel.execute
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.utils.readWholeText
@@ -48,7 +48,7 @@ class SystemPythonServiceShowCaseTest {
for (systemPython in SystemPythonService().findSystemPythons(forceRefresh = true)) {
fileLogger().info("Python found: $systemPython")
val eelApi = systemPython.pythonBinary.getEelDescriptor().upgrade()
val process = eelApi.exec.executeProcess(systemPython.pythonBinary.pathString, "--version").getOrThrow()
val process = eelApi.exec.execute(systemPython.pythonBinary.pathString, "--version").getOrThrow()
val output = async {
(if (systemPython.languageLevel.isPy3K) process.stdout else process.stderr).readWholeText().getOrThrow()
}