mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Python: Do not access the Registry in SystemPythonServiceImpl ctor as it might not be available at that moment.
If we access `SystemPythonServiceImpl` before the Application is fully loaded (i.e. `com.intellij.python.junit5Tests.env.systemPython.SystemPythonRootsFixer.execute`), we might encounter an error: ``` Registry key python.system.refresh.minutes is not defined ``` With this change we access Registry lazily and, unlike `Registry.get`, `RegistryManager` async service is fully safe: it just suspends until the Registry is available. Merge-request: IJ-MR-160727 Merged-by: Ilya Kazakevich <ilya.kazakevich@jetbrains.com> GitOrigin-RevId: ef56cfee7b15907c7c99b859b5704b6fcef66b01
This commit is contained in:
committed by
intellij-monorepo-bot
parent
252bfa2111
commit
87a5090585
+2
-2
@@ -6,14 +6,14 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
import com.intellij.python.community.services.systemPython.SystemPythonService
|
||||
import com.intellij.python.community.services.systemPython.cacheTimeout
|
||||
import com.intellij.python.community.services.systemPython.getCacheTimeout
|
||||
|
||||
private val logger = fileLogger()
|
||||
|
||||
// Preload pythons as soon as a project gets loaded
|
||||
internal class SystemPythonInitialLoader : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
if (cacheTimeout == null) return // Cache is disabled, no need to preload it
|
||||
if (getCacheTimeout() == null) return // Cache is disabled, no need to preload it
|
||||
logger.debug("Preloading pythons for $project")
|
||||
SystemPythonService().findSystemPythons(project.getEelDescriptor().upgrade())
|
||||
}
|
||||
|
||||
+19
-17
@@ -5,7 +5,7 @@ import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.Service.Level.APP
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.registry.RegistryManager
|
||||
import com.intellij.platform.eel.EelApi
|
||||
import com.intellij.platform.eel.EelDescriptor
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
@@ -18,11 +18,9 @@ import com.intellij.python.community.services.systemPython.impl.CoreSystemPython
|
||||
import com.jetbrains.python.PythonBinary
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.sdk.installer.installBinary
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.nio.file.InvalidPathException
|
||||
@@ -35,8 +33,9 @@ import kotlin.time.Duration.Companion.minutes
|
||||
private val logger = fileLogger()
|
||||
|
||||
// null means "disabled"
|
||||
internal val cacheTimeout: Duration?
|
||||
get() = Registry.get("python.system.refresh.minutes").asInteger().let { i ->
|
||||
internal suspend fun getCacheTimeout(): Duration? =
|
||||
// This function is suspending because registry might not be available before the application is fully loaded.
|
||||
RegistryManager.getInstanceAsync().get("python.system.refresh.minutes").asInteger().let { i ->
|
||||
if (i > 0) i.minutes else null
|
||||
}
|
||||
|
||||
@@ -47,18 +46,24 @@ internal val cacheTimeout: Duration?
|
||||
@Internal
|
||||
internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonService, SimplePersistentStateComponent<MyServiceState>(MyServiceState()) {
|
||||
private val findPythonsMutex = Mutex()
|
||||
private val cache: Cache<EelDescriptor, SystemPython>? = cacheTimeout?.let { interval ->
|
||||
Cache(scope, interval) { eelDescriptor ->
|
||||
searchPythonsPhysicallyNoCache(eelDescriptor.upgrade())
|
||||
private val _cacheImpl: CompletableDeferred<Cache<EelDescriptor, SystemPython>?> = CompletableDeferred()
|
||||
private suspend fun cache() = _cacheImpl.await()
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
_cacheImpl.complete(getCacheTimeout()?.let { interval ->
|
||||
Cache<EelDescriptor, SystemPython>(scope, interval) { eelDescriptor ->
|
||||
searchPythonsPhysicallyNoCache(eelDescriptor.upgrade())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun registerSystemPython(pythonPath: PythonBinary): Result<SystemPython, @Nls String> {
|
||||
val pythonWithLangLevel = PythonWithLanguageLevelImpl.createByPythonBinary(pythonPath).getOr { return it }
|
||||
val systemPython = SystemPython(pythonWithLangLevel, null)
|
||||
state.userProvidedPythons.add(pythonPath.pathString)
|
||||
cache?.get(pythonPath.getEelDescriptor())?.add(systemPython)
|
||||
cache()?.get(pythonPath.getEelDescriptor())?.add(systemPython)
|
||||
return Result.success(systemPython)
|
||||
}
|
||||
|
||||
@@ -66,7 +71,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
|
||||
if (eelApi == localEel) LocalPythonInstaller else null
|
||||
|
||||
override suspend fun findSystemPythons(eelApi: EelApi, forceRefresh: Boolean): List<SystemPython> =
|
||||
if (cache != null) {
|
||||
cache()?.let { cache ->
|
||||
// Cache enabled
|
||||
cache.startUpdate()
|
||||
if (forceRefresh) {
|
||||
@@ -76,11 +81,8 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
|
||||
else {
|
||||
cache.get(eelApi.descriptor)
|
||||
}.sorted()
|
||||
}
|
||||
else {
|
||||
// Cache disabled
|
||||
searchPythonsPhysicallyNoCache(eelApi)
|
||||
}
|
||||
} ?: searchPythonsPhysicallyNoCache(eelApi)
|
||||
|
||||
|
||||
class MyServiceState : BaseState() {
|
||||
// Only strings are supported by serializer
|
||||
|
||||
Reference in New Issue
Block a user