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.configuration.PyProjectSdkConfigurationExtension
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 java.io.FileNotFoundException
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.
package com.jetbrains.python.sdk.add.v2
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.module.Module
import com.intellij.openapi.observable.properties.ObservableMutableProperty
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
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.statistics.InterpreterType
import java.nio.file.Path
@@ -24,7 +23,7 @@ class EnvironmentCreatorUv(model: PythonMutableTargetAddInterpreterModel, privat
}
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> {

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.pipenv.getPipEnvExecutable
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 kotlinx.coroutines.Dispatchers
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.
package com.jetbrains.python.sdk.uv
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.Sdk
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.uv.impl.createUvCli
import com.jetbrains.python.sdk.uv.impl.createUvLowLevel
import com.jetbrains.python.sdk.uv.impl.detectUvExecutable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.pathString
internal const val UV_PATH_SETTING: String = "PyCharm.UV.Path"
internal val Sdk.isUv: Boolean
get() = sdkAdditionalData is UvSdkAdditionalData
@@ -50,18 +45,6 @@ val UV_LOCK: String = "uv.lock"
// FIXME: move pyprojecttoml code out to common package
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(
module: Module,
projectPath: Path,

View File

@@ -2,7 +2,9 @@
package com.jetbrains.python.sdk.uv.impl
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.SystemProperties
import com.jetbrains.python.PyBundle
import com.jetbrains.python.pathValidation.PlatformAndRoot
@@ -12,20 +14,21 @@ import com.jetbrains.python.sdk.runExecutable
import com.jetbrains.python.sdk.uv.UvCli
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.pathString
internal fun detectUvExecutable(): Path? {
val name = "uv"
return PathEnvironmentVariableUtil.findInPath(name)?.toPath() ?: SystemProperties.getUserHome().let { homePath ->
Path.of(homePath, ".cargo", "bin", name).takeIf { it.exists() }
private const val UV_PATH_SETTING: String = "PyCharm.Uv.Path"
private var PropertiesComponent.uvPath: Path?
get() {
return getValue(UV_PATH_SETTING)?.let { Path.of(it) }
}
set(value) {
setValue(UV_PATH_SETTING, value.toString())
}
internal fun validateUvExecutable(uvPath: Path?): ValidationInfo? {
private fun validateUvExecutable(uvPath: Path?): ValidationInfo? {
return validateExecutableFile(ValidationRequest(
path = uvPath?.pathString,
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)
}
internal class UvCliImpl(val dispatcher: CoroutineDispatcher, uvPath: Path?): UvCli {
private class UvCliImpl(val dispatcher: CoroutineDispatcher, uvPath: Path?) : UvCli {
val uv: Path
init {
val path = uvPath ?: detectUvExecutable()
val path = uvPath ?: getUvExecutable()
val error = validateUvExecutable(path)
if (error != null) {
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> {
with(Dispatchers.IO) {
with(dispatcher) {
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 {
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.uv.*
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.InterpreterType
import kotlinx.coroutines.Dispatchers
@@ -96,8 +98,10 @@ class PyAddNewUvPanel(
addBrowseFolderListener(null, FileChooserDescriptorFactory.createSingleFileDescriptor())
val field = textField as? JBTextField ?: return@apply
service<PythonSdkCoroutineService>().cs.launch {
detectUvExecutable()?.let { field.emptyText.text = "Auto-detected: ${it.absolutePathString()}" }
PropertiesComponent.getInstance().uvPath?.let {
detectUvExecutable()?.let {
field.emptyText.text = "Auto-detected: ${it.absolutePathString()}"
}
getUvExecutable()?.let {
field.text = it.pathString
}
}
@@ -153,7 +157,9 @@ class PyAddNewUvPanel(
}
val uvPath = uvPathField.text.nullize()?.let { Path.of(it) }
uvPath?.let { PropertiesComponent.getInstance().uvPath = it }
uvPath?.let {
setUvExecutable(it)
}
val sdk = runBlockingCancellable {
setupUvSdkUnderProgress(module, Path.of(path), existingSdks, Path.of(python))
}