PY-32853 Rewrite CondaExecutablesLocator.kt using NIO Paths instead of VirtualFiles

GitOrigin-RevId: e31e36a209c19d9ab26a0fd030ce130a8e732752
This commit is contained in:
Alexander Koshevoy
2023-10-12 11:49:25 +02:00
committed by intellij-monorepo-bot
parent a2b93d5ecf
commit b56e3b9b47
3 changed files with 68 additions and 39 deletions

View File

@@ -6,10 +6,11 @@ import com.intellij.execution.configurations.PathEnvironmentVariableUtil
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.SystemProperties
import com.jetbrains.python.sdk.PythonSdkUtil
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.div
private val CONDA_DEFAULT_ROOTS = listOf("anaconda", "anaconda3", "miniconda", "miniconda3", "Anaconda", "Anaconda3", "Miniconda",
"Miniconda3")
@@ -41,15 +42,14 @@ fun getCondaBasePython(systemCondaExecutable: String): String? {
private fun getPythonName(): String = if (SystemInfo.isWindows) PYTHON_EXE_NAME else PYTHON_UNIX_BINARY_NAME
fun findCondaExecutableRelativeToEnv(sdkPath: String): String? {
val pyExecutable = StandardFileSystems.local().findFileByPath(sdkPath)
if (pyExecutable == null) {
fun findCondaExecutableRelativeToEnv(pyExecutable: Path): Path? {
if (!Files.exists(pyExecutable)) {
return null
}
val pyExecutableDir = pyExecutable.parent
val isBaseConda = pyExecutableDir.findChild(CONDA_ENVS_DIR) != null
val pyExecutableDir = pyExecutable.parent ?: return null
val isBaseConda = Files.exists(pyExecutableDir / CONDA_ENVS_DIR)
val condaName: String
val condaFolder: VirtualFile
val condaFolder: Path
if (SystemInfo.isWindows) {
condaName = CONDA_BAT_NAME
// On Windows python.exe is directly inside base interpreter/environment directory.
@@ -58,7 +58,7 @@ fun findCondaExecutableRelativeToEnv(sdkPath: String): String? {
}
else {
condaName = CONDA_BINARY_NAME
condaFolder = pyExecutableDir.parent
condaFolder = pyExecutableDir.parent ?: return null
}
// XXX Do we still need to support this? When did they drop per-environment conda executable?
@@ -67,36 +67,37 @@ fun findCondaExecutableRelativeToEnv(sdkPath: String): String? {
if (immediateConda != null) {
return immediateConda
}
val envsDir = condaFolder.parent
if (!isBaseConda && envsDir != null && envsDir.name == CONDA_ENVS_DIR) {
return findExecutable(condaName, envsDir.parent)
val envsDir = condaFolder.parent ?: return null
if (!isBaseConda && envsDir.fileName.toString() == CONDA_ENVS_DIR) {
val envsDirParent = envsDir.parent ?: return null
return findExecutable(condaName, envsDirParent)
}
return null
}
private fun getCondaExecutableByName(condaName: String): String? {
val userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/'))
private fun getCondaExecutableByName(condaName: String): Path? {
val userHome = Path.of(SystemProperties.getUserHome())
for (root in CONDA_DEFAULT_ROOTS) {
var condaFolder = userHome?.findChild(root)
var condaFolder = userHome / root
var executableFile = findExecutable(condaName, condaFolder)
if (executableFile != null) return executableFile
if (SystemInfo.isWindows) {
condaFolder = userHome?.findFileByRelativePath(WIN_CONTINUUM_DIR_PATH + root)
condaFolder = userHome / WIN_CONTINUUM_DIR_PATH / root
executableFile = findExecutable(condaName, condaFolder)
if (executableFile != null) return executableFile
condaFolder = LocalFileSystem.getInstance().findFileByPath(WIN_PROGRAM_DATA_PATH + root)
condaFolder = Path.of(WIN_PROGRAM_DATA_PATH, root)
executableFile = findExecutable(condaName, condaFolder)
if (executableFile != null) return executableFile
condaFolder = LocalFileSystem.getInstance().findFileByPath(WIN_C_ROOT_PATH + root)
condaFolder = Path.of(WIN_C_ROOT_PATH, root)
executableFile = findExecutable(condaName, condaFolder)
if (executableFile != null) return executableFile
}
else {
condaFolder = LocalFileSystem.getInstance().findFileByPath(UNIX_OPT_PATH + root)
condaFolder = Path.of(UNIX_OPT_PATH, root)
executableFile = findExecutable(condaName, condaFolder)
if (executableFile != null) return executableFile
}
@@ -105,30 +106,21 @@ private fun getCondaExecutableByName(condaName: String): String? {
return null
}
private fun findExecutable(condaName: String, condaFolder: VirtualFile?): String? {
if (condaFolder != null) {
val binFolder = condaFolder.findChild(if (SystemInfo.isWindows) WIN_CONDA_BIN_DIR_NAME else UNIX_CONDA_BIN_DIR_NAME)
if (binFolder != null) {
val bin = binFolder.findChild(condaName)
if (bin != null) {
val directoryPath = bin.path
val executableFile = PythonSdkUtil.getExecutablePath(directoryPath, condaName)
if (executableFile != null) {
return executableFile
}
}
}
}
return null
private fun findExecutable(condaName: String, condaFolder: Path): Path? {
val binFolderName = if (SystemInfo.isWindows) WIN_CONDA_BIN_DIR_NAME else UNIX_CONDA_BIN_DIR_NAME
val bin = condaFolder / binFolderName / condaName
if (!Files.exists(bin)) return null
return PythonSdkUtil.getExecutablePath(bin, condaName)
}
fun getSystemCondaExecutable(): String? {
fun getSystemCondaExecutable(): Path? {
val condaName = if (SystemInfo.isWindows) CONDA_BAT_NAME else CONDA_BINARY_NAME
// TODO we need another findInPath() that works with Path-s
val condaInPath = PathEnvironmentVariableUtil.findInPath(condaName)
if (condaInPath != null) {
LOG.info("Using $condaInPath as a conda executable (found in PATH)")
return condaInPath.path
return condaInPath.toPath()
}
val condaInRoots = getCondaExecutableByName(condaName)

View File

@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.xmlb.XmlSerializerUtil
import com.intellij.util.xmlb.annotations.Property
import org.jetbrains.annotations.SystemDependent
import java.nio.file.Path
@State(name = "PyCondaPackageService", storages = [Storage(value = "conda_packages.xml", roamingType = RoamingType.DISABLED)])
class PyCondaPackageService : PersistentStateComponent<PyCondaPackageService> {
@@ -27,10 +28,10 @@ class PyCondaPackageService : PersistentStateComponent<PyCondaPackageService> {
@JvmStatic
fun getCondaExecutable(sdkPath: String?): @SystemDependent String? {
if (sdkPath != null) {
val condaPath = findCondaExecutableRelativeToEnv(sdkPath)
val condaPath = findCondaExecutableRelativeToEnv(Path.of(sdkPath))
if (condaPath != null) {
LOG.info("Using $condaPath as a conda executable for $sdkPath (found as a relative to the env)")
return condaPath
return condaPath.toString()
}
}
@@ -41,7 +42,7 @@ class PyCondaPackageService : PersistentStateComponent<PyCondaPackageService> {
return preferredCondaPath
}
return getSystemCondaExecutable()
return getSystemCondaExecutable()?.toString()
}
fun onCondaEnvCreated(condaExecutable: @SystemDependent String) {