From 516d0efec9add01019bb70f585c59630f2c4e922 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 7 Jan 2019 17:03:38 +0100 Subject: [PATCH] extract ProjectSaveSessionProducerManager --- .../src/ComponentStoreImpl.kt | 45 ++---------- .../src/ProjectSaveSessionProducerManager.kt | 71 +++++++++++++++++++ .../src/ProjectStoreImpl.kt | 50 +------------ .../src/SaveExecutor.kt | 40 +++++++++++ .../project/impl/ProjectManagerImpl.java | 7 +- 5 files changed, 123 insertions(+), 90 deletions(-) create mode 100644 platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt create mode 100644 platform/configuration-store-impl/src/SaveExecutor.kt diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index cdf51c662c55..8518687fc35f 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -135,7 +135,7 @@ abstract class ComponentStoreImpl : IComponentStore { beforeSaveComponents(errors, readonlyFiles) - val saveSessionProducerManager = if (components.isEmpty()) null else SaveSessionProducerManager() + val saveSessionProducerManager = if (components.isEmpty()) null else createSaveSessionProducerManager() if (saveSessionProducerManager != null) { saveComponents(isForce, saveSessionProducerManager, errors) } @@ -148,7 +148,7 @@ abstract class ComponentStoreImpl : IComponentStore { } if (saveSessionProducerManager != null) { - doSave(saveSessionProducerManager, readonlyFiles, errors) + saveSessionProducerManager.save(readonlyFiles, errors) } CompoundRuntimeException.throwIfNotEmpty(errors) @@ -224,7 +224,7 @@ abstract class ComponentStoreImpl : IComponentStore { override fun saveApplicationComponent(component: PersistentStateComponent<*>) { val stateSpec = StoreUtil.getStateSpec(component) LOG.info("saveApplicationComponent is called for ${stateSpec.name}") - val externalizationSession = SaveSessionProducerManager() + val externalizationSession = createSaveSessionProducerManager() commitComponent(externalizationSession, ComponentInfoImpl(component, stateSpec), null) val absolutePath = Paths.get(storageManager.expandMacros(findNonDeprecated(stateSpec.storages).path)).toAbsolutePath().toString() runUndoTransparentWriteAction { @@ -244,6 +244,8 @@ abstract class ComponentStoreImpl : IComponentStore { } } + internal open fun createSaveSessionProducerManager() = SaveSessionProducerManager() + private fun commitComponent(session: SaveSessionProducerManager, info: ComponentInfo, componentName: String?) { val component = info.component @Suppress("DEPRECATION") @@ -280,10 +282,6 @@ abstract class ComponentStoreImpl : IComponentStore { } } - protected open fun doSave(saveSession: SaveExecutor, readonlyFiles: MutableList = arrayListOf(), errors: MutableList) { - saveSession.save(readonlyFiles, errors) - } - private fun initJdomExternalizable(@Suppress("DEPRECATION") component: JDOMExternalizable, componentName: String): String? { doAddComponent(componentName, component, null) @@ -601,37 +599,4 @@ private fun notifyUnknownMacros(store: IComponentStore, project: Project, compon LOG.debug("Reporting unknown path macros $macros in component $componentName") doNotify(macros, project, Collections.singletonMap(substitutor, store)) }, project.disposed) -} - -interface SaveExecutor { - /** - * @return was something really saved - */ - fun save(readonlyFiles: MutableList = SmartList(), errors: MutableList): Boolean -} - -private class SaveSessionProducerManager : SaveExecutor { - private val producers = LinkedHashMap() - - fun getProducer(storage: StateStorage): SaveSessionProducer? { - var producer = producers.get(storage) - if (producer == null) { - producer = storage.createSaveSessionProducer() ?: return null - producers.put(storage, producer) - } - return producer - } - - override fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { - if (producers.isEmpty()) { - return false - } - - var changed = false - for (session in producers.values) { - executeSave(session.createSaveSession() ?: continue, readonlyFiles, errors) - changed = true - } - return changed - } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt b/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt new file mode 100644 index 000000000000..33d9996f0e36 --- /dev/null +++ b/platform/configuration-store-impl/src/ProjectSaveSessionProducerManager.kt @@ -0,0 +1,71 @@ +// 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.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.components.impl.stores.SaveSessionAndFile +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.impl.ProjectManagerImpl +import com.intellij.openapi.vfs.ReadonlyStatusHandler +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.containers.mapSmart +import com.intellij.util.lang.CompoundRuntimeException + +internal class ProjectSaveSessionProducerManager(private val project: Project) : SaveSessionProducerManager() { + override fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { + val isChanged = super.save(readonlyFiles, errors) + + val notifications = getUnableToSaveNotifications() + if (readonlyFiles.isEmpty()) { + notifications.forEach { it.expire() } + return isChanged + } + + if (!notifications.isEmpty()) { + throw IComponentStore.SaveCancelledException() + } + + val status = runReadAction { + ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(getFilesList(readonlyFiles)) + } + if (status.hasReadonlyFiles()) { + dropUnableToSaveProjectNotification(project, status.readonlyFiles.toList()) + throw IComponentStore.SaveCancelledException() + } + + val oldList = readonlyFiles.toTypedArray() + readonlyFiles.clear() + for (entry in oldList) { + executeSave(entry.session, readonlyFiles, errors) + } + + CompoundRuntimeException.throwIfNotEmpty(errors) + + if (!readonlyFiles.isEmpty()) { + dropUnableToSaveProjectNotification(project, getFilesList(readonlyFiles)) + throw IComponentStore.SaveCancelledException() + } + + return isChanged + } + + private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: List) { + val notifications = getUnableToSaveNotifications() + if (notifications.isEmpty()) { + Notifications.Bus.notify( + ProjectManagerImpl.UnableToSaveProjectNotification(project, readOnlyFiles), project) + } + else { + notifications[0].setFiles(readOnlyFiles) + } + } + + private fun getUnableToSaveNotifications(): Array { + return NotificationsManager.getNotificationsManager() + .getNotificationsOfType(ProjectManagerImpl.UnableToSaveProjectNotification::class.java, project) + } +} + +private fun getFilesList(readonlyFiles: List) = readonlyFiles.mapSmart { it.file } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index f718dfc26753..2b330a0f9b11 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -3,8 +3,6 @@ package com.intellij.configurationStore import com.intellij.ide.highlighter.ProjectFileType import com.intellij.ide.highlighter.WorkspaceFileType -import com.intellij.notification.Notifications -import com.intellij.notification.NotificationsManager import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.invokeAndWaitIfNeed import com.intellij.openapi.application.runReadAction @@ -20,7 +18,6 @@ import com.intellij.openapi.project.ProjectCoreUtil import com.intellij.openapi.project.ex.ProjectNameProvider import com.intellij.openapi.project.getProjectCachePath import com.intellij.openapi.project.impl.ProjectImpl -import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification import com.intellij.openapi.project.impl.ProjectStoreClassProvider import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt @@ -33,9 +30,7 @@ import com.intellij.util.PathUtilRt import com.intellij.util.SmartList import com.intellij.util.containers.computeIfAny import com.intellij.util.containers.isNullOrEmpty -import com.intellij.util.containers.mapSmart import com.intellij.util.io.* -import com.intellij.util.lang.CompoundRuntimeException import com.intellij.util.text.nullize import java.nio.file.AccessDeniedException import java.nio.file.Path @@ -333,52 +328,9 @@ private open class ProjectStoreImpl(project: Project, private val pathMacroManag super.beforeSaveComponents(errors, readonlyFiles) } - override fun doSave(saveSession: SaveExecutor, readonlyFiles: MutableList, errors: MutableList) { - super.doSave(saveSession, readonlyFiles, errors) - - val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification::class.java, project) - if (readonlyFiles.isEmpty()) { - notifications.forEach { it.expire() } - return - } - - if (!notifications.isEmpty()) { - throw IComponentStore.SaveCancelledException() - } - - val status = runReadAction { ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(getFilesList(readonlyFiles)) } - if (status.hasReadonlyFiles()) { - dropUnableToSaveProjectNotification(project, status.readonlyFiles.toList()) - throw IComponentStore.SaveCancelledException() - } - - val oldList = readonlyFiles.toTypedArray() - readonlyFiles.clear() - for (entry in oldList) { - executeSave(entry.session, readonlyFiles, errors) - } - - CompoundRuntimeException.throwIfNotEmpty(errors) - - if (!readonlyFiles.isEmpty()) { - dropUnableToSaveProjectNotification(project, getFilesList(readonlyFiles)) - throw IComponentStore.SaveCancelledException() - } - } + final override fun createSaveSessionProducerManager() = ProjectSaveSessionProducerManager(project) } -private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: List) { - val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification::class.java, project) - if (notifications.isEmpty()) { - Notifications.Bus.notify(UnableToSaveProjectNotification(project, readOnlyFiles), project) - } - else { - notifications[0].myFiles = readOnlyFiles - } -} - -private fun getFilesList(readonlyFiles: List) = readonlyFiles.mapSmart { it.file } - private class ProjectWithModulesStoreImpl(project: Project, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) { override fun beforeSaveComponents(errors: MutableList, readonlyFiles: MutableList) { super.beforeSaveComponents(errors, readonlyFiles) diff --git a/platform/configuration-store-impl/src/SaveExecutor.kt b/platform/configuration-store-impl/src/SaveExecutor.kt new file mode 100644 index 000000000000..ebf00174b068 --- /dev/null +++ b/platform/configuration-store-impl/src/SaveExecutor.kt @@ -0,0 +1,40 @@ +// 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.SaveSessionAndFile +import com.intellij.util.SmartList +import java.util.* + +interface SaveExecutor { + /** + * @return was something really saved + */ + fun save(readonlyFiles: MutableList = SmartList(), errors: MutableList): Boolean +} + +internal open class SaveSessionProducerManager : SaveExecutor { + private val producers = LinkedHashMap() + + fun getProducer(storage: StateStorage): SaveSessionProducer? { + var producer = producers.get(storage) + if (producer == null) { + producer = storage.createSaveSessionProducer() ?: return null + producers.put(storage, producer) + } + return producer + } + + override fun save(readonlyFiles: MutableList, errors: MutableList): Boolean { + if (producers.isEmpty()) { + return false + } + + var isChanged = false + for (session in producers.values) { + executeSave(session.createSaveSession() ?: continue, readonlyFiles, errors) + isChanged = true + } + return isChanged + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index c70b427edd11..71aade01f548 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -887,7 +887,12 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { public static class UnableToSaveProjectNotification extends Notification { private Project myProject; - public List myFiles; + + private List myFiles; + + public void setFiles(@NotNull List files) { + myFiles = files; + } public UnableToSaveProjectNotification(@NotNull final Project project, @NotNull List readOnlyFiles) { super("Project Settings", "Could not save project", "Unable to save project files. Please ensure project files are writable and you have permissions to modify them." +