From fa7cd10e9437aacfb51fac765f6dc2ebb94b473a Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Wed, 10 Aug 2016 16:57:12 +0300 Subject: [PATCH] IDEA-157763 Settings repository for IDE: initial --- .../src/SchemeManagerImpl.kt | 4 +- .../src/StateStorageManagerImpl.kt | 9 ++- .../src/StreamProvider.kt | 2 + .../src/XmlElementStorage.kt | 12 ++-- .../StreamProviderWrapper.java | 62 +++++++++++++++++++ plugins/settings-repository/src/IcsManager.kt | 12 +++- .../src/actions/SyncAction.kt | 11 ++++ .../src/copyAppSettingsToRepository.kt | 3 +- .../src/settings/upstreamEditor.kt | 4 ++ 9 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index ce5609e5a5c9..04c733380225 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -282,7 +282,7 @@ class SchemeManagerImpl(val fileSpec: String, val oldSchemes = schemes val schemes = oldSchemes.toMutableList() val newSchemesOffset = schemes.size - if (provider != null && provider.enabled) { + if (provider != null && provider.isApplicable(fileSpec, roamingType)) { provider.processChildren(fileSpec, roamingType, { canRead(it) }) { name, input, readOnly -> catchAndLog(name) { val scheme = loadScheme(name, input, schemes, filesToDelete) @@ -500,7 +500,7 @@ class SchemeManagerImpl(val fileSpec: String, private val T.fileName: String? get() = schemeToInfo.get(this)?.fileNameWithoutExtension - private fun canRead(name: CharSequence) = (updateExtension && name.endsWith(DEFAULT_EXT, true) || name.endsWith(schemeExtension, true)) && (processor !is LazySchemeProcessor || processor.isSchemeFile(name)) + fun canRead(name: CharSequence) = (updateExtension && name.endsWith(DEFAULT_EXT, true) || name.endsWith(schemeExtension, true)) && (processor !is LazySchemeProcessor || processor.isSchemeFile(name)) private fun readSchemeFromFile(file: VirtualFile, schemes: MutableList = this.schemes): MUTABLE_SCHEME? { val fileName = file.name diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index b9e084623b01..30a56c7d5c62 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -54,9 +54,14 @@ open class StateStorageManagerImpl(private val rootTagName: String, private val virtualFileTracker: StorageVirtualFileTracker? = StateStorageManagerImpl.createDefaultVirtualTracker(componentManager) ) : StateStorageManager { private val macros: MutableList = ContainerUtil.createLockFreeCopyOnWriteList() private val storageLock = ReentrantReadWriteLock() - private val storages = THashMap() + val storages = THashMap() - var streamProvider: StreamProvider? = null + private val streamWrapper = StreamProviderWrapper() + var streamProvider: StreamProvider? + get() = streamWrapper + set (value) { + streamWrapper.setStreamProvider(value) + } // access under storageLock private var isUseVfsListener = if (componentManager == null) ThreeState.NO else ThreeState.UNSURE // unsure because depends on stream provider state diff --git a/platform/configuration-store-impl/src/StreamProvider.kt b/platform/configuration-store-impl/src/StreamProvider.kt index 95f620e43366..076244797a3b 100644 --- a/platform/configuration-store-impl/src/StreamProvider.kt +++ b/platform/configuration-store-impl/src/StreamProvider.kt @@ -17,6 +17,7 @@ package com.intellij.configurationStore import com.intellij.openapi.components.RoamingType import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream +import org.jetbrains.annotations.TestOnly import java.io.InputStream interface StreamProvider { @@ -42,6 +43,7 @@ interface StreamProvider { fun delete(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT) } +@TestOnly fun StreamProvider.write(path: String, content: String) { write(path, content.toByteArray()) } diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index eb027c064f25..10002f157bb2 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -33,7 +33,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S roamingType: RoamingType? = RoamingType.DEFAULT, provider: StreamProvider? = null) : StorageBaseEx() { val roamingType: RoamingType = roamingType ?: RoamingType.DEFAULT - private val provider: StreamProvider? = if (provider == null || roamingType == RoamingType.DISABLED || !provider.isApplicable(fileSpec, this.roamingType)) null else provider + private val provider: StreamProvider? = if (provider == null || roamingType == RoamingType.DISABLED) null else provider protected abstract fun loadLocalData(): Element? @@ -48,7 +48,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S override fun loadData(): StateMap { val element: Element? // we don't use local data if has stream provider - if (provider != null && provider.enabled) { + if (provider != null && provider.isApplicable(fileSpec, roamingType)) { try { element = loadDataFromProvider() dataLoadedFromProvider(element) @@ -130,7 +130,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S } val provider = storage.provider - if (provider != null && provider.enabled) { + if (provider != null && provider.isApplicable(storage.fileSpec, storage.roamingType)) { if (element == null) { provider.delete(storage.fileSpec, storage.roamingType) } @@ -163,13 +163,17 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S } fun updatedFromStreamProvider(changedComponentNames: MutableSet, deleted: Boolean) { + updatedFrom(changedComponentNames, deleted, true) + } + + fun updatedFrom(changedComponentNames: MutableSet, deleted: Boolean, streamProvider: Boolean) { if (roamingType == RoamingType.DISABLED) { // storage roaming was changed to DISABLED, but settings repository has old state return } try { - val newElement = if (deleted) null else loadDataFromProvider() + val newElement = if (deleted) null else if (streamProvider) loadDataFromProvider() else loadLocalData() val states = storageDataRef.get() if (newElement == null) { // if data was loaded, mark as changed all loaded components diff --git a/platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java b/platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java new file mode 100644 index 000000000000..24f0aca09e5f --- /dev/null +++ b/platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java @@ -0,0 +1,62 @@ +package com.intellij.configurationStore; + +import com.intellij.openapi.components.RoamingType; +import kotlin.jvm.functions.Function1; +import kotlin.jvm.functions.Function3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStream; + +/** + * @author Alexander Lobas + */ +public class StreamProviderWrapper implements StreamProvider { + private StreamProvider myStreamProvider; + + @Nullable + public static StreamProvider getOriginalProvider(@Nullable StreamProvider provider) { + if (provider instanceof StreamProviderWrapper) { + return ((StreamProviderWrapper)provider).myStreamProvider; + } + return null; + } + + public void setStreamProvider(@Nullable StreamProvider streamProvider) { + myStreamProvider = streamProvider; + } + + @Override + public boolean getEnabled() { + return myStreamProvider != null && myStreamProvider.getEnabled(); + } + + @Override + public boolean isApplicable(@NotNull String fileSpec, @NotNull RoamingType roamingType) { + return getEnabled() && myStreamProvider.isApplicable(fileSpec, roamingType); + } + + @Nullable + @Override + public InputStream read(@NotNull String fileSpec, @NotNull RoamingType roamingType) { + return myStreamProvider.read(fileSpec, roamingType); + } + + @Override + public void processChildren(@NotNull String path, + @NotNull RoamingType roamingType, + @NotNull Function1 filter, + @NotNull Function3 processor) { + myStreamProvider.processChildren(path, roamingType, filter, processor); + } + + @Override + public void write(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType) { + myStreamProvider.write(fileSpec, content, size, roamingType); + } + + @Override + public void delete(@NotNull String fileSpec, @NotNull RoamingType roamingType) { + myStreamProvider.delete(fileSpec, roamingType); + } +} diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index 42e1bce07ee8..5c936d80c8a7 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -152,10 +152,18 @@ class IcsManager(dir: Path) { } } + fun newStreamProvider() { + val application = ApplicationManager.getApplication() + (application.stateStore.stateStorageManager as StateStorageManagerImpl).streamProvider = ApplicationLevelProvider() + } + fun beforeApplicationLoaded(application: Application) { repositoryActive = repositoryManager.isRepositoryExists() - (application.stateStore.stateStorageManager as StateStorageManagerImpl).streamProvider = ApplicationLevelProvider() + val storage = application.stateStore.stateStorageManager as StateStorageManagerImpl + if (storage.streamProvider == null || !storage.streamProvider!!.enabled) { + storage.streamProvider = ApplicationLevelProvider() + } autoSyncManager.registerListeners(application) @@ -179,6 +187,8 @@ class IcsManager(dir: Path) { override val enabled: Boolean get() = repositoryActive + override fun isApplicable(fileSpec: String, roamingType: RoamingType): Boolean = enabled + override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean) { val fullPath = toRepositoryPath(path, roamingType, null) diff --git a/plugins/settings-repository/src/actions/SyncAction.kt b/plugins/settings-repository/src/actions/SyncAction.kt index 46b2bd2cef66..6002ede1cbb5 100644 --- a/plugins/settings-repository/src/actions/SyncAction.kt +++ b/plugins/settings-repository/src/actions/SyncAction.kt @@ -15,9 +15,12 @@ */ package org.jetbrains.settingsRepository.actions +import com.intellij.configurationStore.StateStorageManagerImpl import com.intellij.notification.NotificationGroup import com.intellij.notification.NotificationType import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.stateStore import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project import org.jetbrains.settingsRepository.* @@ -60,6 +63,14 @@ internal class ConfigureIcsAction : DumbAwareAction() { } override fun update(e: AnActionEvent) { + if (icsManager.repositoryActive) { + e.presentation.isEnabledAndVisible = true + } + else { + val application = ApplicationManager.getApplication() + val provider = (application.stateStore.stateStorageManager as StateStorageManagerImpl).streamProvider + e.presentation.isEnabledAndVisible = provider == null || !provider.enabled + } e.presentation.icon = null } } \ No newline at end of file diff --git a/plugins/settings-repository/src/copyAppSettingsToRepository.kt b/plugins/settings-repository/src/copyAppSettingsToRepository.kt index eb10009e56e3..94a765e2464e 100644 --- a/plugins/settings-repository/src/copyAppSettingsToRepository.kt +++ b/plugins/settings-repository/src/copyAppSettingsToRepository.kt @@ -17,6 +17,7 @@ package org.jetbrains.settingsRepository import com.intellij.configurationStore.ROOT_CONFIG import com.intellij.configurationStore.StateStorageManagerImpl +import com.intellij.configurationStore.StreamProviderWrapper import com.intellij.configurationStore.removeMacroIfStartsWith import com.intellij.ide.actions.ExportableItem import com.intellij.ide.actions.getExportableComponentsMap @@ -33,7 +34,7 @@ import java.nio.file.NoSuchFileException import java.nio.file.Path fun copyLocalConfig(storageManager: StateStorageManagerImpl = ApplicationManager.getApplication()!!.stateStore.stateStorageManager as StateStorageManagerImpl) { - val streamProvider = storageManager.streamProvider!! as IcsManager.IcsStreamProvider + val streamProvider = StreamProviderWrapper.getOriginalProvider(storageManager.streamProvider)!! as IcsManager.IcsStreamProvider val fileToComponents = getExportableComponentsMap(true, false, storageManager) fileToComponents.keys.forEachGuaranteed { file -> diff --git a/plugins/settings-repository/src/settings/upstreamEditor.kt b/plugins/settings-repository/src/settings/upstreamEditor.kt index 1f249e9a25cf..9be106df655a 100644 --- a/plugins/settings-repository/src/settings/upstreamEditor.kt +++ b/plugins/settings-repository/src/settings/upstreamEditor.kt @@ -81,6 +81,10 @@ fun createMergeActions(project: Project?, urlTextField: TextFieldWithBrowseButto } upstreamSet = true + if (repositoryWillBeCreated) { + icsManager.newStreamProvider() + } + if (repositoryWillBeCreated && syncType != SyncType.OVERWRITE_LOCAL) { ApplicationManager.getApplication().saveSettings()