Scripting: use VFS events instead of document changes to track changes outside of IDE (KT-35557)
^KT-35557 Fixed
This commit is contained in:
+17
-17
@@ -6,15 +6,14 @@
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
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.PathUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.plugins.gradle.settings.GradleLocalSettings
|
||||
import java.nio.file.Paths
|
||||
|
||||
@State(
|
||||
name = "KotlinBuildScriptsModificationInfo",
|
||||
@@ -23,21 +22,22 @@ import java.nio.file.Paths
|
||||
class GradleScriptInputsWatcher(val project: Project) : PersistentStateComponent<GradleScriptInputsWatcher.Storage> {
|
||||
private var storage = Storage()
|
||||
|
||||
init {
|
||||
initStorage(project)
|
||||
}
|
||||
fun startWatching() {
|
||||
project.messageBus.connect().subscribe(
|
||||
VirtualFileManager.VFS_CHANGES,
|
||||
object : BulkFileListener {
|
||||
override fun after(events: List<VFileEvent>) {
|
||||
if (project.isDisposed) return
|
||||
|
||||
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) {
|
||||
storage.fileChanged(file, file.timeStamp)
|
||||
val files = getAffectedGradleProjectFiles(project)
|
||||
for (event in events) {
|
||||
val file = event.file ?: return
|
||||
if (isInAffectedGradleProjectFiles(files, file)) {
|
||||
storage.fileChanged(file, file.timeStamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun areRelatedFilesUpToDate(file: VirtualFile, timeStamp: Long): Boolean {
|
||||
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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.components.*
|
||||
import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.plugins.gradle.settings.GradleLocalSettings
|
||||
import java.nio.file.Paths
|
||||
|
||||
@State(
|
||||
name = "KotlinBuildScriptsModificationInfo",
|
||||
storages = [Storage(StoragePathMacros.CACHE_FILE)]
|
||||
)
|
||||
class GradleScriptInputsWatcher(val project: Project) : PersistentStateComponent<GradleScriptInputsWatcher.Storage> {
|
||||
private var storage = Storage()
|
||||
|
||||
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) {
|
||||
storage.fileChanged(file, file.timeStamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun lastModifiedFileTimeStamp(file: VirtualFile): Long = storage.lastModifiedTimeStampExcept(file)
|
||||
|
||||
fun areRelatedFilesUpToDate(file: VirtualFile, timeStamp: Long): Boolean {
|
||||
return lastModifiedFileTimeStamp(file) < timeStamp
|
||||
}
|
||||
|
||||
class Storage(
|
||||
private var lastModifiedTS: Long = 0,
|
||||
private var lastModifiedFiles: MutableSet<String> = hashSetOf(),
|
||||
private var previousModifiedTS: Long = 0,
|
||||
private var previousModifiedFiles: MutableSet<String> = hashSetOf()
|
||||
) {
|
||||
fun lastModifiedTimeStampExcept(file: VirtualFile): Long {
|
||||
val fileId = getFileId(file)
|
||||
synchronized(this) {
|
||||
if (lastModifiedFiles.contains(fileId) && lastModifiedFiles.size == 1) {
|
||||
return previousModifiedTS
|
||||
}
|
||||
return lastModifiedTS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun fileChanged(file: VirtualFile, ts: Long) {
|
||||
val fileId = getFileId(file)
|
||||
synchronized(this) {
|
||||
when {
|
||||
ts > lastModifiedTS -> {
|
||||
previousModifiedFiles = lastModifiedFiles
|
||||
previousModifiedTS = lastModifiedTS
|
||||
|
||||
lastModifiedFiles = hashSetOf(fileId)
|
||||
lastModifiedTS = ts
|
||||
}
|
||||
ts == lastModifiedTS -> {
|
||||
lastModifiedFiles.add(fileId)
|
||||
}
|
||||
ts == previousModifiedTS -> {
|
||||
previousModifiedFiles.add(fileId)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFileId(file: VirtualFile): String {
|
||||
val canonized = PathUtil.getCanonicalPath(file.path)
|
||||
return FileUtil.toSystemIndependentName(canonized)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getState(): Storage {
|
||||
return storage
|
||||
}
|
||||
|
||||
override fun loadState(state: Storage) {
|
||||
this.storage = state
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun clearAndRefillState() {
|
||||
loadState(project.service<GradleScriptInputsWatcher>().state)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun fileChanged(file: VirtualFile, ts: Long) {
|
||||
storage.fileChanged(file, ts)
|
||||
}
|
||||
}
|
||||
+6
-9
@@ -6,22 +6,18 @@
|
||||
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
|
||||
import com.intellij.util.io.systemIndependentPath
|
||||
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.plugins.gradle.GradleManager
|
||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
|
||||
open class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
|
||||
init {
|
||||
// start GradleScriptInputsWatcher to track changes in gradle-configuration related files
|
||||
project.service<GradleScriptInputsWatcher>().startWatching()
|
||||
}
|
||||
|
||||
override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||
if (!isGradleKotlinScript(vFile)) return
|
||||
|
||||
if (useScriptConfigurationFromImportOnly()) {
|
||||
// do nothing
|
||||
} else {
|
||||
@@ -36,10 +32,11 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project
|
||||
// *.gradle.kts file was changed
|
||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||
}
|
||||
project.service<GradleScriptInputsWatcher>().fileChanged(vFile, vFile.timeStamp)
|
||||
}
|
||||
|
||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
||||
if (!isGradleKotlinScript(vFile)) return false
|
||||
|
||||
return isInAffectedGradleProjectFiles(project, vFile)
|
||||
}
|
||||
}
|
||||
+2
-12
@@ -5,14 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
|
||||
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationLoadingTest
|
||||
import org.jetbrains.kotlin.idea.script.addExtensionPointInTest
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.io.File
|
||||
@@ -28,17 +24,11 @@ class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false
|
||||
// should be initialized explicitly because we do not have a real Gradle Project in this test
|
||||
project.service<GradleScriptInputsWatcher>().startWatching()
|
||||
}
|
||||
|
||||
override fun setUpTestProject() {
|
||||
addExtensionPointInTest(
|
||||
ScriptChangeListener.LISTENER,
|
||||
project,
|
||||
TestGradleScriptListener(project),
|
||||
testRootDisposable
|
||||
)
|
||||
|
||||
val rootDir = "idea/testData/script/definition/loading/gradle/"
|
||||
|
||||
val settings: KtFile = addFileToProject(rootDir + GradleConstants.KOTLIN_DSL_SETTINGS_FILE_NAME)
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* 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.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
|
||||
internal class TestGradleScriptListener(project: Project) : GradleScriptListener(project) {
|
||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user