diff --git a/lib/annotations/jdk/java/nio/file/annotations.xml b/lib/annotations/jdk/java/nio/file/annotations.xml
new file mode 100644
index 000000000000..6706a3e31d7b
--- /dev/null
+++ b/lib/annotations/jdk/java/nio/file/annotations.xml
@@ -0,0 +1,8 @@
+
+ -
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt b/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt
index 9fa0e2b953f0..1caac75d4a69 100644
--- a/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt
+++ b/platform/built-in-server/testSrc/BinaryRequestHandlerTest.kt
@@ -20,11 +20,11 @@ import org.jetbrains.io.MessageDecoder
import org.jetbrains.io.NettyUtil
import org.junit.ClassRule
import org.junit.Test
-import java.util.UUID
+import java.util.*
import java.util.concurrent.TimeUnit
// we don't handle String in efficient way - because we want to test readContent/readChars also
-public class BinaryRequestHandlerTest {
+internal class BinaryRequestHandlerTest {
companion object {
@ClassRule val projectRule = ProjectRule()
}
@@ -47,13 +47,13 @@ public class BinaryRequestHandlerTest {
}
})
- val port = BuiltInServerManager.getInstance().waitForStart().getPort()
+ val port = BuiltInServerManager.getInstance().waitForStart().port
val channel = bootstrap.connect(NetUtils.getLoopbackAddress(), port).syncUninterruptibly().channel()
val buffer = channel.alloc().buffer()
buffer.writeByte('C'.toInt())
buffer.writeByte('H'.toInt())
- buffer.writeLong(MyBinaryRequestHandler.ID.getMostSignificantBits())
- buffer.writeLong(MyBinaryRequestHandler.ID.getLeastSignificantBits())
+ buffer.writeLong(MyBinaryRequestHandler.ID.mostSignificantBits)
+ buffer.writeLong(MyBinaryRequestHandler.ID.leastSignificantBits)
val message = Unpooled.copiedBuffer(text, CharsetUtil.UTF_8)
buffer.writeShort(message.readableBytes())
@@ -67,7 +67,7 @@ public class BinaryRequestHandlerTest {
}
})
- if (result.getState() == Promise.State.PENDING) {
+ if (result.state == Promise.State.PENDING) {
val semaphore = Semaphore()
semaphore.down()
result.processed { semaphore.up() }
diff --git a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt
index 9e4583d1aa50..afb961526dab 100644
--- a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt
+++ b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt
@@ -32,9 +32,9 @@ import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import org.jdom.Element
-class ApplicationPathMacroManager : BasePathMacroManager(null)
+private class ApplicationPathMacroManager : BasePathMacroManager(null)
-class ApplicationStoreImpl(private val application: Application, pathMacroManager: PathMacroManager) : ComponentStoreImpl() {
+class ApplicationStoreImpl(private val application: Application, pathMacroManager: PathMacroManager? = null) : ComponentStoreImpl() {
override val storageManager = ApplicationStorageManager(application, pathMacroManager)
// number of app components require some state, so, we load default state in test mode
@@ -42,8 +42,9 @@ class ApplicationStoreImpl(private val application: Application, pathMacroManage
get() = if (application.isUnitTestMode) StateLoadPolicy.LOAD_ONLY_DEFAULT else StateLoadPolicy.LOAD
override fun setPath(path: String) {
- storageManager.addMacro(ROOT_CONFIG, path)
+ // app config must be first, because collapseMacros collapse from fist to last, so, at first we must replace APP_CONFIG because it overlaps ROOT_CONFIG value
storageManager.addMacro(StoragePathMacros.APP_CONFIG, "$path/${ApplicationStorageManager.FILE_STORAGE_DIR}")
+ storageManager.addMacro(ROOT_CONFIG, path)
val configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(path)
if (configDir != null) {
@@ -110,9 +111,9 @@ class ApplicationStorageManager(private val application: Application, pathMacroM
return path
}
- override fun expandNormalizedPath(path: String): String {
+ override fun expandMacros(path: String): String {
if (path[0] == '$') {
- return super.expandNormalizedPath(path)
+ return super.expandMacros(path)
}
else {
return "${expandMacro(StoragePathMacros.APP_CONFIG)}/$path"
diff --git a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt
index 35d8156911a7..56303e7d4ae6 100644
--- a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt
+++ b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt
@@ -73,8 +73,6 @@ internal class DefaultProjectStoreImpl(override val project: ProjectImpl, privat
override fun expandMacros(file: String) = throw UnsupportedOperationException("Method expandMacros not implemented in " + javaClass)
- override fun collapseMacros(path: String) = throw UnsupportedOperationException("Method collapseMacros not implemented in " + javaClass)
-
override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation) = storage
}
diff --git a/platform/configuration-store-impl/src/ProjectStateStorageManager.kt b/platform/configuration-store-impl/src/ProjectStateStorageManager.kt
index 8bd2930c25be..ed8ccf7526d1 100644
--- a/platform/configuration-store-impl/src/ProjectStateStorageManager.kt
+++ b/platform/configuration-store-impl/src/ProjectStateStorageManager.kt
@@ -35,9 +35,9 @@ class ProjectStateStorageManager(macroSubstitutor: TrackingPathMacroSubstitutor,
return path
}
- override fun expandNormalizedPath(path: String): String {
+ override fun expandMacros(path: String): String {
if (path[0] == '$') {
- return super.expandNormalizedPath(path)
+ return super.expandMacros(path)
}
else {
return "${expandMacro(StoragePathMacros.PROJECT_CONFIG_DIR)}/$path"
diff --git a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt
index 174a2de54b4d..f10998ff977c 100644
--- a/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt
+++ b/platform/configuration-store-impl/src/SchemeManagerFactoryImpl.kt
@@ -29,9 +29,9 @@ import com.intellij.util.containers.ContainerUtil
import com.intellij.util.lang.CompoundRuntimeException
import java.io.File
-val ROOT_CONFIG: String = "\$ROOT_CONFIG$"
+val ROOT_CONFIG = "\$ROOT_CONFIG$"
-public abstract class SchemeManagerFactoryBase : SchemesManagerFactory(), SettingsSavingComponent {
+sealed class SchemeManagerFactoryBase : SchemesManagerFactory(), SettingsSavingComponent {
private val managers = ContainerUtil.createLockFreeCopyOnWriteList>()
abstract val componentManager: ComponentManager
@@ -85,27 +85,27 @@ public abstract class SchemeManagerFactoryBase : SchemesManagerFactory(), Settin
CompoundRuntimeException.throwIfNotEmpty(errors)
}
-}
-private class ApplicationSchemeManagerFactory : SchemeManagerFactoryBase() {
- override val componentManager: ComponentManager
- get() = ApplicationManager.getApplication()
+ private class ApplicationSchemeManagerFactory : SchemeManagerFactoryBase() {
+ override val componentManager: ComponentManager
+ get() = ApplicationManager.getApplication()
- override fun checkPath(originalPath: String): String {
- var path = super.checkPath(originalPath)
- if (path.startsWith(ROOT_CONFIG)) {
- path = path.substring(ROOT_CONFIG.length() + 1)
- val message = "Path must not contains ROOT_CONFIG macro, corrected: $path"
- if (ApplicationManager.getApplication().isUnitTestMode) throw AssertionError(message) else LOG.warn(message)
+ override fun checkPath(originalPath: String): String {
+ var path = super.checkPath(originalPath)
+ if (path.startsWith(ROOT_CONFIG)) {
+ path = path.substring(ROOT_CONFIG.length() + 1)
+ val message = "Path must not contains ROOT_CONFIG macro, corrected: $path"
+ if (ApplicationManager.getApplication().isUnitTestMode) throw AssertionError(message) else LOG.warn(message)
+ }
+ return path
}
- return path
+
+ override fun pathToFile(path: String, storageManager: StateStorageManager) = File(storageManager.expandMacros("$ROOT_CONFIG/$path"))
}
- override fun pathToFile(path: String, storageManager: StateStorageManager) = File(storageManager.expandMacros("$ROOT_CONFIG/$path"))
-}
+ private class ProjectSchemeManagerFactory(private val project: Project) : SchemeManagerFactoryBase() {
+ override val componentManager = project
-private class ProjectSchemeManagerFactory(private val project: Project) : SchemeManagerFactoryBase() {
- override val componentManager = project
-
- override fun pathToFile(path: String, storageManager: StateStorageManager) = File(project.basePath, if (ProjectUtil.isDirectoryBased(project)) "${Project.DIRECTORY_STORE_FOLDER}/$path" else ".$path")
+ override fun pathToFile(path: String, storageManager: StateStorageManager) = File(project.basePath, if (ProjectUtil.isDirectoryBased(project)) "${Project.DIRECTORY_STORE_FOLDER}/$path" else ".$path")
+ }
}
\ No newline at end of file
diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt
index 69c4e03e55a5..446902f7bee0 100644
--- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt
+++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt
@@ -52,7 +52,7 @@ open class StateStorageManagerImpl(private val rootTagName: String,
private val storageLock = ReentrantLock()
private val storages = THashMap()
- public var streamProvider: StreamProvider? = null
+ var streamProvider: StreamProvider? = null
// access under storageLock
private var isUseVfsListener = if (componentManager == null) ThreeState.NO else ThreeState.UNSURE // unsure because depends on stream provider state
@@ -138,22 +138,16 @@ open class StateStorageManagerImpl(private val rootTagName: String,
return if (path.endsWith('/')) path.substring(0, path.length() - 1) else path
}
- /**
- * @param path Must be normalized (see normalizeFileSpec})
- * @return System-independent path
- */
- open fun expandNormalizedPath(path: String): String = expandMacros(path)
-
- fun getOrCreateStorage(fileSpec: String,
+ fun getOrCreateStorage(collapsedPath: String,
roamingType: RoamingType = RoamingType.DEFAULT,
storageClass: Class = StateStorage::class.java,
@Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") @SuppressWarnings("deprecation") stateSplitter: Class = StateSplitterEx::class.java): StateStorage {
- val collapsedPath = normalizeFileSpec(fileSpec)
- val key = if (storageClass == StateStorage::class.java) collapsedPath else storageClass.name
+ val normalizedCollapsedPath = normalizeFileSpec(collapsedPath)
+ val key = if (storageClass == StateStorage::class.java) normalizedCollapsedPath else storageClass.name
storageLock.withLock {
var storage = storages.get(key)
if (storage == null) {
- storage = createStateStorage(storageClass, collapsedPath, roamingType, stateSplitter)
+ storage = createStateStorage(storageClass, normalizedCollapsedPath, roamingType, stateSplitter)
storages.put(key, storage)
}
return storage
@@ -197,7 +191,7 @@ open class StateStorageManagerImpl(private val rootTagName: String,
isUseVfsListener = ThreeState.fromBoolean(streamProvider == null || !streamProvider!!.enabled)
}
- val filePath = expandNormalizedPath(collapsedPath)
+ val filePath = expandMacros(collapsedPath)
@Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE")
if (stateSplitter != StateSplitter::class.java && stateSplitter != StateSplitterEx::class.java) {
val storage = MyDirectoryStorage(this, File(filePath), ReflectionUtil.newInstance(stateSplitter))
@@ -282,7 +276,7 @@ open class StateStorageManagerImpl(private val rootTagName: String,
try {
if (virtualFileTracker != null) {
storages.forEachEntry({ collapsedPath, storage ->
- virtualFileTracker.remove(expandNormalizedPath(collapsedPath))
+ virtualFileTracker.remove(expandMacros(collapsedPath))
true
})
}
@@ -295,7 +289,7 @@ open class StateStorageManagerImpl(private val rootTagName: String,
protected open fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? = pathMacroSubstitutor
- override final fun expandMacros(path: String): String {
+ override fun expandMacros(path: String): String {
// replacement can contains $ (php tests), so, this check must be performed before expand
val matcher = MACRO_PATTERN.matcher(path)
matcherLoop@
@@ -326,17 +320,17 @@ open class StateStorageManagerImpl(private val rootTagName: String,
throw IllegalArgumentException("Unknown macro $macro")
}
- override final fun collapseMacros(path: String): String {
+ fun collapseMacros(path: String): String {
var result = path
for ((key, value) in macros) {
result = StringUtil.replace(result, value, key)
}
- return result
+ return normalizeFileSpec(result)
}
override fun startExternalization() = StateStorageManagerExternalizationSession(this)
- class StateStorageManagerExternalizationSession(protected val storageManager: StateStorageManagerImpl) : StateStorageManager.ExternalizationSession {
+ private class StateStorageManagerExternalizationSession(private val storageManager: StateStorageManagerImpl) : StateStorageManager.ExternalizationSession {
private val sessions = LinkedHashMap()
override fun setState(storageSpecs: Array, component: Any, componentName: String, state: Any) {
diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt
index 6af9347b4ace..27ac1dbc5e2e 100644
--- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt
+++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt
@@ -67,7 +67,7 @@ internal class ApplicationStoreTest {
component.foo = "newValue"
componentStore.save(SmartList())
- assertThat(streamProvider.data.get(RoamingType.DEFAULT)!!.get("new.xml")).isEqualTo("\n" + " \n" + "")
+ assertThat(streamProvider.data.get(RoamingType.DEFAULT)!!.get("new.xml")).isEqualTo("\n \n")
}
@Test fun `load from stream provider`() {
@@ -83,7 +83,7 @@ internal class ApplicationStoreTest {
componentStore.initComponent(component, false)
assertThat(component.foo).isEqualTo("newValue")
- assertThat(Paths.get(componentStore.storageManager.expandNormalizedPath(fileSpec))).isRegularFile()
+ assertThat(Paths.get(componentStore.storageManager.expandMacros(fileSpec))).isRegularFile()
}
@Test fun `remove deprecated storage on write`() {
diff --git a/platform/configuration-store-impl/testSrc/StorageManagerTest.kt b/platform/configuration-store-impl/testSrc/StorageManagerTest.kt
index 76d47dac3373..7f5a9ae3bc92 100644
--- a/platform/configuration-store-impl/testSrc/StorageManagerTest.kt
+++ b/platform/configuration-store-impl/testSrc/StorageManagerTest.kt
@@ -27,7 +27,7 @@ import org.junit.ClassRule
import org.junit.Test
import kotlin.properties.Delegates
-class StorageManagerTest {
+internal class StorageManagerTest {
companion object {
val MACRO = "\$MACRO1$"
@@ -36,27 +36,27 @@ class StorageManagerTest {
private var storageManager: StateStorageManagerImpl by Delegates.notNull()
- public @Before fun setUp() {
+ @Before fun setUp() {
storageManager = StateStorageManagerImpl("foo")
storageManager.addMacro(MACRO, "/temp/m1")
}
- public @Test fun createFileStateStorageMacroSubstituted() {
+ @Test fun createFileStateStorageMacroSubstituted() {
assertThat(storageManager.getOrCreateStorage("$MACRO/test.xml")).isNotNull()
}
- public @Test fun `collapse macro`() {
+ @Test fun `collapse macro`() {
assertThat(storageManager.collapseMacros("/temp/m1/foo")).isEqualTo("$MACRO/foo")
- assertThat(storageManager.collapseMacros("\\temp\\m1\\foo")).isEqualTo("\\temp\\m1\\foo")
+ assertThat(storageManager.collapseMacros("\\temp\\m1\\foo")).isEqualTo("/temp/m1/foo")
}
- public @Test fun `add system-dependent macro`() {
+ @Test fun `add system-dependent macro`() {
val key = "\$INVALID$"
val expansion = "\\temp"
assertThatThrownBy({storageManager.addMacro(key, expansion) }).hasMessage("Macro $key set to system-dependent expansion $expansion")
}
- public @Test fun `create storage assertion thrown when unknown macro`() {
+ @Test fun `create storage assertion thrown when unknown macro`() {
try {
storageManager.getOrCreateStorage("\$UNKNOWN_MACRO$/test.xml")
TestCase.fail("Exception expected")
@@ -66,7 +66,7 @@ class StorageManagerTest {
}
}
- public @Test fun `create file storage macro substituted when expansion has$`() {
+ @Test fun `create file storage macro substituted when expansion has$`() {
storageManager.addMacro("\$DOLLAR_MACRO$", "/temp/d$")
assertThat(storageManager.getOrCreateStorage("\$DOLLAR_MACRO$/test.xml")).isNotNull()
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java
index 811ca228a6d2..f657aa4c95af 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java
@@ -161,7 +161,14 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
}
@NotNull
- public static MultiMap getExportableComponentsMap(final boolean onlyExisting, final boolean computePresentableNames) {
+ public static MultiMap getExportableComponentsMap(boolean onlyExisting, boolean computePresentableNames) {
+ ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication();
+ StateStorageManager storageManager = ComponentsPackage.getStateStore(application).getStateStorageManager();
+ return getExportableComponentsMap(onlyExisting, computePresentableNames, storageManager);
+ }
+
+ @NotNull
+ public static MultiMap getExportableComponentsMap(final boolean onlyExisting, final boolean computePresentableNames, final @NotNull StateStorageManager storageManager) {
@SuppressWarnings("deprecation")
List components1 = ComponentsPackage.getComponents(ApplicationManager.getApplication(), ExportableApplicationComponent.class);
List components2 = ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class);
@@ -180,9 +187,7 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
}
}
- ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication();
- final StateStorageManager storageManager = ComponentsPackage.getStateStore(application).getStateStorageManager();
- ServiceManagerImpl.processAllImplementationClasses(application, new PairProcessor, PluginDescriptor>() {
+ ServiceManagerImpl.processAllImplementationClasses((ApplicationImpl)ApplicationManager.getApplication(), new PairProcessor, PluginDescriptor>() {
@Override
public boolean process(@NotNull Class> aClass, @Nullable PluginDescriptor pluginDescriptor) {
State stateAnnotation = StoreUtil.getStateSpec(aClass);
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
index 03162b4f8005..82b1731b0932 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
@@ -48,12 +48,6 @@ public interface StateStorageManager {
@NotNull
String expandMacros(@NotNull String path);
- @NotNull
- /**
- * @param path System-independent path.
- */
- String collapseMacros(@NotNull String path);
-
interface ExternalizationSession {
void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state);
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
index 1a44e6525e4a..5c1e9ed3d08d 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
@@ -169,9 +169,9 @@
serviceImplementation="com.intellij.execution.process.impl.OSProcessManagerImpl"/>
+ serviceImplementation="com.intellij.configurationStore.SchemeManagerFactoryBase$ApplicationSchemeManagerFactory"/>
+ serviceImplementation="com.intellij.configurationStore.SchemeManagerFactoryBase$ProjectSchemeManagerFactory"/>
()
- private var sanitizedName: String? = null
+ private var sanitizedName: String by Delegates.notNull()
override fun apply(base: Statement, description: Description): Statement {
- sanitizedName = FileUtil.sanitizeFileName(description.getMethodName(), false)
+ sanitizedName = FileUtil.sanitizeFileName(description.methodName, false)
return super.apply(base, description)
}
@@ -61,7 +61,7 @@ public class TemporaryDirectory : ExternalResource() {
}
private fun generatePath(suffix: String?): Path {
- var fileName = sanitizedName!!
+ var fileName = sanitizedName
if (suffix != null) {
fileName += "_$suffix"
}
@@ -93,65 +93,4 @@ public fun generateTemporaryPath(fileName: String?): Path {
throw IOException("Cannot generate unique random path")
}
return path
-}
-
-public fun Path.exists(): Boolean = Files.exists(this)
-
-public fun Path.createDirectories(): Path = Files.createDirectories(this)
-
-public fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree(this, object : SimpleFileVisitor() {
- override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
- Files.delete(file)
- return FileVisitResult.CONTINUE
- }
-
- override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {
- Files.delete(dir)
- return FileVisitResult.CONTINUE
- }
-}) else this
-
-public fun Path.getLastModifiedTime(): FileTime? = Files.getLastModifiedTime(this)
-
-public val Path.systemIndependentPath: String
- get() = toString().replace(File.separatorChar, '/')
-
-public val Path.parentSystemIndependentPath: String
- get() = getParent()!!.toString().replace(File.separatorChar, '/')
-
-public fun Path.readText(): String = Files.readAllBytes(this).toString(Charsets.UTF_8)
-
-public fun VirtualFile.writeChild(relativePath: String, data: String): VirtualFile = VfsTestUtil.createFile(this, relativePath, data)
-
-public fun Path.writeChild(relativePath: String, data: String): Path = writeChild(relativePath, data.toByteArray())
-
-public fun Path.writeChild(relativePath: String, data: ByteArray): Path {
- val path = resolve(relativePath)
- path.getParent().createDirectories()
- return Files.write(path, data)
-}
-
-public fun Path.isDirectory(): Boolean = Files.isDirectory(this)
-
-public fun Path.isFile(): Boolean = Files.isRegularFile(this)
-
-/**
- * Opposite to ugly Java, parent directories will be created
- */
-public fun Path.createFile() {
- getParent()?.createDirectories()
- Files.createFile(this)
-}
-
-public fun Path.refreshVfs() {
- LocalFileSystem.getInstance()?.let { fs ->
- // If a temp directory is reused from some previous test run, there might be cached children in its VFS. Ensure they're removed.
- val virtualFile = fs.findFileByPath(systemIndependentPath)
- if (virtualFile != null) {
- VfsUtil.markDirtyAndRefresh(false, true, true, virtualFile)
- }
- }
-}
-
-val VirtualFile.path: String
- get() = getPath()
+}
\ No newline at end of file
diff --git a/platform/testFramework/test-framework-java8/fsBuilder.kt b/platform/testFramework/test-framework-java8/fsBuilder.kt
new file mode 100644
index 000000000000..ea32d71474af
--- /dev/null
+++ b/platform/testFramework/test-framework-java8/fsBuilder.kt
@@ -0,0 +1,10 @@
+package com.intellij.testFramework
+
+import java.nio.file.FileSystem
+
+fun FileSystem.file(path: String, data: ByteArray): FileSystem {
+ getPath(path).write(data)
+ return this
+}
+
+fun FileSystem.file(path: String, data: String) = file(path, data.toByteArray())
\ No newline at end of file
diff --git a/platform/testFramework/test-framework-java8/path.kt b/platform/testFramework/test-framework-java8/path.kt
new file mode 100644
index 000000000000..c7939e370422
--- /dev/null
+++ b/platform/testFramework/test-framework-java8/path.kt
@@ -0,0 +1,72 @@
+package com.intellij.testFramework
+
+import com.intellij.openapi.vfs.LocalFileSystem
+import com.intellij.openapi.vfs.VfsUtil
+import com.intellij.openapi.vfs.VirtualFile
+import java.io.File
+import java.io.IOException
+import java.nio.file.FileVisitResult
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.SimpleFileVisitor
+import java.nio.file.attribute.BasicFileAttributes
+import java.nio.file.attribute.FileTime
+
+fun Path.exists(): Boolean = Files.exists(this)
+
+fun Path.createDirectories(): Path = Files.createDirectories(this)
+
+fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree(this, object : SimpleFileVisitor() {
+ override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
+ Files.delete(file)
+ return FileVisitResult.CONTINUE
+ }
+
+ override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {
+ Files.delete(dir)
+ return FileVisitResult.CONTINUE
+ }
+}) else this
+
+fun Path.getLastModifiedTime(): FileTime? = Files.getLastModifiedTime(this)
+
+val Path.systemIndependentPath: String
+ get() = toString().replace(File.separatorChar, '/')
+
+val Path.parentSystemIndependentPath: String
+ get() = parent!!.toString().replace(File.separatorChar, '/')
+
+fun Path.readText() = Files.readAllBytes(this).toString(Charsets.UTF_8)
+
+fun VirtualFile.writeChild(relativePath: String, data: String) = VfsTestUtil.createFile(this, relativePath, data)
+
+fun Path.writeChild(relativePath: String, data: ByteArray) = resolve(relativePath).write(data)
+
+fun Path.writeChild(relativePath: String, data: String) = writeChild(relativePath, data.toByteArray())
+
+fun Path.write(data: ByteArray): Path {
+ parent?.createDirectories()
+ return Files.write(this, data)
+}
+
+fun Path.isDirectory() = Files.isDirectory(this)
+
+fun Path.isFile() = Files.isRegularFile(this)
+
+/**
+ * Opposite to Java, parent directories will be created
+ */
+fun Path.createFile() {
+ parent?.createDirectories()
+ Files.createFile(this)
+}
+
+fun Path.refreshVfs() {
+ LocalFileSystem.getInstance()?.let { fs ->
+ // If a temp directory is reused from some previous test run, there might be cached children in its VFS. Ensure they're removed.
+ val virtualFile = fs.findFileByPath(systemIndependentPath)
+ if (virtualFile != null) {
+ VfsUtil.markDirtyAndRefresh(false, true, true, virtualFile)
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7-sources.jar b/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7-sources.jar
new file mode 100644
index 000000000000..3208f4cc636f
Binary files /dev/null and b/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7-sources.jar differ
diff --git a/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7.jar b/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7.jar
new file mode 100644
index 000000000000..f65126e0440c
Binary files /dev/null and b/plugins/settings-repository/lib/dev/memoryfilesystem-0.6.7.jar differ
diff --git a/plugins/settings-repository/settings-repository-tests.iml b/plugins/settings-repository/settings-repository-tests.iml
index 093c3f20dc5b..50acc4cea1bb 100644
--- a/plugins/settings-repository/settings-repository-tests.iml
+++ b/plugins/settings-repository/settings-repository-tests.iml
@@ -23,5 +23,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/settings-repository/src/autoSync.kt b/plugins/settings-repository/src/autoSync.kt
index 808d13c5c46c..ddda5e05e34b 100644
--- a/plugins/settings-repository/src/autoSync.kt
+++ b/plugins/settings-repository/src/autoSync.kt
@@ -34,7 +34,7 @@ import com.intellij.openapi.vcs.VcsNotifier
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier
import java.util.concurrent.Future
-class AutoSyncManager(private val icsManager: IcsManager) {
+internal class AutoSyncManager(private val icsManager: IcsManager) {
private @Volatile var autoSyncFuture: Future<*>? = null
fun waitAutoSync(indicator: ProgressIndicator) {
diff --git a/plugins/settings-repository/src/copyAppSettingsToRepository.kt b/plugins/settings-repository/src/copyAppSettingsToRepository.kt
index fe220a228ef1..d638b61f4303 100644
--- a/plugins/settings-repository/src/copyAppSettingsToRepository.kt
+++ b/plugins/settings-repository/src/copyAppSettingsToRepository.kt
@@ -15,6 +15,7 @@
*/
package org.jetbrains.settingsRepository
+import com.intellij.configurationStore.ROOT_CONFIG
import com.intellij.configurationStore.StateStorageManagerImpl
import com.intellij.ide.actions.ExportSettingsAction
import com.intellij.openapi.application.ApplicationManager
@@ -23,14 +24,14 @@ import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtilRt
import java.io.File
-fun copyLocalConfig() {
- val storageManager = ApplicationManager.getApplication()!!.stateStore.stateStorageManager as StateStorageManagerImpl
+fun copyLocalConfig(storageManager: StateStorageManagerImpl = ApplicationManager.getApplication()!!.stateStore.stateStorageManager as StateStorageManagerImpl) {
val streamProvider = storageManager.streamProvider!! as IcsManager.IcsStreamProvider
- val fileToComponents = ExportSettingsAction.getExportableComponentsMap(true, false)
+ val fileToComponents = ExportSettingsAction.getExportableComponentsMap(true, false, storageManager)
for (file in fileToComponents.keySet()) {
val absolutePath = FileUtilRt.toSystemIndependentName(file.absolutePath)
var fileSpec = storageManager.collapseMacros(absolutePath)
+ LOG.assertTrue(!fileSpec.contains(ROOT_CONFIG))
if (fileSpec.equals(absolutePath)) {
// we have not experienced such problem yet, but we are just aware
val canonicalPath = FileUtilRt.toSystemIndependentName(file.canonicalPath)
diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt
index a7dfedd96e74..4da0728f698e 100644
--- a/plugins/settings-repository/src/sync.kt
+++ b/plugins/settings-repository/src/sync.kt
@@ -83,13 +83,19 @@ class SyncManager(private val icsManager: IcsManager, private val autoSyncManage
when (syncType) {
SyncType.MERGE -> {
updateResult = repositoryManager.pull(indicator)
+ var doPush = true
if (localRepositoryInitializer != null) {
// must be performed only after initial pull, so, local changes will be relative to remote files
localRepositoryInitializer()
- repositoryManager.commit(indicator)
- updateResult = updateResult.concat(repositoryManager.pull(indicator))
+ if (!repositoryManager.commit(indicator, syncType) || repositoryManager.getAheadCommitsCount() == 0) {
+ // avoid error during findRemoteRefUpdatesFor on push - if localRepositoryInitializer specified and nothing to commit (failed or just no files to commit (empty local configuration - no files)),
+ // so, nothing to push
+ doPush = false
+ }
+ }
+ if (doPush) {
+ repositoryManager.push(indicator)
}
- repositoryManager.push(indicator)
}
SyncType.OVERWRITE_LOCAL -> {
// we don't push - probably, repository will be modified/removed (user can do something, like undo) before any other next push activities (so, we don't want to disturb remote)
diff --git a/plugins/settings-repository/testSrc/GitTest.kt b/plugins/settings-repository/testSrc/GitTest.kt
index 707f32ec1acd..49d07892b0ba 100644
--- a/plugins/settings-repository/testSrc/GitTest.kt
+++ b/plugins/settings-repository/testSrc/GitTest.kt
@@ -15,13 +15,15 @@
*/
package org.jetbrains.settingsRepository.test
+import com.intellij.configurationStore.ApplicationStoreImpl
import com.intellij.configurationStore.write
-import com.intellij.mock.MockVirtualFileSystem
+import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vcs.merge.MergeSession
import com.intellij.openapi.vfs.CharsetToolkit
import com.intellij.testFramework.ProjectRule
-import com.intellij.testFramework.path
+import com.intellij.testFramework.file
+import com.intellij.testFramework.writeChild
import com.intellij.util.PathUtilRt
import org.assertj.core.api.Assertions.assertThat
import org.eclipse.jgit.api.Git
@@ -31,6 +33,7 @@ import org.jetbrains.jgit.dirCache.writePath
import org.jetbrains.settingsRepository.CannotResolveConflictInTestMode
import org.jetbrains.settingsRepository.SyncType
import org.jetbrains.settingsRepository.conflictResolver
+import org.jetbrains.settingsRepository.copyLocalConfig
import org.jetbrains.settingsRepository.git.GitRepositoryManager
import org.jetbrains.settingsRepository.git.commit
import org.jetbrains.settingsRepository.git.computeIndexDiff
@@ -39,16 +42,17 @@ import org.junit.ClassRule
import org.junit.Test
import java.io.File
import java.nio.charset.StandardCharsets
-import java.util.Arrays
+import java.nio.file.FileSystem
+import java.util.*
import kotlin.properties.Delegates
// kotlin bug, cannot be val (.NoSuchMethodError: org.jetbrains.settingsRepository.SettingsRepositoryPackage.getMARKER_ACCEPT_MY()[B)
-object AM {
+internal object AM {
val MARKER_ACCEPT_MY: ByteArray = "__accept my__".toByteArray()
val MARKER_ACCEPT_THEIRS: ByteArray = "__accept theirs__".toByteArray()
}
-class GitTest : IcsTestCase() {
+internal class GitTest : IcsTestCase() {
companion object {
@ClassRule val projectRule = ProjectRule()
}
@@ -175,7 +179,7 @@ class GitTest : IcsTestCase() {
repositoryManager.commit()
repositoryManager.pull()
assertThat(FileUtil.loadFile(File(repository.getWorkTree(), file.name))).isEqualTo(String(file.data, CharsetToolkit.UTF8_CHARSET))
- compareFiles(repository.workTree, remoteRepository.workTree, null, PathUtilRt.getFileName(file.name))
+ compareFiles(repository.workTree, remoteRepository.workTree, PathUtilRt.getFileName(file.name))
}
private fun createLocalRepository(remoteBranchName: String? = null) {
@@ -188,15 +192,20 @@ class GitTest : IcsTestCase() {
return addAndCommit("local.xml")
}
- private fun MockVirtualFileSystem.compare() {
- compareFiles(repository.workTree, remoteRepository.workTree, root)
+ private fun FileSystem.compare(): FileSystem {
+ val root = getPath("/")!!
+ compareFiles(root, repository.workTree)
+ compareFiles(root, remoteRepository.workTree)
+ return this
}
// never was merged. we reset using "merge with strategy "theirs", so, we must test - what's happen if it is not first merge? - see next test
@Test fun resetToTheirsIfFirstMerge() {
createLocalRepositoryAndCommit(null)
sync(SyncType.OVERWRITE_LOCAL)
- fs().file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT).compare()
+ fs
+ .file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT)
+ .compare()
}
@Test fun resetToTheirsISecondMergeIsNull() {
@@ -205,8 +214,6 @@ class GitTest : IcsTestCase() {
restoreRemoteAfterPush()
- val fs = MockVirtualFileSystem()
-
fun testRemote() {
fs
.file("local.xml", """""")
@@ -232,7 +239,7 @@ class GitTest : IcsTestCase() {
createLocalRepositoryAndCommit()
sync(SyncType.OVERWRITE_REMOTE)
restoreRemoteAfterPush()
- fs().file("local.xml", """""").compare()
+ fs.file("local.xml", """""").compare()
}
@Test fun `reset to my, second merge is null`() {
@@ -241,8 +248,10 @@ class GitTest : IcsTestCase() {
restoreRemoteAfterPush()
- val fs = fs().file("local.xml", """""").file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT)
- fs.compare()
+ val fs = fs
+ .file("local.xml", """""")
+ .file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT)
+ .compare()
val localToFilePath = "_mac/local2.xml"
addAndCommit(localToFilePath)
@@ -269,7 +278,7 @@ class GitTest : IcsTestCase() {
sync(SyncType.MERGE)
restoreRemoteAfterPush()
- fs().file(SAMPLE_FILE_NAME, data.toString(StandardCharsets.UTF_8)).compare()
+ fs.file(SAMPLE_FILE_NAME, data.toString(StandardCharsets.UTF_8)).compare()
}
@Test fun `merge - theirs file deleted, my modified, accept theirs`() {
@@ -286,7 +295,7 @@ class GitTest : IcsTestCase() {
sync(SyncType.MERGE)
- fs().compare()
+ fs.compare()
}
@Test fun `merge - my file deleted, theirs modified, accept my`() {
@@ -294,16 +303,16 @@ class GitTest : IcsTestCase() {
sync(SyncType.MERGE)
- provider.delete("remote.xml")
+ provider.delete(SAMPLE_FILE_NAME)
repositoryManager.commit()
- remoteRepository.writePath("remote.xml", AM.MARKER_ACCEPT_THEIRS)
+ remoteRepository.writePath(SAMPLE_FILE_NAME, AM.MARKER_ACCEPT_THEIRS)
remoteRepository.commit("")
sync(SyncType.MERGE)
restoreRemoteAfterPush()
- fs().compare()
+ fs.compare()
}
@Test fun `commit if unmerged`() {
@@ -327,7 +336,7 @@ class GitTest : IcsTestCase() {
}
sync(SyncType.MERGE)
- fs().file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT).compare()
+ fs.file(SAMPLE_FILE_NAME, SAMPLE_FILE_CONTENT).compare()
}
// remote is uninitialized (empty - initial commit is not done)
@@ -368,6 +377,51 @@ class GitTest : IcsTestCase() {
}
}
+ @Test fun `initial copy to repository: no local files`() {
+ // check error during findRemoteRefUpdatesFor (no master ref)
+ testInitialCopy(false)
+ }
+
+ @Test fun `initial copy to repository: some local files`() {
+ // check error during findRemoteRefUpdatesFor (no master ref)
+ testInitialCopy(true)
+ }
+
+ private fun testInitialCopy(addLocalFiles: Boolean) {
+ createRemoteRepository(initialCommit = false)
+
+ repositoryManager.createRepositoryIfNeed()
+ repositoryManager.setUpstream(remoteRepository.getWorkTree().absolutePath)
+
+ val store = ApplicationStoreImpl(ApplicationManager.getApplication()!!)
+ val localConfigPath = tempDirManager.newPath("local_config")
+
+ val lafData = """
+
+
+
+ """
+ if (addLocalFiles) {
+ localConfigPath.writeChild("options/ui.lnf.xml", lafData)
+ }
+
+ store.setPath(localConfigPath.toString())
+ store.storageManager.streamProvider = provider
+
+ icsManager.sync(SyncType.MERGE, projectRule.project, { copyLocalConfig(store.storageManager) })
+
+ if (addLocalFiles) {
+ assertThat(localConfigPath).isDirectory()
+ fs
+ .file("ui.lnf.xml", lafData)
+ restoreRemoteAfterPush()
+ }
+ else {
+ assertThat(localConfigPath).doesNotExist()
+ }
+ fs.compare()
+ }
+
private fun createRemoteRepository(branchName: String? = null, initialCommit: Boolean = true) {
val repository = tempDirManager.createRepository("upstream")
if (initialCommit) {
@@ -396,7 +450,6 @@ class GitTest : IcsTestCase() {
sync(syncType)
- val fs = MockVirtualFileSystem()
if (syncType != SyncType.OVERWRITE_LOCAL) {
fs.file(path, data)
}
diff --git a/plugins/settings-repository/testSrc/IcsTestCase.kt b/plugins/settings-repository/testSrc/IcsTestCase.kt
index c07ee3a10825..44ced1f59e2b 100644
--- a/plugins/settings-repository/testSrc/IcsTestCase.kt
+++ b/plugins/settings-repository/testSrc/IcsTestCase.kt
@@ -23,8 +23,8 @@ import org.jetbrains.jgit.dirCache.edit
import org.jetbrains.settingsRepository.IcsManager
import org.jetbrains.settingsRepository.git
import org.junit.Rule
+import java.nio.file.FileSystem
import java.nio.file.Path
-import kotlin.properties.Delegates
fun Repository.add(path: String, data: String) = add(path, data.toByteArray())
@@ -46,6 +46,12 @@ abstract class IcsTestCase {
val tempDirManager = TemporaryDirectory()
@Rule fun getTemporaryFolder() = tempDirManager
+ private val fsRule = InMemoryFsRule()
+ @Rule fun _inMemoryFsRule() = fsRule
+
+ val fs: FileSystem
+ get() = fsRule.fs
+
val icsManager by lazy(LazyThreadSafetyMode.NONE) {
val icsManager = IcsManager(tempDirManager.newDirectory())
icsManager.repositoryManager.createRepositoryIfNeed()
diff --git a/plugins/settings-repository/testSrc/RespositoryHelper.kt b/plugins/settings-repository/testSrc/RespositoryHelper.kt
index 16bf2d86bf01..4ef156277328 100644
--- a/plugins/settings-repository/testSrc/RespositoryHelper.kt
+++ b/plugins/settings-repository/testSrc/RespositoryHelper.kt
@@ -15,31 +15,58 @@
*/
package org.jetbrains.settingsRepository.test
-import com.intellij.mock.MockVirtualFileSystem
-import com.intellij.openapi.vfs.VfsUtilCore
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.testFramework.LightVirtualFile
+import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder
import com.intellij.testFramework.isFile
import gnu.trove.THashSet
import org.assertj.core.api.Assertions.assertThat
import org.eclipse.jgit.lib.Constants
+import org.junit.rules.ExternalResource
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import java.net.URLEncoder
+import java.nio.file.FileSystem
import java.nio.file.Files
import java.nio.file.Path
+import kotlin.properties.Delegates
data class FileInfo(val name: String, val data: ByteArray)
-fun fs() = MockVirtualFileSystem()
+class InMemoryFsRule : ExternalResource() {
+ private var _fs: FileSystem? = null
+
+ private var sanitizedName: String by Delegates.notNull()
+
+ override fun apply(base: Statement, description: Description): Statement {
+ sanitizedName = URLEncoder.encode(description.methodName, Charsets.UTF_8.name())
+ return super.apply(base, description)
+ }
+
+ val fs: FileSystem
+ get() {
+ var r = _fs
+ if (r == null) {
+ r = MemoryFileSystemBuilder
+ .newLinux()
+ .setCurrentWorkingDirectory("/")
+ .build(sanitizedName)
+ _fs = r
+ }
+ return r!!
+ }
+
+ override fun after() {
+ _fs?.close()
+ _fs = null
+ }
+}
private fun getChildrenStream(path: Path, excludes: Array? = null) = Files.list(path)
.filter { !it.endsWith(Constants.DOT_GIT) && (excludes == null || !excludes.contains(it.fileName.toString())) }
.sorted()
-internal fun compareFiles(path1: Path, path2: Path, path3: VirtualFile? = null, vararg localExcludes: String) {
+fun compareFiles(path1: Path, path2: Path, vararg localExcludes: String) {
assertThat(path1).isDirectory()
assertThat(path2).isDirectory()
- if (path3 != null) {
- assertThat(path3.isDirectory).isTrue()
- }
val notFound = THashSet()
for (path in getChildrenStream(path1, localExcludes)) {
@@ -47,21 +74,15 @@ internal fun compareFiles(path1: Path, path2: Path, path3: VirtualFile? = null,
}
for (child2 in getChildrenStream(path2)) {
- val fileName = child2.fileName
- val child1 = path1.resolve(fileName)
- val child3 = path3?.findChild(fileName.toString())
+ val child1 = path1.resolve(child2.fileName.toString())
if (child1.isFile()) {
assertThat(child2).hasSameContentAs(child1)
- if (child3 != null) {
- assertThat(child3.isDirectory).isFalse()
- assertThat(child1).hasContent(if (child3 is LightVirtualFile) child3.content.toString() else VfsUtilCore.loadText(child3))
- }
}
else {
- compareFiles(child1, child2, child3, *localExcludes)
+ compareFiles(child1, child2, *localExcludes)
}
notFound.remove(child1)
}
- assertThat(notFound).isEmpty()
+ assertThat(notFound).`as`("Path '$path1' contains other files than '$path2'").isEmpty()
}
\ No newline at end of file