mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-794861: Exclude .venv dir in background.
`.venv` dirs are python vens and should never be edited. (cherry picked from commit 010004d768cb27f9a9cb7e4891f2b1724e695c1e) GitOrigin-RevId: 54c33f9c914abb913cb74d8f432f951c4c6a9fc3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4243217ad5
commit
853d7e440d
+3
-1
@@ -4,6 +4,7 @@ import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.python.pyproject.model.internal.autoImportBridge.PyProjectAutoImportService
|
||||
import com.intellij.python.pyproject.model.internal.platformBridge.startVenvExclusion
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
|
||||
@@ -18,11 +19,12 @@ private val enabled: Boolean get() = Registry.`is`("intellij.python.pyproject.mo
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
suspend fun startAutoImportIfNeeded(project: Project) {
|
||||
startVenvExclusion(project)
|
||||
if (enabled) {
|
||||
project.service<PyProjectAutoImportService>().start()
|
||||
}
|
||||
else {
|
||||
// User disabled "pyproject.toml -> module" convertion (aka project model rebuilding), but we still need to notify listener,
|
||||
// User disabled "pyproject.toml -> module" conversion (aka project model rebuilding), but we still need to notify listener,
|
||||
// so they configure SDK
|
||||
notifyModelRebuilt(project)
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.intellij.python.pyproject.model.internal
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
internal class PyProjectScopeService(internal val scope: CoroutineScope)
|
||||
+2
-6
@@ -3,7 +3,6 @@ package com.intellij.python.pyproject.model.internal.autoImportBridge
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.writeAction
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectAware
|
||||
@@ -17,6 +16,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.backend.observation.launchTracked
|
||||
import com.intellij.project.stateStore
|
||||
import com.intellij.python.pyproject.model.internal.PY_PROJECT_SYSTEM_ID
|
||||
import com.intellij.python.pyproject.model.internal.PyProjectScopeService
|
||||
import com.intellij.python.pyproject.model.internal.notifyModelRebuilt
|
||||
import com.intellij.python.pyproject.model.internal.pyProjectToml.walkFileSystemNoTomlContent
|
||||
import com.intellij.python.pyproject.model.internal.pyProjectToml.walkFileSystemWithTomlContent
|
||||
@@ -25,7 +25,6 @@ import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.util.messages.Topic
|
||||
import com.intellij.util.ui.EDT
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
@@ -68,7 +67,7 @@ class PyExternalSystemProjectAware private constructor(
|
||||
}
|
||||
|
||||
override fun reloadProject(context: ExternalSystemProjectReloadContext) {
|
||||
project.service<PyExternalSystemProjectAwareService>().scope.launchTracked {
|
||||
project.service<PyProjectScopeService>().scope.launchTracked {
|
||||
reloadProjectImpl()
|
||||
}
|
||||
}
|
||||
@@ -131,7 +130,4 @@ private val PROJECT_AWARE_TOPIC: Topic<ExternalSystemProjectListener> =
|
||||
Topic(ExternalSystemProjectListener::class.java, Topic.BroadcastDirection.NONE)
|
||||
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
private class PyExternalSystemProjectAwareService(val scope: CoroutineScope)
|
||||
|
||||
private val log = fileLogger()
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.intellij.python.pyproject.model.internal.platformBridge
|
||||
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.application.writeAction
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.FileIndexFacade
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.vfs.AsyncFileListener
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent
|
||||
import com.intellij.psi.search.FilenameIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.python.pyproject.model.internal.PyProjectScopeService
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader.Companion.DEFAULT_VIRTUALENV_DIRNAME
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
/**
|
||||
* Excludes [DEFAULT_VIRTUALENV_DIRNAME] from [project] as soon as it appears in index, should only be called once
|
||||
*/
|
||||
internal fun startVenvExclusion(project: Project) {
|
||||
VirtualFileManager.getInstance().addAsyncFileListener(project.service<PyProjectScopeService>().scope) { events ->
|
||||
if (events.none { it is VFileCreateEvent || it is VFileMoveEvent }) {
|
||||
// No need to check anything if no file created
|
||||
null
|
||||
}
|
||||
else {
|
||||
object : AsyncFileListener.ChangeApplier {
|
||||
override fun afterVfsChange() {
|
||||
excludeEnvs(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
excludeEnvs(project)
|
||||
}
|
||||
|
||||
private fun excludeEnvs(project: Project) {
|
||||
project.service<PyProjectScopeService>().scope.launch(Dispatchers.Default) {
|
||||
mutex.withLock {
|
||||
val dirs = readAction { FilenameIndex.getVirtualFilesByName(DEFAULT_VIRTUALENV_DIRNAME, GlobalSearchScope.allScope(project)) }
|
||||
for (venvToExclude in dirs) {
|
||||
val module = readAction { FileIndexFacade.getInstance(project).getModuleForFile(venvToExclude) } ?: continue
|
||||
val rootManager = ModuleRootManager.getInstance(module)
|
||||
if (venvToExclude !in rootManager.excludeRoots) {
|
||||
writeAction {
|
||||
val model = rootManager.modifiableModel
|
||||
val currentRoot = model.contentEntries.firstOrNull { root ->
|
||||
root.file?.let { VfsUtilCore.isAncestor(it, venvToExclude, false) } == true
|
||||
} ?: return@writeAction
|
||||
currentRoot.addExcludeFolder(venvToExclude)
|
||||
model.commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val mutex = Mutex()
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.intellij.python.junit5Tests.unit.pyproject
|
||||
|
||||
import com.intellij.openapi.application.writeAction
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.python.pyproject.model.internal.platformBridge.startVenvExclusion
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.fixture.moduleFixture
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import com.intellij.testFramework.junit5.fixture.tempPathFixture
|
||||
import com.intellij.testFramework.utils.vfs.createDirectory
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import kotlinx.coroutines.delay
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.containsInAnyOrder
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@TestApplication
|
||||
internal class PyExcludeVenvTest {
|
||||
private val tempDirFixture = tempPathFixture()
|
||||
private val module by projectFixture().moduleFixture(tempDirFixture, addPathToSourceRoot = true)
|
||||
|
||||
@Test
|
||||
fun testExclude(): Unit = timeoutRunBlocking {
|
||||
val root = VirtualFileManager.getInstance().refreshAndFindFileByNioPath(tempDirFixture.get())!!
|
||||
val dir1 = writeAction { root.createDirectory(VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME) }
|
||||
startVenvExclusion(module.project)
|
||||
val dir2 = writeAction { root.createDirectory("fopp").createDirectory(VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME) }
|
||||
|
||||
while (module.rootManager.excludeRoots.size != 2) {
|
||||
delay(100.milliseconds)
|
||||
}
|
||||
assertThat("Wrong items excluded", module.rootManager.excludeRoots.toList(), containsInAnyOrder(dir1, dir2))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user