fix uv detection for win and when creating cli; PY-75983

(cherry picked from commit f54ee351bfdceb6597a74d1fb128e000051984ba)

GitOrigin-RevId: 3200c0ae179a2e4e15a9ff9691421803cd09e1af
This commit is contained in:
Aleksandr Sorotskii
2024-11-26 18:56:41 +01:00
committed by intellij-monorepo-bot
parent 77157d6fe2
commit 2769b5d234
6 changed files with 48 additions and 38 deletions

View File

@@ -14,7 +14,7 @@ import com.jetbrains.python.sdk.*
import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension
import com.jetbrains.python.sdk.uv.PY_PROJECT_TOML import com.jetbrains.python.sdk.uv.PY_PROJECT_TOML
import com.jetbrains.python.sdk.uv.getUvExecutable import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.nio.file.Path import java.nio.file.Path

View File

@@ -1,13 +1,12 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2 package com.jetbrains.python.sdk.add.v2
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.observable.properties.ObservableMutableProperty import com.intellij.openapi.observable.properties.ObservableMutableProperty
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.python.sdk.ModuleOrProject import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.uv.uvPath import com.jetbrains.python.sdk.uv.impl.setUvExecutable
import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress
import com.jetbrains.python.statistics.InterpreterType import com.jetbrains.python.statistics.InterpreterType
import java.nio.file.Path import java.nio.file.Path
@@ -24,7 +23,7 @@ class EnvironmentCreatorUv(model: PythonMutableTargetAddInterpreterModel, privat
} }
override fun savePathToExecutableToProperties() { override fun savePathToExecutableToProperties() {
PropertiesComponent.getInstance().uvPath = Path.of(executable.get()) setUvExecutable(Path.of(executable.get()))
} }
override suspend fun setupEnvSdk(project: Project?, module: Module?, baseSdks: List<Sdk>, projectPath: String, homePath: String?, installPackages: Boolean): Result<Sdk> { override suspend fun setupEnvSdk(project: Project?, module: Module?, baseSdks: List<Sdk>, projectPath: String, homePath: String?, installPackages: Boolean): Result<Sdk> {

View File

@@ -23,7 +23,7 @@ import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
import com.jetbrains.python.sdk.pipenv.getPipEnvExecutable import com.jetbrains.python.sdk.pipenv.getPipEnvExecutable
import com.jetbrains.python.sdk.poetry.getPoetryExecutable import com.jetbrains.python.sdk.poetry.getPoetryExecutable
import com.jetbrains.python.sdk.uv.getUvExecutable import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.util.ErrorSink import com.jetbrains.python.util.ErrorSink
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.uv package com.jetbrains.python.sdk.uv
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.util.NlsSafe
@@ -15,15 +14,11 @@ import com.jetbrains.python.sdk.findAmongRoots
import com.jetbrains.python.sdk.setAssociationToModule import com.jetbrains.python.sdk.setAssociationToModule
import com.jetbrains.python.sdk.uv.impl.createUvCli import com.jetbrains.python.sdk.uv.impl.createUvCli
import com.jetbrains.python.sdk.uv.impl.createUvLowLevel import com.jetbrains.python.sdk.uv.impl.createUvLowLevel
import com.jetbrains.python.sdk.uv.impl.detectUvExecutable
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.pathString import kotlin.io.path.pathString
internal const val UV_PATH_SETTING: String = "PyCharm.UV.Path"
internal val Sdk.isUv: Boolean internal val Sdk.isUv: Boolean
get() = sdkAdditionalData is UvSdkAdditionalData get() = sdkAdditionalData is UvSdkAdditionalData
@@ -50,18 +45,6 @@ val UV_LOCK: String = "uv.lock"
// FIXME: move pyprojecttoml code out to common package // FIXME: move pyprojecttoml code out to common package
val PY_PROJECT_TOML: String = "pyproject.toml" val PY_PROJECT_TOML: String = "pyproject.toml"
var PropertiesComponent.uvPath: Path?
get() {
return getValue(UV_PATH_SETTING)?.let { Path.of(it) }
}
set(value) {
setValue(UV_PATH_SETTING, value.toString())
}
fun getUvExecutable(): Path? {
return PropertiesComponent.getInstance().uvPath?.takeIf { it.exists() } ?: detectUvExecutable()
}
suspend fun setupUvSdkUnderProgress( suspend fun setupUvSdkUnderProgress(
module: Module, module: Module,
projectPath: Path, projectPath: Path,

View File

@@ -2,7 +2,9 @@
package com.jetbrains.python.sdk.uv.impl package com.jetbrains.python.sdk.uv.impl
import com.intellij.execution.configurations.PathEnvironmentVariableUtil import com.intellij.execution.configurations.PathEnvironmentVariableUtil
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.ui.ValidationInfo import com.intellij.openapi.ui.ValidationInfo
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.SystemProperties import com.intellij.util.SystemProperties
import com.jetbrains.python.PyBundle import com.jetbrains.python.PyBundle
import com.jetbrains.python.pathValidation.PlatformAndRoot import com.jetbrains.python.pathValidation.PlatformAndRoot
@@ -12,20 +14,21 @@ import com.jetbrains.python.sdk.runExecutable
import com.jetbrains.python.sdk.uv.UvCli import com.jetbrains.python.sdk.uv.UvCli
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.pathString import kotlin.io.path.pathString
internal fun detectUvExecutable(): Path? { private const val UV_PATH_SETTING: String = "PyCharm.Uv.Path"
val name = "uv"
return PathEnvironmentVariableUtil.findInPath(name)?.toPath() ?: SystemProperties.getUserHome().let { homePath ->
Path.of(homePath, ".cargo", "bin", name).takeIf { it.exists() }
}
}
internal fun validateUvExecutable(uvPath: Path?): ValidationInfo? { private var PropertiesComponent.uvPath: Path?
get() {
return getValue(UV_PATH_SETTING)?.let { Path.of(it) }
}
set(value) {
setValue(UV_PATH_SETTING, value.toString())
}
private fun validateUvExecutable(uvPath: Path?): ValidationInfo? {
return validateExecutableFile(ValidationRequest( return validateExecutableFile(ValidationRequest(
path = uvPath?.pathString, path = uvPath?.pathString,
fieldIsEmpty = PyBundle.message("python.sdk.uv.executable.not.found"), fieldIsEmpty = PyBundle.message("python.sdk.uv.executable.not.found"),
@@ -34,15 +37,15 @@ internal fun validateUvExecutable(uvPath: Path?): ValidationInfo? {
)) ))
} }
internal suspend fun runUv(uv: Path, workingDir: Path, vararg args: String): Result<String> { private suspend fun runUv(uv: Path, workingDir: Path, vararg args: String): Result<String> {
return runExecutable(uv, workingDir, *args) return runExecutable(uv, workingDir, *args)
} }
internal class UvCliImpl(val dispatcher: CoroutineDispatcher, uvPath: Path?): UvCli { private class UvCliImpl(val dispatcher: CoroutineDispatcher, uvPath: Path?) : UvCli {
val uv: Path val uv: Path
init { init {
val path = uvPath ?: detectUvExecutable() val path = uvPath ?: getUvExecutable()
val error = validateUvExecutable(path) val error = validateUvExecutable(path)
if (error != null) { if (error != null) {
throw RuntimeException(error.message) throw RuntimeException(error.message)
@@ -52,12 +55,31 @@ internal class UvCliImpl(val dispatcher: CoroutineDispatcher, uvPath: Path?): Uv
} }
override suspend fun runUv(workingDir: Path, vararg args: String): Result<String> { override suspend fun runUv(workingDir: Path, vararg args: String): Result<String> {
with(Dispatchers.IO) { with(dispatcher) {
return runUv(uv, workingDir, *args) return runUv(uv, workingDir, *args)
} }
} }
} }
fun detectUvExecutable(): Path? {
val name = when {
SystemInfo.isWindows -> "uv.exe"
else -> "uv"
}
return PathEnvironmentVariableUtil.findInPath(name)?.toPath() ?: SystemProperties.getUserHome().let { homePath ->
Path.of(homePath, ".local", "bin", name).takeIf { it.exists() } ?: Path.of(homePath, ".cargo", "bin", name).takeIf { it.exists() }
}
}
fun getUvExecutable(): Path? {
return PropertiesComponent.getInstance().uvPath?.takeIf { it.exists() } ?: detectUvExecutable()
}
fun setUvExecutable(path: Path) {
PropertiesComponent.getInstance().uvPath = path
}
fun createUvCli(dispatcher: CoroutineDispatcher = Dispatchers.IO, uv: Path? = null): UvCli { fun createUvCli(dispatcher: CoroutineDispatcher = Dispatchers.IO, uv: Path? = null): UvCli {
return UvCliImpl(dispatcher, uv) return UvCliImpl(dispatcher, uv)
} }

View File

@@ -33,6 +33,8 @@ import com.jetbrains.python.sdk.add.addInterpretersAsync
import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.uv.* import com.jetbrains.python.sdk.uv.*
import com.jetbrains.python.sdk.uv.impl.detectUvExecutable import com.jetbrains.python.sdk.uv.impl.detectUvExecutable
import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.sdk.uv.impl.setUvExecutable
import com.jetbrains.python.statistics.InterpreterTarget import com.jetbrains.python.statistics.InterpreterTarget
import com.jetbrains.python.statistics.InterpreterType import com.jetbrains.python.statistics.InterpreterType
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -96,8 +98,10 @@ class PyAddNewUvPanel(
addBrowseFolderListener(null, FileChooserDescriptorFactory.createSingleFileDescriptor()) addBrowseFolderListener(null, FileChooserDescriptorFactory.createSingleFileDescriptor())
val field = textField as? JBTextField ?: return@apply val field = textField as? JBTextField ?: return@apply
service<PythonSdkCoroutineService>().cs.launch { service<PythonSdkCoroutineService>().cs.launch {
detectUvExecutable()?.let { field.emptyText.text = "Auto-detected: ${it.absolutePathString()}" } detectUvExecutable()?.let {
PropertiesComponent.getInstance().uvPath?.let { field.emptyText.text = "Auto-detected: ${it.absolutePathString()}"
}
getUvExecutable()?.let {
field.text = it.pathString field.text = it.pathString
} }
} }
@@ -153,7 +157,9 @@ class PyAddNewUvPanel(
} }
val uvPath = uvPathField.text.nullize()?.let { Path.of(it) } val uvPath = uvPathField.text.nullize()?.let { Path.of(it) }
uvPath?.let { PropertiesComponent.getInstance().uvPath = it } uvPath?.let {
setUvExecutable(it)
}
val sdk = runBlockingCancellable { val sdk = runBlockingCancellable {
setupUvSdkUnderProgress(module, Path.of(path), existingSdks, Path.of(python)) setupUvSdkUnderProgress(module, Path.of(path), existingSdks, Path.of(python))
} }