IDEA-341326 [AutoSync] fix: ignore modification events for settings files that modified before the sync

GitOrigin-RevId: 840f3430402825c314c22fcbb0af5723969b7abc
This commit is contained in:
Sergei Vorobyov
2024-07-04 17:21:00 +02:00
committed by intellij-monorepo-bot
parent d6c0d0b775
commit e19f421272
7 changed files with 42 additions and 28 deletions

View File

@@ -155,6 +155,7 @@ e:com.intellij.openapi.externalSystem.autoimport.ExternalSystemRefreshStatus
- sf:IDLE:com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus
- sf:IN_PROGRESS:com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus
- sf:JUST_FINISHED:com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus
- sf:JUST_STARTED:com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus
- s:getEntries():kotlin.enums.EnumEntries
- s:valueOf(java.lang.String):com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus
- s:values():com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext$ReloadStatus[]

View File

@@ -2,8 +2,8 @@
package com.intellij.openapi.externalSystem.autoimport
import com.intellij.openapi.Disposable
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.Event.CREATE
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.ReloadStatus.JUST_FINISHED
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.Event
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.ReloadStatus
import org.jetbrains.annotations.ApiStatus
interface ExternalSystemProjectAware {
@@ -45,7 +45,8 @@ interface ExternalSystemProjectAware {
*/
@ApiStatus.Experimental
fun isIgnoredSettingsFileEvent(path: String, context: ExternalSystemSettingsFilesModificationContext): Boolean =
context.reloadStatus == JUST_FINISHED && context.event == CREATE
context.reloadStatus == ReloadStatus.JUST_STARTED ||
context.reloadStatus == ReloadStatus.JUST_FINISHED && context.event == Event.CREATE
/**
* Experimental. Please see implementation limitations.

View File

@@ -20,11 +20,11 @@ interface ExternalSystemSettingsFilesModificationContext {
val modificationType: ExternalSystemModificationType
/**
* Current reload status is same for all settings files in one time.
* Current reload status is same for all settings files at one time.
*/
val reloadStatus: ReloadStatus
enum class Event { CREATE, UPDATE, DELETE }
enum class ReloadStatus { IDLE, IN_PROGRESS, JUST_FINISHED }
enum class ReloadStatus { IDLE, IN_PROGRESS, JUST_STARTED, JUST_FINISHED }
}

View File

@@ -5,7 +5,7 @@ import com.intellij.openapi.Disposable
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.autoimport.AutoImportProjectTracker.Companion.isAsyncChangesProcessing
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemModificationType.EXTERNAL
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.Event.*
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.Event
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.ReloadStatus
import com.intellij.openapi.externalSystem.autoimport.ProjectStatus.ProjectEvent.Companion.externalInvalidate
import com.intellij.openapi.externalSystem.autoimport.ProjectStatus.ProjectEvent.Companion.externalModify
@@ -14,7 +14,10 @@ import com.intellij.openapi.externalSystem.autoimport.ProjectStatus.ProjectEvent
import com.intellij.openapi.externalSystem.autoimport.changes.AsyncFilesChangesListener.Companion.subscribeOnDocumentsAndVirtualFilesChanges
import com.intellij.openapi.externalSystem.autoimport.changes.FilesChangesListener
import com.intellij.openapi.externalSystem.autoimport.changes.NewFilesListener.Companion.whenNewFilesCreated
import com.intellij.openapi.externalSystem.autoimport.settings.*
import com.intellij.openapi.externalSystem.autoimport.settings.AsyncSupplier
import com.intellij.openapi.externalSystem.autoimport.settings.BackgroundAsyncSupplier
import com.intellij.openapi.externalSystem.autoimport.settings.CachingAsyncSupplier
import com.intellij.openapi.externalSystem.autoimport.settings.ReadAsyncSupplier
import com.intellij.openapi.externalSystem.util.ExternalSystemActivityKey
import com.intellij.openapi.externalSystem.util.calculateCrc
import com.intellij.openapi.fileEditor.FileDocumentManager
@@ -99,23 +102,26 @@ class ProjectSettingsTracker(
*
* @see ExternalSystemProjectAware.isIgnoredSettingsFileEvent
*/
private fun SettingsFilesStatus.adjustCrc(operationName: String, reloadStatus: ReloadStatus): SettingsFilesStatus {
private fun SettingsFilesStatus.adjustCrc(
operationName: String,
reloadStatus: ReloadStatus,
): SettingsFilesStatus {
val modificationType = getModificationType()
val oldCRC = oldCRC.toMutableMap()
for (path in updated) {
val context = SettingsFilesModificationContext(UPDATE, modificationType, reloadStatus)
val context = SettingsFilesModificationContext(Event.UPDATE, modificationType, reloadStatus)
if (projectAware.isIgnoredSettingsFileEvent(path, context)) {
oldCRC[path] = newCRC[path]!!
}
}
for (path in created) {
val context = SettingsFilesModificationContext(CREATE, modificationType, reloadStatus)
val context = SettingsFilesModificationContext(Event.CREATE, modificationType, reloadStatus)
if (projectAware.isIgnoredSettingsFileEvent(path, context)) {
oldCRC[path] = newCRC[path]!!
}
}
for (path in deleted) {
val context = SettingsFilesModificationContext(DELETE, modificationType, reloadStatus)
val context = SettingsFilesModificationContext(Event.DELETE, modificationType, reloadStatus)
if (projectAware.isIgnoredSettingsFileEvent(path, context)) {
oldCRC.remove(path)
}
@@ -310,7 +316,7 @@ class ProjectSettingsTracker(
) : ExternalSystemSettingsFilesReloadContext
private class SettingsFilesModificationContext(
override val event: ExternalSystemSettingsFilesModificationContext.Event,
override val event: Event,
override val modificationType: ExternalSystemModificationType,
override val reloadStatus: ReloadStatus,
) : ExternalSystemSettingsFilesModificationContext
@@ -319,10 +325,12 @@ class ProjectSettingsTracker(
override fun onProjectReloadStart() {
applyChangesOperation.traceStart()
settingsFilesStatus.updateAndGet {
SettingsFilesStatus(it.newCRC, it.newCRC)
submitSettingsFilesStatusUpdate("onProjectReloadStart") {
isRefreshVfs = true
reloadStatus = ReloadStatus.JUST_STARTED
syncEvent = ::Synchronize
changeEvent = ::externalInvalidate
}
projectStatus.markSynchronized(currentTime())
}
override fun onProjectReloadFinish(status: ExternalSystemRefreshStatus) {

View File

@@ -830,7 +830,7 @@ class AutoReloadTest : AutoReloadTestCase() {
assertStateAndReset(numReload = 0, numSettingsAccess = 2, notified = true, event = "non settings files creation")
scheduleProjectReload()
assertStateAndReset(numReload = 1, numSettingsAccess = 1, notified = false, event = "project reload")
assertStateAndReset(numReload = 1, numSettingsAccess = 2, notified = false, event = "project reload")
configFile1.modify(INTERNAL)
configFile2.modify(INTERNAL)
@@ -843,10 +843,10 @@ class AutoReloadTest : AutoReloadTestCase() {
assertStateAndReset(numReload = 0, numSettingsAccess = 0, notified = true, event = "internal settings files modification")
scheduleProjectReload()
assertStateAndReset(numReload = 1, numSettingsAccess = 1, notified = false, event = "project reload")
assertStateAndReset(numReload = 1, numSettingsAccess = 2, notified = false, event = "project reload")
settings1File.modify(EXTERNAL)
assertStateAndReset(numReload = 1, numSettingsAccess = 1, notified = false, event = "external settings file modification")
assertStateAndReset(numReload = 1, numSettingsAccess = 2, notified = false, event = "external settings file modification")
registerSettingsFile("settings3.groovy")
val settings3File = settings2File.copy("settings3.groovy")
@@ -858,7 +858,7 @@ class AutoReloadTest : AutoReloadTestCase() {
assertStateAndReset(numReload = 0, numSettingsAccess = 0, notified = true, event = "internal settings files modification")
scheduleProjectReload()
assertStateAndReset(numReload = 1, numSettingsAccess = 1, notified = false, event = "project reload")
assertStateAndReset(numReload = 1, numSettingsAccess = 2, notified = false, event = "project reload")
settings3File.modify(INTERNAL)
assertStateAndReset(numReload = 0, numSettingsAccess = 0, notified = true, event = "internal settings file modification")
@@ -983,7 +983,13 @@ class AutoReloadTest : AutoReloadTestCase() {
}
}
fun `test settings file modification during sync (parallel)`() {
/**
* The current implementation of settings files watcher cannot 100% separate cases by the file change time (before or during sync).
* Decided that all files that changed in the begging of sync are changed before sync.
* It means that files don't affect the auto-sync project status.
* (These modifications ignored)
*/
fun `_test settings file modification during sync (parallel)`() {
test { settingsFile ->
enableAsyncExecution()
setDispatcherMergingSpan(10)

View File

@@ -389,7 +389,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
SimpleTestBench(projectAware).apply {
assertStateAndReset(
numReload = 1,
numSettingsAccess = 1,
numSettingsAccess = 2,
notified = false,
numSubscribing = 2,
numUnsubscribing = 0,
@@ -401,7 +401,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
assertStateAndReset(numReload = 0, numSettingsAccess = 1, notified = true, event = "settings file is created")
scheduleProjectReload()
assertStateAndReset(numReload = 1, numSettingsAccess = 1, notified = false, event = "project is reloaded")
assertStateAndReset(numReload = 1, numSettingsAccess = 2, notified = false, event = "project is reloaded")
test(settingsFile)
}

View File

@@ -74,13 +74,11 @@ class MockProjectAware(
}
override fun isIgnoredSettingsFileEvent(path: String, context: ExternalSystemSettingsFilesModificationContext): Boolean {
val condition = ignoredSettingsFiles[path]
if (condition != null) {
return condition(context)
}
else {
return super.isIgnoredSettingsFileEvent(path, context)
if (super.isIgnoredSettingsFileEvent(path, context)) {
return true
}
val condition = ignoredSettingsFiles[path] ?: return false
return condition(context)
}
override fun adjustModificationType(path: String, modificationType: ExternalSystemModificationType): ExternalSystemModificationType {