Scripting: avoid just in case configuration requests to Gradle (KT-34442)
Listen to changes in files that may affect gradle configuration Remove configuration request if none of such file was changed since last request ^KT-34442 Fixed
This commit is contained in:
+3
-7
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.core.script.*
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.toVfsRoots
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCache
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationState
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
||||
@@ -130,13 +131,8 @@ internal abstract class AbstractScriptConfigurationManager(
|
||||
return reloadIfOutOfDate(files, false)
|
||||
}
|
||||
|
||||
override fun forceConfigurationReload(file: KtFile) {
|
||||
val virtualFile = file.originalFile.virtualFile ?: return
|
||||
cache.markOutOfDate(virtualFile)
|
||||
|
||||
rootsIndexer.transaction {
|
||||
reloadOutOfDateConfiguration(file, loadEvenWillNotBeApplied = true)
|
||||
}
|
||||
override fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope) {
|
||||
cache.markOutOfDate(scope)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-15
@@ -9,7 +9,6 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
@@ -18,12 +17,9 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.kotlin.idea.core.script.*
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptConfigurationManagerExtensions.LOADER
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptConfigurationManagerExtensions.LISTENER
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationFileAttributeCache
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationMemoryCache
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.DefaultScriptChangeListener
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangesNotifier
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.loader.DefaultScriptConfigurationLoader
|
||||
@@ -119,14 +115,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
||||
yield(defaultLoader)
|
||||
}
|
||||
|
||||
private val defaultListener = DefaultScriptChangeListener()
|
||||
private val listeners: Sequence<ScriptChangeListener>
|
||||
get() = sequence {
|
||||
yieldAll(LISTENER.getPoint(project).extensionList)
|
||||
yield(defaultListener)
|
||||
}
|
||||
|
||||
private val notifier = ScriptChangesNotifier(project, updater, listeners)
|
||||
private val notifier = ScriptChangesNotifier(project, updater)
|
||||
|
||||
private val saveLock = ReentrantLock()
|
||||
|
||||
@@ -322,9 +311,6 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
||||
object DefaultScriptConfigurationManagerExtensions {
|
||||
val LOADER: ExtensionPointName<ScriptConfigurationLoader> =
|
||||
ExtensionPointName.create("org.jetbrains.kotlin.scripting.idea.loader")
|
||||
|
||||
val LISTENER: ExtensionPointName<ScriptChangeListener> =
|
||||
ExtensionPointName.create("org.jetbrains.kotlin.scripting.idea.listener")
|
||||
}
|
||||
|
||||
val ScriptConfigurationManager.testingBackgroundExecutor
|
||||
|
||||
+7
-1
@@ -29,12 +29,18 @@ interface ScriptConfigurationCache {
|
||||
|
||||
fun setApplied(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot)
|
||||
fun setLoaded(file: VirtualFile, configurationSnapshot: ScriptConfigurationSnapshot)
|
||||
fun markOutOfDate(file: VirtualFile)
|
||||
fun markOutOfDate(scope: ScriptConfigurationCacheScope)
|
||||
|
||||
fun allApplied(): Collection<Pair<VirtualFile, ScriptCompilationConfigurationWrapper>>
|
||||
fun clear()
|
||||
}
|
||||
|
||||
sealed class ScriptConfigurationCacheScope {
|
||||
object All : ScriptConfigurationCacheScope()
|
||||
class File(val file: KtFile) : ScriptConfigurationCacheScope()
|
||||
class Except(val file: KtFile) : ScriptConfigurationCacheScope()
|
||||
}
|
||||
|
||||
data class ScriptConfigurationState(
|
||||
val applied: ScriptConfigurationSnapshot? = null,
|
||||
val loaded: ScriptConfigurationSnapshot? = null
|
||||
|
||||
+31
-8
@@ -37,14 +37,26 @@ open class ScriptConfigurationMemoryCache(
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun markOutOfDate(file: VirtualFile) {
|
||||
val old = memoryCache[file] ?: ScriptConfigurationState()
|
||||
memoryCache.put(
|
||||
file, old.copy(
|
||||
applied = old.applied?.copy(inputs = CachedConfigurationInputs.OutOfDate),
|
||||
loaded = old.loaded?.copy(inputs = CachedConfigurationInputs.OutOfDate)
|
||||
)
|
||||
)
|
||||
override fun markOutOfDate(scope: ScriptConfigurationCacheScope) {
|
||||
when (scope) {
|
||||
is ScriptConfigurationCacheScope.File -> {
|
||||
val file = scope.file.originalFile.virtualFile
|
||||
markFileOutOfDate(file)
|
||||
}
|
||||
is ScriptConfigurationCacheScope.Except -> {
|
||||
val file = scope.file.originalFile.virtualFile
|
||||
memoryCache.entrySet().forEach {
|
||||
if (it.key != file) {
|
||||
markFileOutOfDate(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
is ScriptConfigurationCacheScope.All ->{
|
||||
memoryCache.entrySet().forEach {
|
||||
markFileOutOfDate(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@@ -59,4 +71,15 @@ open class ScriptConfigurationMemoryCache(
|
||||
override fun clear() {
|
||||
memoryCache.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun markFileOutOfDate(file: VirtualFile) {
|
||||
val old = memoryCache[file] ?: return
|
||||
memoryCache.put(
|
||||
file, old.copy(
|
||||
applied = old.applied?.copy(inputs = CachedConfigurationInputs.OutOfDate),
|
||||
loaded = old.loaded?.copy(inputs = CachedConfigurationInputs.OutOfDate)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+12
-6
@@ -4,16 +4,22 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea.core.script.configuration.listener
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.isNonScript
|
||||
|
||||
open class DefaultScriptChangeListener : ScriptChangeListener {
|
||||
override fun editorActivated(file: KtFile, updater: ScriptConfigurationUpdater): Boolean {
|
||||
open class DefaultScriptChangeListener(project: Project) : ScriptChangeListener(project) {
|
||||
override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||
val file = getAnalyzableKtFileForScript(vFile) ?: return
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun documentChanged(file: KtFile, updater: ScriptConfigurationUpdater): Boolean {
|
||||
override fun documentChanged(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||
val file = getAnalyzableKtFileForScript(vFile) ?: return
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
||||
return vFile.isValid && !vFile.isNonScript()
|
||||
}
|
||||
}
|
||||
+24
-5
@@ -5,18 +5,37 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.configuration.listener
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
/**
|
||||
* [ScriptChangesNotifier] will call first applicable [ScriptChangeListener] when editor is activated or document changed.
|
||||
* (it treated as applicable if [editorActivated] or [documentChanged] will return true).
|
||||
*
|
||||
* Listener may call [ScriptConfigurationUpdater] to invalidate configuration and schedule reloading.
|
||||
*
|
||||
* @see DefaultScriptConfigurationManager for more details.
|
||||
*/
|
||||
interface ScriptChangeListener {
|
||||
fun editorActivated(file: KtFile, updater: ScriptConfigurationUpdater): Boolean
|
||||
fun documentChanged(file: KtFile, updater: ScriptConfigurationUpdater): Boolean
|
||||
abstract class ScriptChangeListener(protected val project: Project) {
|
||||
abstract fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater)
|
||||
abstract fun documentChanged(vFile: VirtualFile, updater: ScriptConfigurationUpdater)
|
||||
|
||||
abstract fun isApplicable(vFile: VirtualFile): Boolean
|
||||
|
||||
protected fun getAnalyzableKtFileForScript(vFile: VirtualFile): KtFile? {
|
||||
if (project.isDisposed) return null
|
||||
|
||||
return (PsiManager.getInstance(project).findFile(vFile) as? KtFile)?.takeIf {
|
||||
ProjectRootsUtil.isInProjectSource(it, includeScriptsOutsideSourceRoots = true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LISTENER: ExtensionPointName<ScriptChangeListener> =
|
||||
ExtensionPointName.create("org.jetbrains.kotlin.scripting.idea.listener")
|
||||
}
|
||||
}
|
||||
+19
-28
@@ -15,17 +15,13 @@ import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.util.Alarm
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener.Companion.LISTENER
|
||||
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.isNonScript
|
||||
|
||||
internal class ScriptChangesNotifier(
|
||||
private val project: Project,
|
||||
private val updater: ScriptConfigurationUpdater,
|
||||
private val listeners: Sequence<ScriptChangeListener>
|
||||
private val updater: ScriptConfigurationUpdater
|
||||
) {
|
||||
private val scriptsQueue = Alarm(Alarm.ThreadToUse.SWING_THREAD, project)
|
||||
private val scriptChangesListenerDelay = 1400
|
||||
@@ -45,9 +41,7 @@ internal class ScriptChangesNotifier(
|
||||
}
|
||||
|
||||
private fun runScriptDependenciesUpdateIfNeeded(file: VirtualFile) {
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
listeners.first { it.editorActivated(ktFile, updater) }
|
||||
getListener(project, file)?.editorActivated(file, updater)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -55,12 +49,12 @@ internal class ScriptChangesNotifier(
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
val document = event.document
|
||||
val file = FileDocumentManager.getInstance().getFile(document)?.takeIf { it.isInLocalFileSystem } ?: return
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
val listener = getListener(project, file) ?: return
|
||||
|
||||
scriptsQueue.cancelAllRequests()
|
||||
|
||||
scriptsQueue.addRequest(
|
||||
{ listeners.first { it.documentChanged(ktFile, updater) } },
|
||||
{ listener.documentChanged(file, updater) },
|
||||
scriptChangesListenerDelay,
|
||||
true
|
||||
)
|
||||
@@ -68,23 +62,20 @@ internal class ScriptChangesNotifier(
|
||||
}, project.messageBus.connect())
|
||||
}
|
||||
|
||||
private fun getKtFileToStartConfigurationUpdate(file: VirtualFile): KtFile? {
|
||||
if (project.isDisposed || !file.isValid || file.isNonScript()) {
|
||||
return null
|
||||
private val defaultListener = DefaultScriptChangeListener(project)
|
||||
private val listeners: Sequence<ScriptChangeListener>
|
||||
get() = sequence {
|
||||
yieldAll(LISTENER.getPoint(project).extensionList)
|
||||
yield(defaultListener)
|
||||
}
|
||||
|
||||
if (
|
||||
ApplicationManager.getApplication().isUnitTestMode &&
|
||||
ApplicationManager.getApplication().isScriptChangesNotifierDisabled == true
|
||||
) {
|
||||
return null
|
||||
}
|
||||
private fun getListener(project: Project, file: VirtualFile): ScriptChangeListener? {
|
||||
if (project.isDisposed || areListenersDisabled()) return null
|
||||
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return null
|
||||
if (ProjectRootsUtil.isInProjectSource(ktFile, includeScriptsOutsideSourceRoots = true)) {
|
||||
return ktFile
|
||||
}
|
||||
|
||||
return null
|
||||
return listeners.firstOrNull { it.isApplicable(file) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun areListenersDisabled(): Boolean {
|
||||
return ApplicationManager.getApplication().isUnitTestMode && ApplicationManager.getApplication().isScriptChangesNotifierDisabled == true
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.configuration.listener
|
||||
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
interface ScriptConfigurationUpdater {
|
||||
@@ -24,7 +25,7 @@ interface ScriptConfigurationUpdater {
|
||||
fun ensureConfigurationUpToDate(files: List<KtFile>): Boolean
|
||||
|
||||
/**
|
||||
* Invalidate current configuration and start loading new
|
||||
* Invalidate current configuration
|
||||
*/
|
||||
fun forceConfigurationReload(file: KtFile)
|
||||
fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope)
|
||||
}
|
||||
+38
-13
@@ -5,24 +5,49 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.DefaultScriptChangeListener
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.plugins.gradle.GradleManager
|
||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
|
||||
class GradleScriptListener : DefaultScriptChangeListener() {
|
||||
private val listenGradleRelatedFiles = false // todo
|
||||
class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
||||
|
||||
override fun editorActivated(file: KtFile, updater: ScriptConfigurationUpdater): Boolean {
|
||||
if (!isGradleKotlinScript(file.virtualFile)) return false
|
||||
if (listenGradleRelatedFiles) {
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
// todo: force reload if related files changed
|
||||
override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||
if (!isGradleKotlinScript(vFile)) return
|
||||
|
||||
if (useScriptConfigurationFromImportOnly()) {
|
||||
// do nothing
|
||||
} else {
|
||||
// configuration will be reloaded after editor activation, even it is already up-to-date
|
||||
// this is required for Gradle scripts, since it's classpath may depend on other files (`.properties` for example)
|
||||
updater.forceConfigurationReload(file)
|
||||
val file = getAnalyzableKtFileForScript(vFile) ?: return
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
override fun documentChanged(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||
val file = getAnalyzableKtFileForScript(vFile)
|
||||
if (file != null) {
|
||||
// *.gradle.kts file was changed
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
updater.postponeConfigurationReload(ScriptConfigurationCacheScope.Except(file))
|
||||
} else {
|
||||
updater.postponeConfigurationReload(ScriptConfigurationCacheScope.All)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
||||
val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
|
||||
if (gradleSettings.getLinkedProjectsSettings().isEmpty()) return false
|
||||
|
||||
val projectSettings = gradleSettings.getLinkedProjectsSettings().filterIsInstance<GradleProjectSettings>().firstOrNull()
|
||||
?: return false
|
||||
|
||||
val affectedFiles = ExternalSystemApiUtil.getAllManagers().filterIsInstance<GradleManager>().firstOrNull()
|
||||
?.getAffectedExternalProjectFiles(projectSettings.externalProjectPath, project)
|
||||
return affectedFiles?.any { it.path == vFile.path } == true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user