IDEA-157763 Settings repository for IDE: initial
authorAlexander Lobas <Alexander.Lobas@jetbrains.com>
Wed, 10 Aug 2016 13:57:12 +0000 (16:57 +0300)
committerAlexander Lobas <Alexander.Lobas@jetbrains.com>
Wed, 10 Aug 2016 13:58:56 +0000 (16:58 +0300)
platform/configuration-store-impl/src/SchemeManagerImpl.kt
platform/configuration-store-impl/src/StateStorageManagerImpl.kt
platform/configuration-store-impl/src/StreamProvider.kt
platform/configuration-store-impl/src/XmlElementStorage.kt
platform/configuration-store-impl/src/com/intellij/configurationStore/StreamProviderWrapper.java [new file with mode: 0644]
plugins/settings-repository/src/IcsManager.kt
plugins/settings-repository/src/actions/SyncAction.kt
plugins/settings-repository/src/copyAppSettingsToRepository.kt
plugins/settings-repository/src/settings/upstreamEditor.kt

index ce5609e5a5c97fdfc70d9b290faea95f2fbdc888..04c733380225e64dd4c0b8262f1bdf8f5b87c6d5 100644 (file)
@@ -282,7 +282,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(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<T : Scheme, MUTABLE_SCHEME : T>(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<T> = this.schemes): MUTABLE_SCHEME? {
     val fileName = file.name
index b9e084623b01a6567e16090aef5971288a917359..30a56c7d5c629d943ef19d12d256af33fb847553 100644 (file)
@@ -54,9 +54,14 @@ open class StateStorageManagerImpl(private val rootTagName: String,
                                    private val virtualFileTracker: StorageVirtualFileTracker? = StateStorageManagerImpl.createDefaultVirtualTracker(componentManager) ) : StateStorageManager {
   private val macros: MutableList<Macro> = ContainerUtil.createLockFreeCopyOnWriteList()
   private val storageLock = ReentrantReadWriteLock()
-  private val storages = THashMap<String, StateStorage>()
+  val storages = THashMap<String, StateStorage>()
 
-  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
index 95f620e4336651499647e7ab17bfd4120ddab4e9..076244797a3bc851181d08a95775c00efdcbcc75 100644 (file)
@@ -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())
 }
index eb027c064f25c4bdf5c79842cb4481c3180f7b69..10002f157bb2cb5fcb1c42fa1686c2bfa0e33b18 100644 (file)
@@ -33,7 +33,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S
                                                        roamingType: RoamingType? = RoamingType.DEFAULT,
                                                        provider: StreamProvider? = null) : StorageBaseEx<StateMap>() {
   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<String>, deleted: Boolean) {
+    updatedFrom(changedComponentNames, deleted, true)
+  }
+
+  fun updatedFrom(changedComponentNames: MutableSet<String>, 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 (file)
index 0000000..24f0aca
--- /dev/null
@@ -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<? super String, Boolean> filter,
+                              @NotNull Function3<? super String, ? super InputStream, ? super Boolean, Boolean> 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);
+  }
+}
index 42e1bce07ee8c726e1261bda26805da0d111218e..5c936d80c8a7cbf18d77bc2b399257a088dbef2b 100644 (file)
@@ -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)
 
index 46b2bd2cef66a47eb8f48cba1f5b99d4c3f8517b..6002ede1cbb52e5a5e72036ccb9f22cb5672bac8 100644 (file)
  */
 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
index eb10009e56e32ca952989912d34208e8db0802a0..94a765e2464e8ab1e2af13fcc60ac5d488c62242 100644 (file)
@@ -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 ->
index 1f249e9a25cf578248be9a61d14dc4954753224c..9be106df655afedef0599722af45bdef1487089f 100644 (file)
@@ -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()