diff --git a/python/openapi/src/com/jetbrains/python/venvReader/VirtualEnvReader.kt b/python/openapi/src/com/jetbrains/python/venvReader/VirtualEnvReader.kt index ee051ccf65c5..9299f5b5e6f1 100644 --- a/python/openapi/src/com/jetbrains/python/venvReader/VirtualEnvReader.kt +++ b/python/openapi/src/com/jetbrains/python/venvReader/VirtualEnvReader.kt @@ -181,7 +181,7 @@ class VirtualEnvReader private constructor( } } - fun getVenvRootPath(path: Path): Path? { + fun getVenvName(path: Path): String? { val bin = path.parent val binFolderName = when (forcedOs ?: path.osFamily) { @@ -194,18 +194,24 @@ class VirtualEnvReader private constructor( } val venv = bin.parent + return venv?.name + } - if (venv == null) { + fun getVenvNameForTarget(path: FullPathOnTarget, platform: Platform): String? { + val separator = platform.fileSeparator + val bin = path.substringBeforeLast(separator) + + val binFolderName = when (platform) { + Platform.UNIX -> "bin" + Platform.WINDOWS -> "Scripts" + } + + if (bin.substringAfterLast(separator) != binFolderName) { return null } - val root = venv.parent - - if (root == null) { - return null - } - - return root + val venv = bin.substringBeforeLast(separator) + return venv.substringAfterLast(separator).takeIf { it.isNotBlank() } } /** diff --git a/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt b/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt index 6a7bd3c981ec..61f023b7570d 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt @@ -62,6 +62,7 @@ import java.nio.file.Path import kotlin.io.path.Path import kotlin.io.path.exists import kotlin.io.path.isDirectory +import kotlin.io.path.name private val LOG: Logger = fileLogger() @@ -92,7 +93,8 @@ sealed interface FileSystem
{ suspend fun wrapSdk(sdk: Sdk): SdkWrapper
suspend fun detectSelectableVenv(projectPathPrefix: Path): List {
else -> null
}
- override suspend fun resolvePythonBinary(pythonHome: PathHolder.Eel): PathHolder.Eel? {
+ override fun resolvePythonBinary(pythonHome: PathHolder.Eel): PathHolder.Eel? {
return pythonHome.path.resolvePythonBinary()?.let { PathHolder.Eel(it) }
}
+ override fun getVenvName(pythonHome: PathHolder.Eel): String? {
+ return resolvePythonBinary(pythonHome)?.let { VirtualEnvReader().getVenvName(it.path) }
+ }
+
override suspend fun which(cmd: String): PathHolder.Eel? = detectTool(cmd, eelApi)?.let { PathHolder.Eel(it) }
override suspend fun getHomePath(): PathHolder.Eel = PathHolder.Eel(eelApi.userInfo.home.asNioPath())
@@ -353,12 +359,19 @@ sealed interface FileSystem {
return listOf(systemPython)
}
- override suspend fun resolvePythonBinary(pythonHome: PathHolder.Target): PathHolder.Target {
+ override fun resolvePythonBinary(pythonHome: PathHolder.Target): PathHolder.Target {
val pythonHomeString = pythonHome.pathString
val platform = targetEnvironmentConfiguration.getPlatformAndRoot().platform
return PathHolder.Target(VirtualEnvReader().findPythonInPythonRootForTarget(pythonHomeString, platform))
}
+ override fun getVenvName(pythonHome: PathHolder.Target): String? {
+ val pythonBinary = resolvePythonBinary(pythonHome)
+ val pythonBinaryString = pythonBinary.pathString
+ val platform = targetEnvironmentConfiguration.getPlatformAndRoot().platform
+ return VirtualEnvReader().getVenvNameForTarget(pythonBinaryString, platform)
+ }
+
override suspend fun which(cmd: String): PathHolder.Target? {
val binaryPathString = executeCommand("which $cmd") ?: return null
val binaryPathOnFS = parsePath(binaryPathString).getOr { return null }
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/ValidatedPathField.kt b/python/src/com/jetbrains/python/sdk/add/v2/ValidatedPathField.kt
index 5b8f7f29dacf..4ea5ef5319fd 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/ValidatedPathField.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/ValidatedPathField.kt
@@ -10,6 +10,7 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet
import com.intellij.openapi.application.EDT
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
+import com.intellij.openapi.observable.properties.AtomicProperty
import com.intellij.openapi.observable.properties.ObservableMutableProperty
import com.intellij.openapi.observable.properties.ObservableProperty
import com.intellij.openapi.observable.util.and
@@ -317,6 +318,7 @@ internal fun (
@@ -108,7 +107,7 @@ internal class EnvironmentCreatorPoetry (
venvExistenceValidationState.set(
if (venvPath.exists())
- Error(Paths.get(VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME))
+ Error(VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME)
else
Invisible
)
@@ -145,7 +144,7 @@ internal class EnvironmentCreatorPoetry (
with(panel) {
row("") {
checkBox(PyBundle.message("python.sdk.poetry.dialog.add.new.environment.in.project.checkbox"))
- .bindSelected(service (
savePathForEelOnly(pathHolder) { path -> setUvExecutableLocal(path) }
}
+ private val venvAlreadyExistsError = propertyGraph.property
+ }
}
override fun setupUI(panel: Panel, validationRequestor: DialogValidationRequestor) {
@@ -120,7 +139,14 @@ internal class EnvironmentCreatorUv (
labelText = message("sdk.create.custom.location"),
missingExecutableText = null,
isFileSelectionMode = false,
+ venvExistenceValidationState = venvExistenceValidationState,
)
+
+ row("") {
+ venvExistenceValidationAlert(validationRequestor) {
+ onVenvSelectExisting()
+ }
+ }
}
}
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/venvExistenceValidationAlert.kt b/python/src/com/jetbrains/python/sdk/add/v2/venvExistenceValidationAlert.kt
index d2a4bca87885..85fc2bd43800 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/venvExistenceValidationAlert.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/venvExistenceValidationAlert.kt
@@ -12,18 +12,17 @@ import com.intellij.ui.dsl.builder.components.ValidationType
import com.intellij.ui.dsl.builder.components.validationTooltip
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
import com.jetbrains.python.PyBundle.message
-import java.nio.file.Path
import javax.swing.JComponent
internal sealed class VenvExistenceValidationState {
data object Invisible : VenvExistenceValidationState()
data class Warning(
- val venvPath: Path,
+ val venvName: String,
) : VenvExistenceValidationState()
data class Error(
- val venvPath: Path,
+ val venvName: String,
) : VenvExistenceValidationState()
}
@@ -50,15 +49,15 @@ internal fun Row.venvExistenceValidationAlert(
is VenvExistenceValidationState.Warning -> listOfNotNull(selectExitingEnvironment)
is VenvExistenceValidationState.Error -> listOfNotNull(
ActionLink(message("sdk.create.custom.override.action")) {
- observableState.set(VenvExistenceValidationState.Warning(state.venvPath))
+ observableState.set(VenvExistenceValidationState.Warning(state.venvName))
},
selectExitingEnvironment,
)
}
val text = when (state) {
VenvExistenceValidationState.Invisible -> ""
- is VenvExistenceValidationState.Warning -> message("sdk.create.custom.override.warning", state.venvPath.toString())
- is VenvExistenceValidationState.Error -> message("sdk.create.custom.override.error", state.venvPath.toString())
+ is VenvExistenceValidationState.Warning -> message("sdk.create.custom.override.warning", state.venvName)
+ is VenvExistenceValidationState.Error -> message("sdk.create.custom.override.error", state.venvName)
}
noticePlaceholder.component =