diff --git a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt index 7cada4f1753c..dbd79f0e9bb5 100644 --- a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt +++ b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt @@ -7,7 +7,6 @@ import com.intellij.openapi.application.PathManager import com.intellij.openapi.application.appSystemDir import com.intellij.openapi.components.* import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil -import com.intellij.openapi.components.impl.stores.SaveSessionAndFile import com.intellij.openapi.diagnostic.runAndLogException import com.intellij.openapi.util.NamedJDOMExternalizable import com.intellij.util.io.systemIndependentPath @@ -35,24 +34,19 @@ class ApplicationStoreImpl(private val application: Application, pathMacroManage storageManager.addMacro(StoragePathMacros.CACHE_FILE, appSystemDir.resolve("workspace").resolve("app.xml").systemIndependentPath) } - override suspend fun doSave(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) { - val saveSessionManager = saveSettingsSavingComponentsAndCommitComponents(errors, isForceSavingAllSettings) + override suspend fun doSave(result: SaveResult, isForceSavingAllSettings: Boolean) { + val saveSessionManager = saveSettingsSavingComponentsAndCommitComponents(result, isForceSavingAllSettings) // todo can we store default project in parallel to regular saving? for now only flush on disk is async, but not component committing coroutineScope { launch { - saveSessionManager.save(readonlyFiles, errors) + saveSessionManager.save().appendTo(result) } launch { // here, because no Project (and so, ProjectStoreImpl) on Welcome Screen - serviceIfCreated()?.save(errors, readonlyFiles, isForceSavingAllSettings) - } - } - } - - override fun createSaveSessionProducerManager(): SaveSessionProducerManager { - return object : SaveSessionProducerManager() { - override suspend fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { - return super.save(readonlyFiles, errors) + val r = serviceIfCreated()?.save(isForceSavingAllSettings) ?: return@launch + // ignore + r.isChanged = false + r.appendTo(result) } } } diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index a6ae30e2b10f..9a7e28bea735 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -13,7 +13,6 @@ import com.intellij.openapi.components.* import com.intellij.openapi.components.StateStorageChooserEx.Resolution import com.intellij.openapi.components.impl.ComponentManagerImpl import com.intellij.openapi.components.impl.stores.IComponentStore -import com.intellij.openapi.components.impl.stores.SaveSessionAndFile import com.intellij.openapi.components.impl.stores.UnknownMacroNotification import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.diagnostic.logger @@ -32,7 +31,6 @@ import com.intellij.util.SmartList import com.intellij.util.SystemProperties import com.intellij.util.containers.SmartHashSet import com.intellij.util.containers.isNullOrEmpty -import com.intellij.util.lang.CompoundRuntimeException import com.intellij.util.messages.MessageBus import com.intellij.util.xmlb.XmlSerializerUtil import gnu.trove.THashMap @@ -131,16 +129,24 @@ abstract class ComponentStoreImpl : IComponentStore { } final override suspend fun save(isForceSavingAllSettings: Boolean) { - val errors = SmartList() - val readonlyFiles = SmartList() - doSave(errors, readonlyFiles, isForceSavingAllSettings) - CompoundRuntimeException.throwIfNotEmpty(errors) + val result = SaveResult() + doSave(result, isForceSavingAllSettings) + result.throwIfErrored() } - internal abstract suspend fun doSave(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) + internal abstract suspend fun doSave(result: SaveResult, isForceSavingAllSettings: Boolean) + + internal suspend fun createSaveSessionManagerAndSaveComponents(saveResult: SaveResult, isForceSavingAllSettings: Boolean): SaveSessionProducerManager { + return withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { + val errors = SmartList() + val manager = doCreateSaveSessionManagerAndSaveComponents(isForceSavingAllSettings, errors) + saveResult.addErrors(errors) + manager + } + } @CalledInAwt - internal fun createSaveSessionManagerAndSaveComponents(isForce: Boolean, errors: MutableList): SaveSessionProducerManager { + internal fun doCreateSaveSessionManagerAndSaveComponents(isForce: Boolean, errors: MutableList): SaveSessionProducerManager { val saveSessionProducerManager = createSaveSessionProducerManager() saveComponents(isForce, saveSessionProducerManager, errors) return saveSessionProducerManager @@ -218,12 +224,12 @@ abstract class ComponentStoreImpl : IComponentStore { commitComponent(externalizationSession, ComponentInfoImpl(component, stateSpec), null) val absolutePath = Paths.get(storageManager.expandMacros(findNonDeprecated(stateSpec.storages).path)).toAbsolutePath().toString() runUndoTransparentWriteAction { - val errors: MutableList = SmartList() + val saveResult = SaveResult() val newDisposable = Disposer.newDisposable() try { VfsRootAccess.allowRootAccess(newDisposable, absolutePath) runBlocking { - val isSomethingChanged = externalizationSession.save(errors = errors) + val isSomethingChanged = externalizationSession.save().isChanged if (!isSomethingChanged) { LOG.info("saveApplicationComponent is called for ${stateSpec.name} but nothing to save") } @@ -232,7 +238,7 @@ abstract class ComponentStoreImpl : IComponentStore { finally { Disposer.dispose(newDisposable) } - CompoundRuntimeException.throwIfNotEmpty(errors) + saveResult.throwIfErrored() } } @@ -583,10 +589,9 @@ private fun notifyUnknownMacros(store: IComponentStore, project: Project, compon // to make sure that ApplicationStore or ProjectStore will not call incomplete doSave implementation // (because these stores combine several calls for better control/async instead of simple sequential delegation) abstract class ChildlessComponentStore : ComponentStoreImpl() { - override suspend fun doSave(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) { - withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { - createSaveSessionManagerAndSaveComponents(isForceSavingAllSettings, errors) - } - .save(readonlyFiles, errors) + override suspend fun doSave(result: SaveResult, isForceSavingAllSettings: Boolean) { + createSaveSessionManagerAndSaveComponents(result, isForceSavingAllSettings) + .save() + .appendTo(result) } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt b/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt index 3da6f8ed2c89..4e4a9870bd0b 100644 --- a/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt +++ b/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt @@ -5,10 +5,10 @@ import com.intellij.openapi.application.AppUIExecutor import com.intellij.openapi.application.async.coroutineDispatchingContext import com.intellij.openapi.components.SettingsSavingComponent import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.util.SmartList import com.intellij.util.containers.ContainerUtil import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() { @Suppress("DEPRECATION") @@ -27,31 +27,34 @@ abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() { super.initComponent(component, isService) } - internal suspend fun saveSettingsSavingComponentsAndCommitComponents(errors: MutableList, isForceSavingAllSettings: Boolean): SaveSessionProducerManager { + internal suspend fun saveSettingsSavingComponentsAndCommitComponents(result: SaveResult, isForceSavingAllSettings: Boolean): SaveSessionProducerManager { coroutineScope { // expects EDT launch(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { + @Suppress("Duplicates") + val errors = SmartList() for (settingsSavingComponent in settingsSavingComponents) { runAndCollectException(errors) { settingsSavingComponent.save() } } + result.addErrors(errors) } launch { + val errors = SmartList() for (settingsSavingComponent in asyncSettingsSavingComponents) { runAndCollectException(errors) { settingsSavingComponent.save() } } + result.addErrors(errors) } } // SchemeManager (old settingsSavingComponent) must be saved before saving components (component state uses scheme manager in an ipr project, so, we must save it before) // so, call sequentially it, not inside coroutineScope - return withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { - createSaveSessionManagerAndSaveComponents(isForceSavingAllSettings, errors) - } + return createSaveSessionManagerAndSaveComponents(result, isForceSavingAllSettings) } } diff --git a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt index e992ea61f583..2a2c5ee16756 100644 --- a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt @@ -3,7 +3,6 @@ package com.intellij.configurationStore import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.* -import com.intellij.openapi.components.impl.stores.SaveSessionAndFile import com.intellij.openapi.project.Project import org.jdom.Element import java.io.Writer @@ -104,8 +103,10 @@ internal class DefaultProjectExportableAndSaveTrigger { @Volatile var project: Project? = null - suspend fun save(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) { - val project = project ?: return - (project.stateStore as ComponentStoreImpl).doSave(errors, readonlyFiles, isForceSavingAllSettings) + suspend fun save(isForceSavingAllSettings: Boolean): SaveResult { + val project = project ?: return SaveResult.EMPTY + val result = SaveResult() + (project.stateStore as ComponentStoreImpl).doSave(result, isForceSavingAllSettings) + return result } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/FileBasedStorage.kt b/platform/configuration-store-impl/src/FileBasedStorage.kt index eb6302a6e7ac..d730d1b17797 100644 --- a/platform/configuration-store-impl/src/FileBasedStorage.kt +++ b/platform/configuration-store-impl/src/FileBasedStorage.kt @@ -319,7 +319,8 @@ private fun deleteFile(file: Path, requestor: Any, virtualFile: VirtualFile?) { else { throw ReadOnlyModificationException(virtualFile, object : SaveSession { override fun save() { - deleteFile(requestor, virtualFile) + // caller must wraps into undo transparent and write action + virtualFile.delete(requestor) } }) } diff --git a/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt b/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt index 8fc71099f091..d877c0e28e1c 100644 --- a/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt +++ b/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt @@ -3,52 +3,74 @@ package com.intellij.configurationStore import com.intellij.notification.Notifications import com.intellij.notification.NotificationsManager -import com.intellij.openapi.application.runReadAction -import com.intellij.openapi.components.impl.stores.IComponentStore +import com.intellij.openapi.application.AppUIExecutor +import com.intellij.openapi.application.async.coroutineDispatchingContext +import com.intellij.openapi.application.async.inUndoTransparentAction +import com.intellij.openapi.application.async.inWriteAction import com.intellij.openapi.components.impl.stores.SaveSessionAndFile import com.intellij.openapi.project.Project import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification import com.intellij.openapi.vfs.ReadonlyStatusHandler import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.SmartList import com.intellij.util.containers.mapSmart -import com.intellij.util.lang.CompoundRuntimeException +import kotlinx.coroutines.withContext internal class ProjectSaveSessionProducerManager(private val project: Project) : SaveSessionProducerManager() { - override suspend fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { - val isChanged = super.save(readonlyFiles, errors) + suspend fun saveWithAdditionalSaveSessions(extraSessions: List): SaveResult { + val saveSessions = SmartList() + collectSaveSessions(saveSessions) + if (saveSessions.isEmpty() && extraSessions.isEmpty()) { + return SaveResult.EMPTY + } + val saveResult = withContext(AppUIExecutor.onUiThread().inUndoTransparentAction().inWriteAction().coroutineDispatchingContext()) { + val r = SaveResult() + saveSessions(extraSessions, r) + saveSessions(saveSessions, r) + r + } + validate(saveResult) + return saveResult + } + + private suspend fun validate(saveResult: SaveResult) { val notifications = getUnableToSaveNotifications() + val readonlyFiles = saveResult.readonlyFiles if (readonlyFiles.isEmpty()) { notifications.forEach { it.expire() } - return isChanged + return } if (!notifications.isEmpty()) { - throw IComponentStore.SaveCancelledException() + throw UnresolvedReadOnlyFilesException(readonlyFiles.mapSmart { it.file }) } - val status = runReadAction { + val status = withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(getFilesList(readonlyFiles)) } + if (status.hasReadonlyFiles()) { - dropUnableToSaveProjectNotification(project, status.readonlyFiles.toList()) - throw IComponentStore.SaveCancelledException() + val unresolvedReadOnlyFiles = status.readonlyFiles.toList() + dropUnableToSaveProjectNotification(project, unresolvedReadOnlyFiles) + saveResult.addError(UnresolvedReadOnlyFilesException(unresolvedReadOnlyFiles)) + return } val oldList = readonlyFiles.toTypedArray() readonlyFiles.clear() - for (entry in oldList) { - executeSave(entry.session, readonlyFiles, errors) - } - - CompoundRuntimeException.throwIfNotEmpty(errors) + withContext(AppUIExecutor.onUiThread().inUndoTransparentAction().inWriteAction().coroutineDispatchingContext()) { + val r = SaveResult() + for (entry in oldList) { + executeSave(entry.session, r) + } + r + }.appendTo(saveResult) if (!readonlyFiles.isEmpty()) { dropUnableToSaveProjectNotification(project, getFilesList(readonlyFiles)) - throw IComponentStore.SaveCancelledException() + saveResult.addError(UnresolvedReadOnlyFilesException(readonlyFiles.mapSmart { it.file })) } - - return isChanged } private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: List) { diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index c5696e2960d8..3d41d5370ea7 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -6,13 +6,10 @@ import com.intellij.ide.highlighter.WorkspaceFileType import com.intellij.openapi.application.AppUIExecutor import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.async.coroutineDispatchingContext -import com.intellij.openapi.application.async.inUndoTransparentAction -import com.intellij.openapi.application.async.inWriteAction import com.intellij.openapi.application.runReadAction import com.intellij.openapi.components.* import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.components.impl.stores.IProjectStore -import com.intellij.openapi.components.impl.stores.SaveSessionAndFile import com.intellij.openapi.diagnostic.runAndLogException import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager @@ -329,7 +326,7 @@ private open class ProjectStoreImpl(project: Project, private val pathMacroManag } } - override suspend fun doSave(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) = coroutineScope { + final override suspend fun doSave(result: SaveResult, isForceSavingAllSettings: Boolean) { coroutineScope { launch { try { @@ -340,43 +337,42 @@ private open class ProjectStoreImpl(project: Project, private val pathMacroManag } } launch { - saveSettingsSavingComponentsAndCommitComponents(errors, isForceSavingAllSettings).save(readonlyFiles, errors) + // save modules before project + val errors = SmartList() + val moduleSaveSessions = saveModules(errors, isForceSavingAllSettings) + result.addErrors(errors) + + (saveSettingsSavingComponentsAndCommitComponents(result, isForceSavingAllSettings) as ProjectSaveSessionProducerManager) + .saveWithAdditionalSaveSessions(moduleSaveSessions) + .appendTo(result) } } } + protected open suspend fun saveModules(errors: MutableList, isForceSavingAllSettings: Boolean): List { + return emptyList() + } + final override fun createSaveSessionProducerManager() = ProjectSaveSessionProducerManager(project) } private class ProjectWithModulesStoreImpl(project: Project, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) { - override suspend fun doSave(errors: MutableList, readonlyFiles: MutableList, isForceSavingAllSettings: Boolean) { - // save modules before project - saveModules(ModuleManager.getInstance(project)?.modules ?: Module.EMPTY_ARRAY, errors, readonlyFiles, isForceSavingAllSettings) - - super.doSave(errors, readonlyFiles, isForceSavingAllSettings) - } - - private suspend fun saveModules(modules: Array, errors: MutableList, readonlyFiles: MutableList, isForce: Boolean) { + override suspend fun saveModules(errors: MutableList, isForceSavingAllSettings: Boolean): List { + val modules = ModuleManager.getInstance(project)?.modules ?: Module.EMPTY_ARRAY if (modules.isEmpty()) { - return + return emptyList() } - withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { + return withContext(AppUIExecutor.onUiThread().coroutineDispatchingContext()) { // do no create with capacity because very rarely a lot of modules will be modified val saveSessions: MutableList = SmartList() // commit components for (module in modules) { val moduleStore = ModuleServiceManager.getService(module, IComponentStore::class.java) as ComponentStoreImpl // collectSaveSessions is very cheap, so, do it in EDT - moduleStore.createSaveSessionManagerAndSaveComponents(isForce, errors).collectSaveSessions(saveSessions) - } - - if (!saveSessions.isEmpty()) { - withContext(AppUIExecutor.onUiThread().inUndoTransparentAction().inWriteAction().coroutineDispatchingContext()) { - // flush on disk - saveSessions(saveSessions, readonlyFiles, errors) - } + moduleStore.doCreateSaveSessionManagerAndSaveComponents(isForceSavingAllSettings, errors).collectSaveSessions(saveSessions) } + saveSessions } } } diff --git a/platform/configuration-store-impl/src/SaveExecutor.kt b/platform/configuration-store-impl/src/SaveExecutor.kt index f8700d2c42bc..8fc8b4dee247 100644 --- a/platform/configuration-store-impl/src/SaveExecutor.kt +++ b/platform/configuration-store-impl/src/SaveExecutor.kt @@ -12,11 +12,11 @@ import com.intellij.util.SmartList import kotlinx.coroutines.withContext import java.util.* -interface SaveExecutor { +internal interface SaveExecutor { /** * @return was something really saved */ - suspend fun save(readonlyFiles: MutableList = SmartList(), errors: MutableList): Boolean + suspend fun save(): SaveResult } internal open class SaveSessionProducerManager : SaveExecutor { @@ -56,44 +56,48 @@ internal open class SaveSessionProducerManager : SaveExecutor { } } - override suspend fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { + override suspend fun save(): SaveResult { val saveSessions = SmartList() collectSaveSessions(saveSessions) if (saveSessions.isEmpty()) { - return false + return SaveResult.EMPTY + } + + val task = { + val result = SaveResult() + saveSessions(saveSessions, result) + result } - val task = { saveSessions(saveSessions, readonlyFiles, errors) } if (isVfsRequired) { - withContext(AppUIExecutor.onUiThread().inUndoTransparentAction().inWriteAction().coroutineDispatchingContext()) { + return withContext(AppUIExecutor.onUiThread().inUndoTransparentAction().inWriteAction().coroutineDispatchingContext()) { task() } } else { - task() + return task() } - return true } } -internal fun saveSessions(saveSessions: MutableList, readonlyFiles: MutableList, errors: MutableList) { +internal fun saveSessions(saveSessions: List, result: SaveResult) { for (saveSession in saveSessions) { - executeSave(saveSession, readonlyFiles, errors) + executeSave(saveSession, result) } } -internal fun executeSave(session: SaveSession, readonlyFiles: MutableList, errors: MutableList) { +internal fun executeSave(session: SaveSession, result: SaveResult) { try { session.save() } catch (e: ReadOnlyModificationException) { LOG.warn(e) - readonlyFiles.add(SaveSessionAndFile(e.session ?: session, e.file)) + result.addReadOnlyFile(SaveSessionAndFile(e.session ?: session, e.file)) } catch (e: ProcessCanceledException) { throw e } catch (e: Exception) { - errors.add(e) + result.addError(e) } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/SaveResult.kt b/platform/configuration-store-impl/src/SaveResult.kt new file mode 100644 index 000000000000..d182567f8c59 --- /dev/null +++ b/platform/configuration-store-impl/src/SaveResult.kt @@ -0,0 +1,59 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.configurationStore + +import com.intellij.openapi.components.impl.stores.SaveSessionAndFile +import com.intellij.util.SmartList +import com.intellij.util.lang.CompoundRuntimeException + +internal class SaveResult { + companion object { + val EMPTY = SaveResult() + } + + private val errors: MutableList = SmartList() + val readonlyFiles: MutableList = SmartList() + + @Suppress("MemberVisibilityCanBePrivate") + var isChanged = false + + @Synchronized + fun addError(error: Throwable) { + errors.add(error) + } + + @Synchronized + fun addReadOnlyFile(info: SaveSessionAndFile) { + readonlyFiles.add(info) + } + + fun addErrors(list: List) { + if (list.isEmpty()) { + return + } + + synchronized(this) { + errors.addAll(list) + } + } + + @Synchronized + fun appendTo(saveResult: SaveResult) { + if (this === EMPTY) { + return + } + + synchronized(saveResult) { + saveResult.errors.addAll(errors) + saveResult.readonlyFiles.addAll(readonlyFiles) + + if (isChanged) { + saveResult.isChanged = isChanged + } + } + } + + @Synchronized + fun throwIfErrored() { + CompoundRuntimeException.throwIfNotEmpty(errors) + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/configurationStore/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/configurationStore/StateStorageBase.kt index f30d9623cde3..fe319644201e 100644 --- a/platform/platform-impl/src/com/intellij/configurationStore/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/configurationStore/StateStorageBase.kt @@ -1,10 +1,11 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.configurationStore import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.impl.stores.BatchUpdateListener import com.intellij.openapi.diagnostic.debugOrInfoIfTestMode import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.messages.MessageBus import org.jdom.Element import java.util.concurrent.atomic.AtomicReference @@ -83,4 +84,6 @@ inline fun runBatchUpdate(messageBus: MessageBus, runnable: () -> T): T { finally { publisher.onBatchUpdateFinished() } -} \ No newline at end of file +} + +class UnresolvedReadOnlyFilesException(val files: List) : RuntimeException() \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt b/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt index e34c772762b1..bdff5aac16ef 100644 --- a/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt +++ b/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt @@ -13,7 +13,6 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx import com.intellij.openapi.components.ComponentManager import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.State -import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.components.stateStore import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileEditor.FileDocumentManager @@ -28,7 +27,7 @@ import kotlinx.coroutines.runBlocking private val LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.StoreUtil") /** - * Consider to not use this method in tests, for tests direct saving of state store is ok. + * Do not use this method in tests, instead directly save using state store. */ @JvmOverloads fun saveSettings(componentManager: ComponentManager, isForceSavingAllSettings: Boolean = false) { @@ -39,7 +38,7 @@ fun saveSettings(componentManager: ComponentManager, isForceSavingAllSettings: B componentManager.stateStore.save(isForceSavingAllSettings = isForceSavingAllSettings) } } - catch (e: IComponentStore.SaveCancelledException) { + catch (e: UnresolvedReadOnlyFilesException) { LOG.info(e) } catch (e: Throwable) { diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.kt b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.kt index f7bd69989140..10030195a48a 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.kt @@ -24,8 +24,6 @@ interface IComponentStore { fun isReloadPossible(componentNames: Set): Boolean - class SaveCancelledException : RuntimeException() - suspend fun save(isForceSavingAllSettings: Boolean = false) @TestOnly