mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[python] show execution command and outputs for conda runner in case of parsing failures (PY-76274)
+ ZeroCodeStdoutParserTransformer + ZeroCodeJsonParserTransformer + add transformer showcase Merge-request: IJ-MR-172758 Merged-by: Vitaly Legchilkin <Vitaly.Legchilkin@jetbrains.com> GitOrigin-RevId: 1f293e8725a986eaed2a6050a3c6a240441f09fe
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bc2fcf0c88
commit
eb336fedc2
@@ -5,10 +5,6 @@ import com.intellij.openapi.diagnostic.Logger
|
||||
import com.jetbrains.python.Result.Failure
|
||||
import com.jetbrains.python.Result.Success
|
||||
import com.jetbrains.python.errorProcessing.MessageError
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import com.jetbrains.python.packaging.PyExecutionException
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
/**
|
||||
@@ -114,29 +110,9 @@ sealed class Result<out SUCC, out ERR> {
|
||||
fun <S> success(value: S): Success<S> = Success(value)
|
||||
fun <E> failure(error: E): Failure<E> = Failure(error)
|
||||
fun localizedError(message: @Nls String): Failure<MessageError> = failure(MessageError(message))
|
||||
|
||||
@ApiStatus.Internal
|
||||
inline fun <T> runCatching(body: () -> T): PyResult<T> = pyRunCatching(body)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UsagesOfObsoleteApi")
|
||||
@ApiStatus.Internal
|
||||
inline fun <T> pyRunCatching(body: () -> T): PyResult<T> {
|
||||
return try {
|
||||
PyResult.success(body())
|
||||
}
|
||||
catch (t: PyExecutionException) {
|
||||
PyResult.failure(t.pyError)
|
||||
}
|
||||
catch (t: CancellationException) {
|
||||
throw t
|
||||
}
|
||||
catch (t: IllegalArgumentException) {
|
||||
//Parse deserialization exceptions
|
||||
PyResult.localizedError(t.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps success result to another one with same error
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
### auto-generated section `build intellij.python.community.execService` start
|
||||
load("//build:compiler-options.bzl", "create_kotlinc_options")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library", "jvm_resources")
|
||||
|
||||
create_kotlinc_options(
|
||||
name = "custom_community-execService",
|
||||
opt_in = ["kotlin.time.ExperimentalTime"]
|
||||
)
|
||||
|
||||
jvm_resources(
|
||||
name = "community-execService_resources",
|
||||
files = glob(["resources/**/*"]),
|
||||
@@ -12,6 +18,7 @@ jvm_library(
|
||||
module_name = "intellij.python.community.execService",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/**/*.kt", "src/**/*.java"], allow_empty = True),
|
||||
kotlinc_opts = ":custom_community-execService",
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
"@lib//:jetbrains-annotations",
|
||||
@@ -25,6 +32,8 @@ jvm_library(
|
||||
"//platform/util/progress",
|
||||
"//platform/execution",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"@lib//:kotlinx-serialization-json",
|
||||
"@lib//:kotlinx-serialization-core",
|
||||
],
|
||||
runtime_deps = [":community-execService_resources"]
|
||||
)
|
||||
@@ -33,6 +42,7 @@ jvm_library(
|
||||
name = "community-execService_test_lib",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["tests/**/*.kt", "tests/**/*.java"], allow_empty = True),
|
||||
kotlinc_opts = ":custom_community-execService",
|
||||
associates = [":community-execService"],
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
@@ -57,6 +67,8 @@ jvm_library(
|
||||
"//platform/util/progress",
|
||||
"//platform/execution",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"@lib//:kotlinx-serialization-json",
|
||||
"@lib//:kotlinx-serialization-core",
|
||||
],
|
||||
runtime_deps = [":community-execService_resources"]
|
||||
)
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="kotlin-language" name="Kotlin">
|
||||
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
|
||||
<compilerSettings>
|
||||
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=kotlin.time.ExperimentalTime" />
|
||||
</compilerSettings>
|
||||
<compilerArguments>
|
||||
<stringArguments>
|
||||
<stringArg name="jvmTarget" arg="17" />
|
||||
<stringArg name="apiVersion" arg="2.2" />
|
||||
<stringArg name="languageVersion" arg="2.2" />
|
||||
</stringArguments>
|
||||
<arrayArguments>
|
||||
<arrayArg name="pluginClasspaths">
|
||||
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
|
||||
</arrayArg>
|
||||
</arrayArguments>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
@@ -28,5 +49,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.util.progress" />
|
||||
<orderEntry type="module" module-name="intellij.platform.execution" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel" />
|
||||
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
|
||||
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -164,6 +164,20 @@ object ZeroCodeStdoutTransformer : ProcessOutputTransformer<String> {
|
||||
if (processOutput.exitCode == 0) Result.success(processOutput.stdoutString.trim()) else Result.failure(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* A process output transformer that parses standard output using a provided parser function.
|
||||
*
|
||||
* @param T The type of the result produced by the transformer.
|
||||
* @param stdoutParser A function that takes a string (standard output) and parses it into a [Result] containing
|
||||
* either a successfully parsed result of type [T], or a failure with an optional [NlsSafe] error message.
|
||||
*/
|
||||
open class ZeroCodeStdoutParserTransformer<T>(val stdoutParser: (String) -> Result<T, @NlsSafe String?>) : ProcessOutputTransformer<T> {
|
||||
override fun invoke(processOutput: EelProcessExecutionResult): Result<T, @NlsSafe String?> {
|
||||
val data = ZeroCodeStdoutTransformer.invoke(processOutput).getOr { return it }
|
||||
return stdoutParser(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @property[env] Environment variables to be applied with the process run
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// 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.python.community.execService
|
||||
|
||||
import com.intellij.serialization.SerializationException
|
||||
import com.jetbrains.python.Result
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
/**
|
||||
* A functional interface defining a contract for parsing JSON strings into instances of type [T].
|
||||
*
|
||||
* Potential exceptions:
|
||||
* - [IllegalArgumentException]: Thrown if the input JSON string is invalid or improper.
|
||||
* - [SerializationException]: Thrown if there is a failure during the deserialization process.
|
||||
*
|
||||
* @param T The type of object expected as the result of JSON parsing.
|
||||
*/
|
||||
fun interface JsonParser<T> {
|
||||
fun parseJson(rawJson: String): T
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the JSON from the process execution result using the provided parser function.
|
||||
* [jsonParser] may throw [SerializationException] or [IllegalArgumentException] if output is invalid,
|
||||
* in this case the parsing exception localized message will be returned.
|
||||
*
|
||||
*
|
||||
* @param jsonParser Function that converts stdout string to type [T].
|
||||
* @return A [Result] containing either the successfully parsed [T] object, or a parsing failure message
|
||||
*/
|
||||
class ZeroCodeJsonParserTransformer<T>(jsonParser: JsonParser<T>) : ZeroCodeStdoutParserTransformer<T>(
|
||||
{
|
||||
try {
|
||||
Result.success(jsonParser.parseJson(it))
|
||||
}
|
||||
catch (t: SerializationException) {
|
||||
Result.failure(t.localizedMessage)
|
||||
}
|
||||
catch (t: IllegalArgumentException) {
|
||||
Result.failure(t.localizedMessage)
|
||||
}
|
||||
}
|
||||
) {
|
||||
companion object {
|
||||
inline operator fun <reified T> invoke(json: Json): ZeroCodeJsonParserTransformer<T> {
|
||||
return ZeroCodeJsonParserTransformer(JsonParser { json.decodeFromString(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-40
@@ -4,7 +4,10 @@ package com.intellij.python.junit5Tests.unit.alsoWin
|
||||
import com.intellij.platform.eel.EelPlatform
|
||||
import com.intellij.platform.eel.getShell
|
||||
import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.platform.eel.provider.utils.*
|
||||
import com.intellij.platform.eel.provider.utils.asEelChannel
|
||||
import com.intellij.platform.eel.provider.utils.consumeAsEelChannel
|
||||
import com.intellij.platform.eel.provider.utils.readWholeText
|
||||
import com.intellij.platform.eel.provider.utils.sendWholeText
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.EelHolder
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.EelSource
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.TestApplicationWithEel
|
||||
@@ -97,45 +100,6 @@ class ExecServiceShowCaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@EelSource
|
||||
fun testDataTransformer(eelHolder: EelHolder): Unit = timeoutRunBlocking {
|
||||
val eel = eelHolder.eel
|
||||
|
||||
data class Record(val name: String, val age: Int)
|
||||
|
||||
val (shell, execArg) = eel.exec.getShell()
|
||||
val args = Args(execArg, "echo Alice,25 && echo Bob,48")
|
||||
|
||||
val records = ExecService().execute((BinOnEel(shell.asNioPath())), args) { output ->
|
||||
val stdout = output.stdoutString.trim()
|
||||
when {
|
||||
output.exitCode == 123 -> {
|
||||
Result.success(emptyList())
|
||||
}
|
||||
output.exitCode != 0 -> {
|
||||
Result.failure(null)
|
||||
}
|
||||
stdout == "SOME_BUSINESS_ERROR" -> {
|
||||
Result.failure("My Business Error Description")
|
||||
}
|
||||
else -> {
|
||||
val records = stdout.lines().map { it.trim() }.map {
|
||||
val (name, age) = it.split(',')
|
||||
Record(name, age.trim().toInt())
|
||||
}
|
||||
Result.success(records)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
listOf(Record("Alice", 25), Record("Bob", 48)),
|
||||
records.getOrThrow()
|
||||
)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EelSource
|
||||
fun testSunnyDay(eelHolder: EelHolder): Unit = timeoutRunBlocking {
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// 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.python.junit5Tests.unit.alsoWin
|
||||
|
||||
import com.intellij.platform.eel.EelPlatform
|
||||
import com.intellij.platform.eel.getShell
|
||||
import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.platform.eel.provider.utils.stdoutString
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.EelHolder
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.EelSource
|
||||
import com.intellij.platform.testFramework.junit5.eel.params.api.TestApplicationWithEel
|
||||
import com.intellij.python.community.execService.*
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.getOrThrow
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
/**
|
||||
* How to use [ProcessOutputTransformer] inheritors.
|
||||
*/
|
||||
@TestApplicationWithEel(osesMayNotHaveRemoteEels = [OS.WINDOWS, OS.LINUX, OS.MAC])
|
||||
class ProcessOutputTransformerShowCaseTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@EelSource
|
||||
fun testProcessOutputTransformer(eelHolder: EelHolder): Unit = timeoutRunBlocking {
|
||||
val eel = eelHolder.eel
|
||||
|
||||
data class Record(val name: String, val age: Int)
|
||||
|
||||
val (shell, execArg) = eel.exec.getShell()
|
||||
val args = Args(execArg, "echo Alice,25 && echo Bob,48")
|
||||
|
||||
val records = ExecService().execute((BinOnEel(shell.asNioPath())), args) { output ->
|
||||
val stdout = output.stdoutString.trim()
|
||||
when {
|
||||
output.exitCode == 123 -> {
|
||||
Result.success(emptyList())
|
||||
}
|
||||
output.exitCode != 0 -> {
|
||||
Result.failure(null)
|
||||
}
|
||||
stdout == "SOME_BUSINESS_ERROR" -> {
|
||||
Result.failure("My Business Error Description")
|
||||
}
|
||||
else -> {
|
||||
val records = stdout.lines().map { it.trim() }.map {
|
||||
val (name, age) = it.split(',')
|
||||
Record(name, age.trim().toInt())
|
||||
}
|
||||
Result.success(records)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
listOf(Record("Alice", 25), Record("Bob", 48)),
|
||||
records.getOrThrow()
|
||||
)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EelSource
|
||||
@DisabledOnOs(OS.WINDOWS, disabledReason = "echo command creates extra escaping on Windows")
|
||||
fun testZeroCodeJsonParserTransformer(eelHolder: EelHolder): Unit = timeoutRunBlocking {
|
||||
val eel = eelHolder.eel
|
||||
|
||||
@Serializable
|
||||
data class Record(val name: String, val age: Int)
|
||||
|
||||
val testData = listOf(Record("Alice", 25), Record("Bob", 48))
|
||||
|
||||
val (shell, execArg) = eel.exec.getShell()
|
||||
|
||||
val json = Json { ignoreUnknownKeys = true }
|
||||
val serialized = json.encodeToString(testData)
|
||||
val args = Args(
|
||||
execArg,
|
||||
if (eel.platform is EelPlatform.Windows) "echo $serialized" else "echo '$serialized'"
|
||||
)
|
||||
|
||||
val recordsViaManualDecode = ExecService().execute(
|
||||
binary = (BinOnEel(shell.asNioPath())),
|
||||
args = args,
|
||||
processOutputTransformer = ZeroCodeJsonParserTransformer { jsonString ->
|
||||
json.decodeFromString<List<Record>>(jsonString)
|
||||
}
|
||||
)
|
||||
|
||||
assertEquals(testData, recordsViaManualDecode.getOrThrow())
|
||||
|
||||
val recordsViaGenericTransform = ExecService().execute(
|
||||
binary = (BinOnEel(shell.asNioPath())),
|
||||
args = args,
|
||||
processOutputTransformer = ZeroCodeJsonParserTransformer<List<Record>>(json)
|
||||
)
|
||||
|
||||
assertEquals(testData, recordsViaGenericTransform.getOrThrow())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.sdk
|
||||
|
||||
import com.intellij.python.community.execService.Args
|
||||
import com.intellij.python.community.execService.BinOnEel
|
||||
import com.intellij.python.community.execService.ExecOptions
|
||||
import com.intellij.python.community.execService.ExecService
|
||||
import com.intellij.python.community.execService.execGetStdout
|
||||
import com.intellij.python.community.execService.*
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
@@ -13,6 +9,16 @@ import java.nio.file.Path
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
@Internal
|
||||
suspend fun runExecutableWithProgress(
|
||||
executable: Path, workDir: Path?,
|
||||
timeout: Duration = 10.minutes,
|
||||
env: Map<String, String> = emptyMap(),
|
||||
vararg args: String,
|
||||
): PyResult<String> {
|
||||
return runExecutableWithProgress(executable, workDir, timeout, env, *args, transformer = ZeroCodeStdoutTransformer)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes a given executable with specified arguments within an optional project directory.
|
||||
@@ -24,12 +30,26 @@ import kotlin.time.Duration.Companion.minutes
|
||||
* @return A [Result] object containing the output of the command execution.
|
||||
*/
|
||||
@Internal
|
||||
suspend fun runExecutableWithProgress(
|
||||
suspend fun <T> runExecutableWithProgress(
|
||||
executable: Path, workDir: Path?,
|
||||
timeout: Duration = 10.minutes,
|
||||
env: Map<String, String> = emptyMap(),
|
||||
vararg args: String,
|
||||
): PyResult<String> {
|
||||
transformer: ProcessOutputTransformer<T>,
|
||||
): PyResult<T> {
|
||||
val execOptions = ExecOptions(timeout = timeout, env = env)
|
||||
return ExecService().execGetStdout(BinOnEel(executable, workDir), Args(*args), execOptions)
|
||||
|
||||
val errorHandlerTransformer: ProcessOutputTransformer<T> = { output ->
|
||||
when {
|
||||
output.exitCode == 0 -> transformer.invoke(output)
|
||||
else -> Result.failure(null)
|
||||
}
|
||||
}
|
||||
|
||||
return ExecService().execute(
|
||||
binary = BinOnEel(executable, workDir),
|
||||
args = Args(*args),
|
||||
options = execOptions,
|
||||
processOutputTransformer = errorHandlerTransformer
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ package com.jetbrains.python.sdk.conda.execution
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.platform.eel.isWindows
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
import com.intellij.python.community.execService.ProcessOutputTransformer
|
||||
import com.intellij.python.community.execService.ZeroCodeJsonParserTransformer
|
||||
import com.intellij.python.community.execService.ZeroCodeStdoutTransformer
|
||||
import com.intellij.util.ShellEnvironmentReader
|
||||
import com.jetbrains.python.PyBundle
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import com.jetbrains.python.packaging.common.PythonOutdatedPackage
|
||||
import com.jetbrains.python.packaging.common.PythonPackage
|
||||
import com.jetbrains.python.pyRunCatching
|
||||
import com.jetbrains.python.sdk.conda.execution.models.CondaEnvInfo
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
|
||||
import com.jetbrains.python.sdk.runExecutableWithProgress
|
||||
@@ -24,62 +26,82 @@ import kotlin.time.Duration.Companion.minutes
|
||||
object CondaExecutor {
|
||||
suspend fun createNamedEnv(condaPath: Path, envName: String, pythonVersion: String): PyResult<Unit> {
|
||||
val args = listOf("create", "-y", "-n", envName, "python=${pythonVersion}")
|
||||
return runConda(condaPath, args, null).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, args, null
|
||||
) { PyResult.success(Unit) }
|
||||
}
|
||||
|
||||
suspend fun createUnnamedEnv(condaPath: Path, envPrefix: String, pythonVersion: String): PyResult<Unit> {
|
||||
val args = listOf("create", "-y", "-p", envPrefix, "python=${pythonVersion}")
|
||||
return runConda(condaPath, args, null).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, args, null
|
||||
) { PyResult.success(Unit) }
|
||||
}
|
||||
|
||||
suspend fun createFileEnv(condaPath: Path, environmentYaml: Path): PyResult<Unit> {
|
||||
val args = listOf("env", "create", "-f", environmentYaml.pathString)
|
||||
return runConda(condaPath, args, null).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, args, null
|
||||
) { PyResult.success(Unit) }
|
||||
}
|
||||
|
||||
suspend fun updateFromEnvironmentFile(condaPath: Path, envYmlPath: String, envIdentity: PyCondaEnvIdentity): PyResult<Unit> {
|
||||
val args = listOf("env", "update", "--file", envYmlPath, "--prune")
|
||||
return runConda(condaPath, args, envIdentity).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, args, envIdentity
|
||||
) { PyResult.success(Unit) }
|
||||
}
|
||||
|
||||
suspend fun listEnvs(condaPath: Path): PyResult<CondaEnvInfo> {
|
||||
val args = listOf("env", "list", "--json")
|
||||
val json = runConda(condaPath, args, null).getOr { return it }
|
||||
return pyRunCatching {
|
||||
CondaExecutionParser.parseListEnvironmentsOutput(json)
|
||||
}
|
||||
return runConda(
|
||||
condaPath, args, null,
|
||||
transformer = ZeroCodeJsonParserTransformer { CondaExecutionParser.parseListEnvironmentsOutput(it) }
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun exportEnvironmentFile(condaPath: Path, envIdentity: PyCondaEnvIdentity): PyResult<String> {
|
||||
return runConda(condaPath, listOf("env", "export") + listOf("--no-builds"), envIdentity)
|
||||
return runConda(
|
||||
condaPath, listOf("env", "export") + listOf("--no-builds"), envIdentity,
|
||||
transformer = ZeroCodeStdoutTransformer
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun listPackages(condaPath: Path, envIdentity: PyCondaEnvIdentity): PyResult<List<PythonPackage>> {
|
||||
return runConda(condaPath, listOf("list", "--json"), envIdentity).mapSuccess {
|
||||
CondaExecutionParser.parseCondaPackageList(it)
|
||||
}
|
||||
return runConda(
|
||||
condaPath, listOf("list", "--json"), envIdentity,
|
||||
transformer = ZeroCodeJsonParserTransformer { CondaExecutionParser.parseCondaPackageList(it) }
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun installPackages(condaPath: Path, envIdentity: PyCondaEnvIdentity, packages: List<String>, options: List<String>): PyResult<Unit> {
|
||||
return runConda(condaPath, listOf("install") + packages + listOf("-y") + options, envIdentity).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, listOf("install") + packages + listOf("-y") + options, envIdentity
|
||||
) { PyResult.success(Unit) }
|
||||
|
||||
}
|
||||
|
||||
suspend fun uninstallPackages(condaPath: Path, envIdentity: PyCondaEnvIdentity, packages: List<String>): PyResult<Unit> {
|
||||
return runConda(condaPath, listOf("uninstall") + packages + "-y", envIdentity).mapSuccess { }
|
||||
return runConda(
|
||||
condaPath, listOf("uninstall") + packages + "-y", envIdentity
|
||||
) { PyResult.success(Unit) }
|
||||
}
|
||||
|
||||
|
||||
suspend fun listOutdatedPackages(condaPath: Path, envIdentity: PyCondaEnvIdentity): PyResult<List<PythonOutdatedPackage>> {
|
||||
val jsonPyResult = runConda(condaPath, listOf("update", "--dry-run", "--all", "--json"), envIdentity).getOr {
|
||||
return it
|
||||
}
|
||||
return pyRunCatching {
|
||||
CondaExecutionParser.parseOutdatedOutputs(jsonPyResult)
|
||||
}
|
||||
return runConda(
|
||||
condaPath, listOf("update", "--dry-run", "--all", "--json"), envIdentity,
|
||||
transformer = ZeroCodeJsonParserTransformer { CondaExecutionParser.parseOutdatedOutputs(it) }
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun runConda(condaPath: Path, args: List<String>, condaEnvIdentity: PyCondaEnvIdentity?, timeout: Duration = 15.minutes): PyResult<String> {
|
||||
private suspend fun <T> runConda(
|
||||
condaPath: Path,
|
||||
args: List<String>,
|
||||
condaEnvIdentity: PyCondaEnvIdentity?,
|
||||
timeout: Duration = 15.minutes,
|
||||
transformer: ProcessOutputTransformer<T>,
|
||||
): PyResult<T> {
|
||||
val condaEnv = when (condaEnvIdentity) {
|
||||
is PyCondaEnvIdentity.UnnamedEnv -> {
|
||||
if (condaEnvIdentity.isBase)
|
||||
@@ -98,7 +120,7 @@ object CondaExecutor {
|
||||
}
|
||||
|
||||
val runArgs = (args + condaEnv).toTypedArray()
|
||||
return runExecutableWithProgress(condaPath, null, timeout, env = envs, *runArgs)
|
||||
return runExecutableWithProgress(condaPath, null, timeout, env = envs, *runArgs, transformer = transformer)
|
||||
}
|
||||
|
||||
private fun getFixedEnvs(condaPath: Path): PyResult<Map<String, String>> {
|
||||
|
||||
Reference in New Issue
Block a user