Scripting: check if affected scripts are changed using file modification stamp instead of mark them out of date in cache

^KT-35205 Fixed
This commit is contained in:
Natalia Selezneva
2019-12-06 15:47:20 +03:00
parent ec04f0059c
commit 31887d2fd1
8 changed files with 171 additions and 7 deletions
@@ -5,16 +5,19 @@
package org.jetbrains.kotlin.idea.scripting.gradle package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
data class GradleKotlinScriptConfigurationInputs( data class GradleKotlinScriptConfigurationInputs(
val buildScriptAndPluginsSections: String val buildScriptAndPluginsSections: String,
val timeStamp: Long
) : CachedConfigurationInputs { ) : CachedConfigurationInputs {
override fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile?): Boolean { override fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile?): Boolean {
val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) ?: return false
return actualStamp == this return actualStamp.buildScriptAndPluginsSections == this.buildScriptAndPluginsSections
&& project.service<GradleScriptInputsWatcher>().areAffectedFilesUpToDate(file, timeStamp)
} }
} }
@@ -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<VirtualFile> { 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
}
}
@@ -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<VirtualFile> { 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
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.scripting.gradle package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.openapi.components.service
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
@@ -34,10 +35,8 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project
if (file != null) { if (file != null) {
// *.gradle.kts file was changed // *.gradle.kts file was changed
updater.ensureUpToDatedConfigurationSuggested(file) updater.ensureUpToDatedConfigurationSuggested(file)
updater.postponeConfigurationReload(ScriptConfigurationCacheScope.Except(file))
} else {
updater.postponeConfigurationReload(ScriptConfigurationCacheScope.All)
} }
project.service<GradleScriptInputsWatcher>().addToStorage(vFile)
} }
override fun isApplicable(vFile: VirtualFile): Boolean { override fun isApplicable(vFile: VirtualFile): Boolean {
@@ -55,7 +55,7 @@ fun getGradleScriptInputsStamp(
} }
} }
GradleKotlinScriptConfigurationInputs(result.toString()) GradleKotlinScriptConfigurationInputs(result.toString(), file.timeStamp)
} else null } else null
} }
} }
@@ -103,6 +103,44 @@ class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() {
assertConfigurationUpToDate(testFiles.settings) 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() { fun testFileAttributes() {
assertAndLoadInitialConfiguration(testFiles.buildKts) assertAndLoadInitialConfiguration(testFiles.buildKts)
+2
View File
@@ -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." This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place."
defaultValue="true" defaultValue="true"
restartRequired="false"/> restartRequired="false"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher"/>
</extensions> </extensions>
<actions> <actions>
+2
View File
@@ -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." This setting currently affects only HMPP projects. You may need to delete existing test configurations for the change to take place."
defaultValue="true" defaultValue="true"
restartRequired="false"/> restartRequired="false"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcher"/>
</extensions> </extensions>
<actions> <actions>