mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-82119 Packaging: Fix bugs in Conda
Signed-off-by: Nikita.Ashihmin <nikita.ashihmin@jetbrains.com> GitOrigin-RevId: 0ae5236e0d1c72de889f15563bc08a541cec834f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b219e8ca22
commit
a2b962df79
@@ -18,7 +18,7 @@ import com.jetbrains.python.sdk.getOrCreateAdditionalData
|
||||
internal class CondaPackageManagerEngine(private val sdk: Sdk) : PythonPackageManagerEngine {
|
||||
suspend fun updateFromEnvironmentFile(envFile: VirtualFile): PyResult<Unit> {
|
||||
val env = getEnvData()
|
||||
return CondaExecutor.updateFromEnvironmentFile(env.condaPath, envFile.path)
|
||||
return CondaExecutor.updateFromEnvironmentFile(env.condaPath, envFile.path, env.envIdentity)
|
||||
}
|
||||
|
||||
suspend fun exportToEnvironmentFile(): PyResult<String> {
|
||||
@@ -74,8 +74,4 @@ internal class CondaPackageManagerEngine(private val sdk: Sdk) : PythonPackageMa
|
||||
PyResult.success(quoted)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
}
|
||||
}
|
||||
+8
@@ -15,6 +15,14 @@ import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
object CondaEnvironmentYmlParser {
|
||||
fun readNameFromFile(file: VirtualFile): String? {
|
||||
val text = FileDocumentManager.getInstance().getDocument(file)?.text ?: return null
|
||||
val yaml = Yaml(configuration = YamlConfiguration(strictMode = false))
|
||||
val environment: YamlMap = yaml.parseToYamlNode(text).yamlMap
|
||||
|
||||
return environment.get<YamlScalar>("name")?.yamlScalar?.content
|
||||
}
|
||||
|
||||
fun fromFile(file: VirtualFile): List<PyRequirement>? {
|
||||
val pyRequirements = runCatching { readDeps(file) }.onFailure {
|
||||
thisLogger().info("Cannot parse deps from ${file.readText()}", it)
|
||||
|
||||
@@ -18,18 +18,20 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
import com.intellij.platform.util.progress.RawProgressReporter
|
||||
import com.jetbrains.python.conda.loadLocalPythonCondaPath
|
||||
import com.jetbrains.python.conda.saveLocalPythonCondaPath
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import com.jetbrains.python.errorProcessing.asPythonResult
|
||||
import com.jetbrains.python.getOrThrow
|
||||
import com.jetbrains.python.onFailure
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.sdk.PythonSdkAdditionalData
|
||||
import com.jetbrains.python.sdk.PythonSdkType
|
||||
import com.jetbrains.python.conda.loadLocalPythonCondaPath
|
||||
import com.jetbrains.python.conda.saveLocalPythonCondaPath
|
||||
import com.jetbrains.python.sdk.flavors.PyFlavorAndData
|
||||
import com.jetbrains.python.sdk.flavors.conda.*
|
||||
import com.jetbrains.python.sdk.getOrCreateAdditionalData
|
||||
import com.jetbrains.python.target.PyTargetAwareAdditionalData
|
||||
import com.jetbrains.python.util.ShowingMessageErrorSync
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.future.await
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -48,8 +50,9 @@ internal val condaSupportedLanguages: List<LanguageLevel>
|
||||
.asReversed()
|
||||
.filter { it < LanguageLevel.PYTHON313 }
|
||||
|
||||
val condaLatestSupportedLanguage: LanguageLevel @ApiStatus.Internal get() =
|
||||
condaSupportedLanguages.maxWith(LanguageLevel.VERSION_COMPARATOR)
|
||||
val condaLatestSupportedLanguage: LanguageLevel
|
||||
@ApiStatus.Internal get() =
|
||||
condaSupportedLanguages.maxWith(LanguageLevel.VERSION_COMPARATOR)
|
||||
|
||||
/**
|
||||
* See [com.jetbrains.env.conda.PyCondaSdkTest]
|
||||
@@ -73,7 +76,9 @@ suspend fun PyCondaCommand.createCondaSdkFromExistingEnv(
|
||||
sdkModificator.sdkAdditionalData = additionalData
|
||||
// homePath is not required by conda, but used by lots of tools all over the code and required by CondaPathFix
|
||||
// Because homePath is not set yet, CondaPathFix does not work
|
||||
sdkModificator.homePath = getCondaPythonBinaryPath(project, condaEnv, targetConfig).getOrThrow()
|
||||
sdkModificator.homePath = getCondaPythonBinaryPath(project, condaEnv, targetConfig).onFailure {
|
||||
ShowingMessageErrorSync.emit(it)
|
||||
}.getOrThrow()
|
||||
edtWriteAction {
|
||||
sdkModificator.commitChanges()
|
||||
}
|
||||
|
||||
@@ -6,16 +6,22 @@ import com.jetbrains.python.packaging.conda.CondaPackage
|
||||
import com.jetbrains.python.sdk.conda.execution.models.CondaEnvInfo
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
|
||||
internal object CondaExecutionParser {
|
||||
private val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true }
|
||||
fun parseCondaPackageList(text: String): List<CondaPackage> {
|
||||
return text.lineSequence()
|
||||
.filterNot { it.startsWith("#") }
|
||||
.map { line -> line.split(listLineParser) }
|
||||
.filterNot { it.size < 2 }
|
||||
//TODO: fix
|
||||
.map { CondaPackage(it[0], it[1], editableMode = false, installedWithPip = (it.size >= 4 && it[3] == "pypi")) }
|
||||
val parsed = json.parseToJsonElement(text).jsonArray
|
||||
return parsed.map {
|
||||
val jsonObject = it.jsonObject
|
||||
val name = jsonObject["name"]?.jsonPrimitive?.content ?: ""
|
||||
val version = jsonObject["version"]?.jsonPrimitive?.content ?: ""
|
||||
val channel = jsonObject["channel"]?.jsonPrimitive?.content ?: ""
|
||||
val isPypi = channel == "pypi"
|
||||
CondaPackage(name, version, editableMode = false, installedWithPip = isPypi)
|
||||
}
|
||||
.sortedWith(compareBy(CondaPackage::name))
|
||||
.toList()
|
||||
}
|
||||
@@ -51,6 +57,4 @@ internal object CondaExecutionParser {
|
||||
|
||||
@Serializable
|
||||
private data class CondaPackageInfo(val name: String, val version: String)
|
||||
|
||||
private val listLineParser = "\\s+".toRegex()
|
||||
}
|
||||
@@ -37,9 +37,9 @@ object CondaExecutor {
|
||||
return runConda(condaPath, args, null).mapSuccess { }
|
||||
}
|
||||
|
||||
suspend fun updateFromEnvironmentFile(condaPath: Path, envYmlPath: String): PyResult<Unit> {
|
||||
suspend fun updateFromEnvironmentFile(condaPath: Path, envYmlPath: String, envIdentity: PyCondaEnvIdentity): PyResult<Unit> {
|
||||
val args = listOf("env", "update", "--file", envYmlPath, "--prune")
|
||||
return runConda(condaPath, args, null).mapSuccess { }
|
||||
return runConda(condaPath, args, envIdentity).mapSuccess { }
|
||||
}
|
||||
|
||||
suspend fun listEnvs(condaPath: Path): PyResult<CondaEnvInfo> {
|
||||
@@ -55,7 +55,7 @@ object CondaExecutor {
|
||||
}
|
||||
|
||||
suspend fun listPackages(condaPath: Path, envIdentity: PyCondaEnvIdentity): PyResult<List<PythonPackage>> {
|
||||
return runConda(condaPath, listOf("list"), envIdentity).mapSuccess {
|
||||
return runConda(condaPath, listOf("list", "--json"), envIdentity).mapSuccess {
|
||||
CondaExecutionParser.parseCondaPackageList(it)
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ object CondaExecutor {
|
||||
return it
|
||||
}
|
||||
|
||||
val runArgs = (condaEnv + args).toTypedArray()
|
||||
val runArgs = (args + condaEnv).toTypedArray()
|
||||
return runExecutableWithProgress(condaPath, null, timeout, env = envs, *runArgs)
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ object CondaExecutor {
|
||||
}
|
||||
else value
|
||||
|
||||
key to fixedVal.toString()
|
||||
key to fixedVal
|
||||
}.toMap()
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
// 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.flavors.conda
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||
import com.intellij.execution.target.FullPathOnTarget
|
||||
import com.intellij.execution.target.TargetEnvironmentConfiguration
|
||||
import com.intellij.execution.target.TargetedCommandLineBuilder
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import com.jetbrains.python.packaging.conda.environmentYml.format.CondaEnvironmentYmlParser
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.sdk.conda.TargetCommandExecutor
|
||||
import com.jetbrains.python.sdk.conda.createCondaSdkFromExistingEnv
|
||||
@@ -21,10 +21,9 @@ import java.util.*
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
/**
|
||||
* TODO: Once we get rid of [TargetCommandExecutor] and have access to [com.intellij.execution.target.TargetEnvironmentConfiguration] use it validate conda binary in [getEnvs]
|
||||
* TODO: Once we get rid of [TargetCommandExecutor] and have access to [TargetEnvironmentConfiguration] use it validate conda binary in [getEnvs]
|
||||
* @see `PyCondaTest`
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@@ -115,7 +114,6 @@ data class PyCondaEnv(
|
||||
|
||||
/**
|
||||
* Request to create new conda environment.
|
||||
* Conda binary must be run with [createEnvArguments]
|
||||
*/
|
||||
sealed class NewCondaEnvRequest {
|
||||
abstract val envName: @NonNls String
|
||||
@@ -157,14 +155,16 @@ sealed class NewCondaEnvRequest {
|
||||
assert(environmentYaml.exists()) { "$environmentYaml doesn't exist" }
|
||||
}
|
||||
|
||||
private val lazyName = lazy {
|
||||
ObjectMapper(YAMLFactory()).readValue(environmentYaml.pathString, ObjectNode::class.java).get("name").asText()
|
||||
}
|
||||
override val envName: String get() = lazyName.value
|
||||
override val envName: String = readEnvName()
|
||||
|
||||
@ApiStatus.Internal
|
||||
override suspend fun create(condaPath: Path): PyResult<Unit> {
|
||||
return CondaExecutor.createFileEnv(condaPath, environmentYaml)
|
||||
}
|
||||
|
||||
private fun readEnvName(): String = runReadAction {
|
||||
val virtualFile = VirtualFileManager.getInstance().findFileByNioPath(environmentYaml) ?: return@runReadAction "default"
|
||||
CondaEnvironmentYmlParser.readNameFromFile(virtualFile) ?: "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user