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
|
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||||
|
|
||||||
import com.intellij.openapi.components.*
|
import com.intellij.openapi.components.*
|
||||||
import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.vfs.VfsUtil
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
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 com.intellij.util.PathUtil
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.plugins.gradle.settings.GradleLocalSettings
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
@State(
|
@State(
|
||||||
name = "KotlinBuildScriptsModificationInfo",
|
name = "KotlinBuildScriptsModificationInfo",
|
||||||
@@ -23,21 +22,22 @@ import java.nio.file.Paths
|
|||||||
class GradleScriptInputsWatcher(val project: Project) : PersistentStateComponent<GradleScriptInputsWatcher.Storage> {
|
class GradleScriptInputsWatcher(val project: Project) : PersistentStateComponent<GradleScriptInputsWatcher.Storage> {
|
||||||
private var storage = Storage()
|
private var storage = Storage()
|
||||||
|
|
||||||
init {
|
fun startWatching() {
|
||||||
initStorage(project)
|
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 files = getAffectedGradleProjectFiles(project)
|
||||||
val localSettings = GradleLocalSettings.getInstance(project)
|
for (event in events) {
|
||||||
localSettings.externalConfigModificationStamps.forEach { (path, stamp) ->
|
val file = event.file ?: return
|
||||||
val file = VfsUtil.findFile(Paths.get(path), true)
|
if (isInAffectedGradleProjectFiles(files, file)) {
|
||||||
if (file != null && !file.isDirectory) {
|
storage.fileChanged(file, file.timeStamp)
|
||||||
val calculateCrc = ConfigurationFileCrcFactory(file).create()
|
}
|
||||||
if (calculateCrc != stamp) {
|
}
|
||||||
storage.fileChanged(file, file.timeStamp)
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun areRelatedFilesUpToDate(file: VirtualFile, timeStamp: Long): Boolean {
|
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
|
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||||
|
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
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
|
||||||
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.ScriptChangeListener
|
||||||
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
|
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) {
|
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) {
|
override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
|
||||||
if (!isGradleKotlinScript(vFile)) return
|
|
||||||
|
|
||||||
if (useScriptConfigurationFromImportOnly()) {
|
if (useScriptConfigurationFromImportOnly()) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
@@ -36,10 +32,11 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project
|
|||||||
// *.gradle.kts file was changed
|
// *.gradle.kts file was changed
|
||||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
updater.ensureUpToDatedConfigurationSuggested(file)
|
||||||
}
|
}
|
||||||
project.service<GradleScriptInputsWatcher>().fileChanged(vFile, vFile.timeStamp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(vFile: VirtualFile): Boolean {
|
override fun isApplicable(vFile: VirtualFile): Boolean {
|
||||||
|
if (!isGradleKotlinScript(vFile)) return false
|
||||||
|
|
||||||
return isInAffectedGradleProjectFiles(project, vFile)
|
return isInAffectedGradleProjectFiles(project, vFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-12
@@ -5,14 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.scripting.gradle
|
package org.jetbrains.kotlin.idea.scripting.gradle
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
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.AbstractScriptConfigurationLoadingTest
|
||||||
import org.jetbrains.kotlin.idea.script.addExtensionPointInTest
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -28,17 +24,11 @@ class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() {
|
|||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.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() {
|
override fun setUpTestProject() {
|
||||||
addExtensionPointInTest(
|
|
||||||
ScriptChangeListener.LISTENER,
|
|
||||||
project,
|
|
||||||
TestGradleScriptListener(project),
|
|
||||||
testRootDisposable
|
|
||||||
)
|
|
||||||
|
|
||||||
val rootDir = "idea/testData/script/definition/loading/gradle/"
|
val rootDir = "idea/testData/script/definition/loading/gradle/"
|
||||||
|
|
||||||
val settings: KtFile = addFileToProject(rootDir + GradleConstants.KOTLIN_DSL_SETTINGS_FILE_NAME)
|
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