mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-86605: Do not access IO from interpreterType.
This property violates kotlin ideology: properties must be fast, `O(1)`, and thread agnostic. This one is used all over the system including plugins (unfortunately) and we can't force callers to use BG. So we have to make it thread-agnostic. We sacrifice accuracy in favor of speed. Most people use `.pyenv` as a dir name, and those who do not, will be excluded from the statistics. Note, that this function was never intended to be used for anything but statistics. `LOG.error` throws exception in tests (but not in prod) so we use it to make sure we do not access IO from this function. Merge-request: IJ-MR-191539 Merged-by: Ilya Kazakevich <ilya.kazakevich@jetbrains.com> GitOrigin-RevId: a92a233bcce22d47e522034c04ba2c93d2efb33b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5d1923b07d
commit
bb1ccaf504
@@ -54,6 +54,7 @@ import java.nio.file.Path
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.copyToRecursively
|
||||
import kotlin.io.path.createDirectory
|
||||
import kotlin.io.path.exists
|
||||
|
||||
@JvmOverloads
|
||||
@@ -71,8 +72,8 @@ fun testNameFixture(lowerCaseFirstLetter: Boolean = true): TestFixture<String> =
|
||||
|
||||
@JvmOverloads
|
||||
@TestOnly
|
||||
fun tempPathFixture(root: Path? = null, prefix: String = "IJ"): TestFixture<Path> = testFixture {
|
||||
val tempDir = withContext(Dispatchers.IO) {
|
||||
fun tempPathFixture(root: Path? = null, prefix: String = "IJ", subdirName: String? = null): TestFixture<Path> = testFixture {
|
||||
var tempDir = withContext(Dispatchers.IO) {
|
||||
if (root == null) {
|
||||
it.eel?.fs?.createTemporaryDirectory(CreateTemporaryEntryOptions.Builder().prefix(prefix).build())?.getOrThrow()?.asNioPath()
|
||||
?: Files.createTempDirectory(prefix)
|
||||
@@ -84,6 +85,9 @@ fun tempPathFixture(root: Path? = null, prefix: String = "IJ"): TestFixture<Path
|
||||
Files.createTempDirectory(root, prefix)
|
||||
}
|
||||
}
|
||||
if (subdirName != null) {
|
||||
tempDir = tempDir.resolve(subdirName).createDirectory()
|
||||
}
|
||||
val realTempDir = tempDir.toRealPath()
|
||||
initialized(realTempDir) {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.jetbrains.python.venvReader
|
||||
import com.intellij.execution.Platform
|
||||
import com.intellij.execution.target.FullPathOnTarget
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.util.io.toCanonicalPath
|
||||
import com.intellij.platform.eel.EelApi
|
||||
@@ -13,6 +14,7 @@ import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.platform.eel.provider.localEel
|
||||
import com.intellij.platform.eel.provider.osFamily
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.util.ui.EDT
|
||||
import com.jetbrains.python.PythonBinary
|
||||
import com.jetbrains.python.PythonHomePath
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader.Companion.Instance
|
||||
@@ -71,7 +73,7 @@ class VirtualEnvReader private constructor(
|
||||
|
||||
@RequiresBackgroundThread
|
||||
fun getPyenvRootDir(eel: EelApi? = getLocalEelIfApp()): Directory {
|
||||
return resolveDirFromEnvOrElseGetDirInHomePath(eel, "PYENV_ROOT", ".pyenv")
|
||||
return resolveDirFromEnvOrElseGetDirInHomePath(eel, "PYENV_ROOT", PYENV_DEFAULT_DIR_NAME)
|
||||
}
|
||||
|
||||
@RequiresBackgroundThread
|
||||
@@ -235,6 +237,12 @@ class VirtualEnvReader private constructor(
|
||||
|
||||
@RequiresBackgroundThread
|
||||
private fun resolveDirFromEnvOrElseGetDirInHomePath(eel: EelApi?, env: String, dirName: String): Path {
|
||||
if (EDT.isCurrentThreadEdt()) {
|
||||
// This check should have been done by @RequiresBackgroundThread
|
||||
// But since Kotlin doesn't support it, we have to do that imperatively.
|
||||
// This error doesn't break user flow but tests
|
||||
logger.error("Access from EDT isn't allowed", Throwable())
|
||||
}
|
||||
val envs = forcedVars
|
||||
?: eel?.let { eel -> runBlockingMaybeCancellable { eel.exec.environmentVariables().eelIt().await() } }
|
||||
?: System.getenv()
|
||||
@@ -245,6 +253,7 @@ class VirtualEnvReader private constructor(
|
||||
|
||||
|
||||
companion object {
|
||||
private val logger = fileLogger()
|
||||
internal val Instance: VirtualEnvReader = VirtualEnvReader(forcedVars = null, forcedOs = null)
|
||||
|
||||
|
||||
@@ -259,6 +268,8 @@ class VirtualEnvReader private constructor(
|
||||
@Suppress("VENV_IS_OK") // The only place it should be used in prod
|
||||
const val DEFAULT_VIRTUALENV_DIRNAME: String = ".venv"
|
||||
|
||||
const val PYENV_DEFAULT_DIR_NAME: String = ".pyenv"
|
||||
|
||||
private val POSIX_PYTHON_PATTERN = Regex("^(pypy|python)(\\d+(\\.\\d+)*)?$")
|
||||
private val WIN_PYTHON_PATTERN = Regex("^(pypy|python)(\\d+(\\.\\d+)*)?\\.exe$", RegexOption.IGNORE_CASE)
|
||||
private fun getLocalEelIfApp(): EelApi? = if (ApplicationManager.getApplication() != null) localEel else null
|
||||
|
||||
@@ -182,6 +182,11 @@ val Sdk.executionType: InterpreterTarget
|
||||
else -> LOCAL
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for statistics only and might be somewhat inaccurate.
|
||||
* Moreover, interpreters will become a pluggable system soon, so there will be no predefined enum.
|
||||
* Please, do not use it.
|
||||
*/
|
||||
val Sdk.interpreterType: InterpreterType
|
||||
get() = when {
|
||||
// The order of checks is important here since e.g. a pipenv is a virtualenv
|
||||
@@ -190,7 +195,7 @@ val Sdk.interpreterType: InterpreterType
|
||||
isPoetry -> POETRY
|
||||
isHatch -> HATCH
|
||||
this.isCondaVirtualEnv || this.sdkAdditionalData.asSafely<PythonSdkAdditionalData>()?.flavor is CondaEnvSdkFlavor -> CONDAVENV
|
||||
VirtualEnvReader().isPyenvSdk(getHomePath()) -> PYENV
|
||||
homePath?.contains(PYENV_PATTERN) == true -> PYENV
|
||||
this.isVirtualEnv -> VIRTUALENV
|
||||
else -> REGULAR
|
||||
}
|
||||
@@ -213,3 +218,4 @@ private val PyTargetAwareAdditionalData.executionType: InterpreterTarget
|
||||
}
|
||||
} ?: REMOTE_UNKNOWN
|
||||
|
||||
private val PYENV_PATTERN = Regex("[/\\\\]${VirtualEnvReader.PYENV_DEFAULT_DIR_NAME}[/\\\\]")
|
||||
Reference in New Issue
Block a user