.gradle.kts: fix freezes by avoiding fs walking

^KT-36502 Fixed
This commit is contained in:
Natalia Selezneva
2020-03-02 09:56:38 +03:00
parent 01c4e66edb
commit c0cd010b7d
5 changed files with 44 additions and 44 deletions
@@ -9,16 +9,12 @@ import com.intellij.openapi.externalSystem.service.project.autoimport.AsyncFileC
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import java.util.*
fun addVfsListener(watcher: GradleScriptInputsWatcher) {
VirtualFileManager.getInstance().addAsyncFileListener(
object : AsyncFileChangeListenerBase() {
private var files: Set<String> = Collections.emptySet()
override fun isRelevant(path: String): Boolean {
return isInAffectedGradleProjectFiles(files, path)
return isInAffectedGradleProjectFiles(watcher.project, path)
}
override fun updateFile(file: VirtualFile, event: VFileEvent) {
@@ -28,11 +24,9 @@ fun addVfsListener(watcher: GradleScriptInputsWatcher) {
// do nothing
override fun prepareFileDeletion(file: VirtualFile) {}
override fun apply() {}
override fun reset() {
files = getAffectedGradleProjectFiles(watcher.project)
}
override fun reset() {}
},
watcher.project,
watcher.project
)
}
@@ -5,26 +5,28 @@
package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.util.concurrency.SequentialTaskExecutor
fun addVfsListener(watcher: GradleScriptInputsWatcher) {
watcher.project.messageBus.connect().subscribe(
VirtualFileManager.VFS_CHANGES,
object : BulkFileListener {
private val executor =
SequentialTaskExecutor.createSequentialApplicationPoolExecutor("GradleScriptInputsWatcherVfsChangesExecutor")
override fun after(events: List<VFileEvent>) {
ApplicationManager.getApplication().executeOnPooledThread {
if (watcher.project.isDisposed) return@executeOnPooledThread
val files = getAffectedGradleProjectFiles(watcher.project)
executor.submit(Runnable {
if (watcher.project.isDisposed) return@Runnable
for (event in events) {
val file = event.file ?: return@executeOnPooledThread
if (isInAffectedGradleProjectFiles(files, event.path)) {
val file = event.file ?: continue
if (isInAffectedGradleProjectFiles(watcher.project, event.path)) {
watcher.fileChanged(event.path, file.timeStamp)
}
}
}
})
}
}
)
@@ -9,16 +9,12 @@ import com.intellij.openapi.externalSystem.autoimport.AsyncFileChangeListenerBas
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import java.util.*
fun addVfsListener(watcher: GradleScriptInputsWatcher) {
VirtualFileManager.getInstance().addAsyncFileListener(
object : AsyncFileChangeListenerBase() {
private var files: Set<String> = Collections.emptySet();
override fun isRelevant(path: String): Boolean {
return isInAffectedGradleProjectFiles(files, path)
return isInAffectedGradleProjectFiles(watcher.project, path)
}
override fun updateFile(file: VirtualFile, event: VFileEvent) {
@@ -27,11 +23,9 @@ fun addVfsListener(watcher: GradleScriptInputsWatcher) {
// do nothing
override fun apply() {}
override fun init() {
files = getAffectedGradleProjectFiles(watcher.project)
}
override fun init() {}
},
watcher.project,
watcher.project
)
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
import org.jetbrains.kotlin.idea.scripting.gradle.getGradleScriptInputsStamp
import org.jetbrains.kotlin.idea.scripting.gradle.saveGradleProjectRootsAfterImport
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
@@ -55,7 +56,11 @@ class KotlinDslScriptModelDataService : AbstractProjectDataService<ProjectData,
gradleKotlinBuildScripts.clear()
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
val projectSettings = gradleSettings.getLinkedProjectSettings(projectData?.linkedExternalProjectPath ?: return) ?: return
val projectRoot = projectData?.linkedExternalProjectPath ?: return
val projectSettings = gradleSettings.getLinkedProjectSettings(projectRoot) ?: return
saveGradleProjectRootsAfterImport(projectSettings.modules.takeIf { it.isNotEmpty() } ?: setOf(projectRoot))
val gradleExeSettings = ExternalSystemApiUtil.getExecutionSettings<GradleExecutionSettings>(
project,
projectSettings.externalProjectPath,
@@ -12,14 +12,12 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.util.io.systemIndependentPath
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScriptInitializer
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.plugins.gradle.GradleManager
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
@@ -28,34 +26,41 @@ private val sections = arrayListOf("buildscript", "plugins", "initscript", "plug
fun isGradleKotlinScript(virtualFile: VirtualFile) = virtualFile.name.endsWith(".gradle.kts")
fun isInAffectedGradleProjectFiles(project: Project, filePath: String): Boolean {
// fast path
if (!filePath.contains("gradle")) return false
if (filePath.endsWith("/gradle.properties")) return true
if (filePath.endsWith("/gradle-wrapper.properties")) return true
val affectedFiles = getAffectedGradleProjectFiles(project)
return isInAffectedGradleProjectFiles(affectedFiles, filePath)
}
if (filePath.endsWith(".gradle") || filePath.endsWith(".gradle.kts")) {
if (ApplicationManager.getApplication().isUnitTestModeWithoutAffectedGradleProjectFilesCheck) {
return true
}
fun isInAffectedGradleProjectFiles(files: Set<String>, filePath: String): Boolean {
if (ApplicationManager.getApplication().isUnitTestModeWithoutAffectedGradleProjectFilesCheck) {
return true
return filePath.substringBeforeLast("/") in getGradleProjectsRoots(project)
}
return filePath in files
return false
}
fun getAffectedGradleProjectFiles(project: Project): Set<String> {
private var cachedGradleProjectsRoots: Set<String>? = null
private fun getGradleProjectsRoots(project: Project): Set<String> {
if (cachedGradleProjectsRoots == null) {
cachedGradleProjectsRoots = computeGradleProjectRoots(project)
}
return cachedGradleProjectsRoots ?: emptySet()
}
fun saveGradleProjectRootsAfterImport(roots: Set<String>) {
cachedGradleProjectsRoots = roots
}
private fun computeGradleProjectRoots(project: Project): Set<String> {
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
if (gradleSettings.getLinkedProjectsSettings().isEmpty()) return setOf()
val projectSettings = gradleSettings.getLinkedProjectsSettings().filterIsInstance<GradleProjectSettings>().firstOrNull()
?: return setOf()
return ExternalSystemApiUtil.getAllManagers()
.filterIsInstance<GradleManager>()
.firstOrNull()
?.getAffectedExternalProjectFiles(projectSettings.externalProjectPath, project)
?.mapTo(mutableSetOf()) { it.toPath().systemIndependentPath }
?: setOf()
return projectSettings.modules.takeIf { it.isNotEmpty() } ?: setOf(projectSettings.externalProjectPath)
}
fun getGradleScriptInputsStamp(