diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt index 2cfecbee1aa..0b26e3d0ed4 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt @@ -5,16 +5,19 @@ package org.jetbrains.kotlin.idea.scripting.gradle +import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs import org.jetbrains.kotlin.psi.KtFile data class GradleKotlinScriptConfigurationInputs( - val buildScriptAndPluginsSections: String + val buildScriptAndPluginsSections: String, + val timeStamp: Long ) : CachedConfigurationInputs { override fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile?): Boolean { - val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) - return actualStamp == this + val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) ?: return false + return actualStamp.buildScriptAndPluginsSections == this.buildScriptAndPluginsSections + && project.service().areAffectedFilesUpToDate(file, timeStamp) } } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt new file mode 100644 index 00000000000..8c55b5027bb --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle + +import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.plugins.gradle.settings.GradleLocalSettings +import java.nio.file.Paths +import java.util.* + +class GradleScriptInputsWatcher(val project: Project) { + private val comparator = Comparator { f1, f2 -> (f1.timeStamp - f2.timeStamp).toInt() } + + private val storage = TreeSet(comparator) + + init { + initStorage(project) + } + + private fun initStorage(project: Project) { + val localSettings = GradleLocalSettings.getInstance(project) + localSettings.externalConfigModificationStamps.forEach { (path, stamp) -> + val file = VfsUtil.findFile(Paths.get(path), true) + if (file != null && !file.isDirectory) { + val calculateCrc = ConfigurationFileCrcFactory(file).create() + if (calculateCrc != stamp) { + addToStorage(file) + } + } + } + } + + fun addToStorage(file: VirtualFile) { + if (storage.contains(file)) { + storage.remove(file) + } + storage.add(file) + } + + fun areAffectedFilesUpToDate(file: VirtualFile, timeStamp: Long): Boolean { + if (storage.isEmpty()) return true + + val iterator = storage.descendingIterator() + if (!iterator.hasNext()) return true + + var lastModifiedFile = iterator.next() + while (lastModifiedFile == file && iterator.hasNext()) { + lastModifiedFile = iterator.next() + } + + if (lastModifiedFile == file) return true + + return lastModifiedFile.timeStamp <= timeStamp + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt.as34 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt.as34 new file mode 100644 index 00000000000..f9101acb4f1 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt.as34 @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle + +import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.plugins.gradle.settings.GradleLocalSettings +import java.nio.file.Paths +import java.util.* + +class GradleScriptInputsWatcher(val project: Project) { + private val comparator = Comparator { f1, f2 -> (f1.timeStamp - f2.timeStamp).toInt() } + + private val storage = TreeSet(comparator) + + init { + initStorage(project) + } + + private fun initStorage(project: Project) { + val localSettings = GradleLocalSettings.getInstance(project) + localSettings.externalConfigModificationStamps.forEach { (path, stamp) -> + val file = VfsUtil.findFile(Paths.get(path), true) + if (file != null && !file.isDirectory) { + val calculateCrc = ConfigurationFileCrcFactory(project, file).create() + if (calculateCrc != stamp) { + addToStorage(file) + } + } + } + } + + fun addToStorage(file: VirtualFile) { + if (storage.contains(file)) { + storage.remove(file) + } + storage.add(file) + } + + fun areAffectedFilesUpToDate(file: VirtualFile, timeStamp: Long): Boolean { + if (storage.isEmpty()) return true + + val iterator = storage.descendingIterator() + if (!iterator.hasNext()) return true + + var lastModifiedFile = iterator.next() + while (lastModifiedFile == file && iterator.hasNext()) { + lastModifiedFile = iterator.next() + } + + if (lastModifiedFile == file) return true + + return lastModifiedFile.timeStamp <= timeStamp + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt index 57d1c547e80..1a528f12531 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.scripting.gradle +import com.intellij.openapi.components.service import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile @@ -34,10 +35,8 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project if (file != null) { // *.gradle.kts file was changed updater.ensureUpToDatedConfigurationSuggested(file) - updater.postponeConfigurationReload(ScriptConfigurationCacheScope.Except(file)) - } else { - updater.postponeConfigurationReload(ScriptConfigurationCacheScope.All) } + project.service().addToStorage(vFile) } override fun isApplicable(vFile: VirtualFile): Boolean { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt index 7ea39c6532d..bb58ab08d30 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt @@ -55,7 +55,7 @@ fun getGradleScriptInputsStamp( } } - GradleKotlinScriptConfigurationInputs(result.toString()) + GradleKotlinScriptConfigurationInputs(result.toString(), file.timeStamp) } else null } } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt index d020f65152c..9496d2a2d19 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcherTest.kt @@ -103,6 +103,44 @@ class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() { assertConfigurationUpToDate(testFiles.settings) } + fun testChangeOutsideSectionsInvalidatesOtherFiles() { + assertAndLoadInitialConfiguration(testFiles.buildKts) + assertAndLoadInitialConfiguration(testFiles.settings) + + changeBuildKtsOutsideSections() + + assertConfigurationUpToDate(testFiles.buildKts) + assertConfigurationUpdateWasDone(testFiles.settings) + } + + fun testChangeInsideSectionsInvalidatesOtherFiles() { + assertAndLoadInitialConfiguration(testFiles.buildKts) + assertAndLoadInitialConfiguration(testFiles.settings) + + changeBuildKtsInsideSections() + + assertConfigurationUpdateWasDone(testFiles.buildKts) + assertConfigurationUpdateWasDone(testFiles.settings) + } + + fun testChangeInsideNonKtsFileInvalidatesOtherFiles() { + assertAndLoadInitialConfiguration(testFiles.buildKts) + + changePropertiesFile() + + assertConfigurationUpdateWasDone(testFiles.buildKts) + } + + fun testTwoFilesChanged() { + assertAndLoadInitialConfiguration(testFiles.buildKts) + assertAndLoadInitialConfiguration(testFiles.settings) + + changePropertiesFile() + changeSettingsKtsOutsideSections() + + assertConfigurationUpdateWasDone(testFiles.settings) + } + fun testFileAttributes() { assertAndLoadInitialConfiguration(testFiles.buildKts) diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index aed4e300e15..8b2e213c801 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -34,6 +34,8 @@ This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place." defaultValue="true" restartRequired="false"/> + + diff --git a/idea/resources/META-INF/gradle.xml.183 b/idea/resources/META-INF/gradle.xml.183 index 1f5f463b8a0..df2d2e74693 100644 --- a/idea/resources/META-INF/gradle.xml.183 +++ b/idea/resources/META-INF/gradle.xml.183 @@ -31,6 +31,8 @@ This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place." defaultValue="true" restartRequired="false"/> + +