diff --git a/platform/workspaceModel/jps/src/com/intellij/workspaceModel/ide/impl/jps/serialization/ModuleImlFileEntitiesSerializer.kt b/platform/workspaceModel/jps/src/com/intellij/workspaceModel/ide/impl/jps/serialization/ModuleImlFileEntitiesSerializer.kt index 1a157d34fca8..005e2ccdd36a 100644 --- a/platform/workspaceModel/jps/src/com/intellij/workspaceModel/ide/impl/jps/serialization/ModuleImlFileEntitiesSerializer.kt +++ b/platform/workspaceModel/jps/src/com/intellij/workspaceModel/ide/impl/jps/serialization/ModuleImlFileEntitiesSerializer.kt @@ -595,75 +595,80 @@ internal open class ModuleImlFileEntitiesSerializer(internal val modulePath: Mod return result } -@Suppress("UNCHECKED_CAST") -override fun saveEntities(mainEntities: Collection, - entities: Map, List>, - storage: EntityStorage, - writer: JpsFileContentWriter) { + @Suppress("UNCHECKED_CAST") + override fun saveEntities(mainEntities: Collection, + entities: Map, List>, + storage: EntityStorage, + writer: JpsFileContentWriter) { val module = mainEntities.singleOrNull() if (module != null && acceptsSource(module.entitySource)) { saveModuleEntities(module, entities, storage, writer) } - else { - val targetComponent = if (Orphanage.use) ADDITIONAL_MODULE_ELEMENTS_COMPONENT_NAME else MODULE_ROOT_MANAGER_COMPONENT_NAME - if (ContentRootEntity::class.java in entities || SourceRootEntity::class.java in entities || ExcludeUrlEntity::class.java in entities) { - val contentEntities = entities[ContentRootEntity::class.java] as? List ?: emptyList() - val sourceRootEntities = (entities[SourceRootEntity::class.java] as? List)?.toMutableSet() ?: mutableSetOf() - val excludeRoots = (entities[ExcludeUrlEntity::class.java] as? List)?.filter { it.contentRoot != null }?.toMutableSet() - ?: mutableSetOf() - val rootElement = JDomSerializationUtil.createComponentElement(targetComponent) - if (contentEntities.isNotEmpty()) { - contentEntities.forEach { - it.sourceRoots.filter { sourceRootEntity -> acceptsSource(sourceRootEntity.entitySource) }.forEach { sourceRootEntity -> - sourceRootEntities.remove(sourceRootEntity) - } - it.excludedUrls.filter { exclude -> acceptsSource(exclude.entitySource) }.forEach { exclude -> - excludeRoots.remove(exclude) - } - } - saveContentEntities(contentEntities, rootElement) - writer.saveComponent(fileUrl.url, targetComponent, rootElement) - } - if (sourceRootEntities.isNotEmpty() || excludeRoots.isNotEmpty()) { - val excludes = excludeRoots.groupBy { it.contentRoot!!.url }.toMutableMap() - if (sourceRootEntities.isNotEmpty()) { - sourceRootEntities.groupBy { it.contentRoot } - .toSortedMap(compareBy { it.url.url }) - .forEach { (contentRoot, sourceRoots) -> - val contentRootTag = Element(CONTENT_TAG) - contentRootTag.setAttribute(URL_ATTRIBUTE, contentRoot.url.url) - if (Orphanage.use) { - contentRootTag.setAttribute(DUMB_ATTRIBUTE, true.toString()) - } - saveSourceRootEntities(sourceRoots, contentRootTag, contentRoot.getSourceRootsComparator()) - excludes[contentRoot.url]?.let { - saveExcludeUrls(contentRootTag, it) - excludes.remove(contentRoot.url) - } - rootElement.addContent(contentRootTag) - writer.saveComponent(fileUrl.url, targetComponent, rootElement) + else { + val targetComponent = if (Orphanage.use) ADDITIONAL_MODULE_ELEMENTS_COMPONENT_NAME else MODULE_ROOT_MANAGER_COMPONENT_NAME + if (ContentRootEntity::class.java in entities || SourceRootEntity::class.java in entities || ExcludeUrlEntity::class.java in entities) { + val contentEntities = entities[ContentRootEntity::class.java] as? List ?: emptyList() + val sourceRootEntities = (entities[SourceRootEntity::class.java] as? List)?.toMutableSet() ?: mutableSetOf() + val excludeRoots = (entities[ExcludeUrlEntity::class.java] as? List)?.filter { it.contentRoot != null }?.toMutableSet() + ?: mutableSetOf() + val rootElement = JDomSerializationUtil.createComponentElement(targetComponent) + if (contentEntities.isNotEmpty()) { + contentEntities.forEach { + it.sourceRoots.filter { sourceRootEntity -> acceptsSource(sourceRootEntity.entitySource) }.forEach { sourceRootEntity -> + sourceRootEntities.remove(sourceRootEntity) + } + it.excludedUrls.filter { exclude -> acceptsSource(exclude.entitySource) }.forEach { exclude -> + excludeRoots.remove(exclude) } - } - excludes.toSortedMap(compareBy { it.url }).forEach { (url, exclude) -> - val contentRootTag = Element(CONTENT_TAG) - contentRootTag.setAttribute(URL_ATTRIBUTE, url.url) - if (Orphanage.use) { - contentRootTag.setAttribute(DUMB_ATTRIBUTE, true.toString()) } - saveExcludeUrls(contentRootTag, exclude) - rootElement.addContent(contentRootTag) + saveContentEntities(contentEntities, rootElement) writer.saveComponent(fileUrl.url, targetComponent, rootElement) } - } + if (sourceRootEntities.isNotEmpty() || excludeRoots.isNotEmpty()) { + val excludes = excludeRoots.groupBy { it.contentRoot!!.url }.toMutableMap() + if (sourceRootEntities.isNotEmpty()) { + sourceRootEntities.groupBy { it.contentRoot } + .toSortedMap(compareBy { it.url.url }) + .forEach { (contentRoot, sourceRoots) -> + val contentRootTag = Element(CONTENT_TAG) + contentRootTag.setAttribute(URL_ATTRIBUTE, contentRoot.url.url) + if (Orphanage.use) { + contentRootTag.setAttribute(DUMB_ATTRIBUTE, true.toString()) + } + saveSourceRootEntities(sourceRoots, contentRootTag, contentRoot.getSourceRootsComparator()) + excludes[contentRoot.url]?.let { + saveExcludeUrls(contentRootTag, it) + excludes.remove(contentRoot.url) + } + rootElement.addContent(contentRootTag) + writer.saveComponent(fileUrl.url, targetComponent, rootElement) + } + } + excludes.toSortedMap(compareBy { it.url }).forEach { (url, exclude) -> + val contentRootTag = Element(CONTENT_TAG) + contentRootTag.setAttribute(URL_ATTRIBUTE, url.url) + if (Orphanage.use) { + contentRootTag.setAttribute(DUMB_ATTRIBUTE, true.toString()) + } + saveExcludeUrls(contentRootTag, exclude) + rootElement.addContent(contentRootTag) + writer.saveComponent(fileUrl.url, targetComponent, rootElement) + } + } - } - else { - writer.saveComponent(fileUrl.url, MODULE_ROOT_MANAGER_COMPONENT_NAME, null) - writer.saveComponent(fileUrl.url, DEPRECATED_MODULE_MANAGER_COMPONENT_NAME, null) - if (Orphanage.use) { - writer.saveComponent(fileUrl.url, ADDITIONAL_MODULE_ELEMENTS_COMPONENT_NAME, null) + if (Orphanage.use) { + // Component to save additional roots before introducing AdditionalModuleElements. + // It's not used for this function anymore and should be cleared + writer.saveComponent(fileUrl.url, MODULE_ROOT_MANAGER_COMPONENT_NAME, null) + } + } + else { + writer.saveComponent(fileUrl.url, MODULE_ROOT_MANAGER_COMPONENT_NAME, null) + writer.saveComponent(fileUrl.url, DEPRECATED_MODULE_MANAGER_COMPONENT_NAME, null) + if (Orphanage.use) { + writer.saveComponent(fileUrl.url, ADDITIONAL_MODULE_ELEMENTS_COMPONENT_NAME, null) + } } - } } createFacetSerializer().saveFacetEntities(module, entities, writer, this::acceptsSource) @@ -1029,6 +1034,7 @@ internal open class ModuleListSerializerImpl(override val fileUrl: String, writer.saveComponent(fileUrl, MODULE_ROOT_MANAGER_COMPONENT_NAME, null) writer.saveComponent(fileUrl, DEPRECATED_MODULE_MANAGER_COMPONENT_NAME, null) writer.saveComponent(fileUrl, TEST_MODULE_PROPERTIES_COMPONENT_NAME, null) + writer.saveComponent(fileUrl, ADDITIONAL_MODULE_ELEMENTS_COMPONENT_NAME, null) } private fun getModuleFileUrl(source: JpsFileEntitySource.FileInDirectory, diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/misc.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/misc.xml new file mode 100644 index 000000000000..8ddc2148d7dc --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/modules.xml new file mode 100644 index 000000000000..7c5c7c342a23 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/.idea/modules.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/modules/test.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/modules/test.xml new file mode 100644 index 000000000000..a2fd710158f0 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/modules/test.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/project/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/project/modules.xml new file mode 100644 index 000000000000..4559fe912c0c --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/cache/project/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/test.iml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/test.iml new file mode 100644 index 000000000000..7c5c7c342a23 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadAndRemoveAdditionalRootY/test.iml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/misc.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/misc.xml new file mode 100644 index 000000000000..8ddc2148d7dc --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/modules.xml new file mode 100644 index 000000000000..b402e967f73f --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/.idea/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml new file mode 100644 index 000000000000..a2fd710158f0 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml new file mode 100644 index 000000000000..4559fe912c0c --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/test.iml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/test.iml new file mode 100644 index 000000000000..f92789a4c813 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/after/loadIncorrectSavedAdditionalRoots/test.iml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/misc.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/misc.xml new file mode 100644 index 000000000000..8ddc2148d7dc --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/modules.xml new file mode 100644 index 000000000000..b402e967f73f --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/.idea/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/modules/test.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/modules/test.xml new file mode 100644 index 000000000000..a2fd710158f0 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/modules/test.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/project/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/project/modules.xml new file mode 100644 index 000000000000..4559fe912c0c --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/cache/project/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/test.iml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/test.iml new file mode 100644 index 000000000000..f92789a4c813 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadAndRemoveAdditionalRoot/test.iml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/misc.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/misc.xml new file mode 100644 index 000000000000..8ddc2148d7dc --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/modules.xml new file mode 100644 index 000000000000..b402e967f73f --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/.idea/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml new file mode 100644 index 000000000000..a2fd710158f0 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/modules/test.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml new file mode 100644 index 000000000000..4559fe912c0c --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/cache/project/modules.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/test.iml b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/test.iml new file mode 100644 index 000000000000..24844a0d3990 --- /dev/null +++ b/platform/workspaceModel/jps/tests/testData/serialization/splitModuleAndContentRoot/before/loadIncorrectSavedAdditionalRoots/test.iml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/impl/jps/serialization/JpsSplitModuleAndContentRootTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/impl/jps/serialization/JpsSplitModuleAndContentRootTest.kt index f94bfcd3cb59..6a812b41a9b7 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/impl/jps/serialization/JpsSplitModuleAndContentRootTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/impl/jps/serialization/JpsSplitModuleAndContentRootTest.kt @@ -33,6 +33,7 @@ class JpsSplitModuleAndContentRootTest { @Before fun setUp() { + Assume.assumeTrue(Orphanage.use) virtualFileManager = IdeVirtualFileUrlManagerImpl() } @@ -48,7 +49,6 @@ class JpsSplitModuleAndContentRootTest { @Test fun `add local content root via orphanage`() { - Assume.assumeTrue(Orphanage.use) checkSaveProjectAfterChange("after/addContentRootOrphanage", "after/addContentRootOrphanage", false) { builder, orphanage, configLocation -> assertTrue(builder.entities(ModuleEntity::class.java).toList().isEmpty()) assertTrue(orphanage.entities(ModuleEntity::class.java).single().contentRoots.single().entitySource !is OrphanageWorkerEntitySource) @@ -576,9 +576,25 @@ class JpsSplitModuleAndContentRootTest { } } + @Test + fun `load incorrect saved additional root`() { + checkSaveProjectAfterChange("before/loadIncorrectSavedAdditionalRoots", "after/loadIncorrectSavedAdditionalRoots", forceFilesRewrite = true) { builder, orphanage, configLocation -> + // Nothing + } + } + + @Test + fun `load and remove additional root`() { + checkSaveProjectAfterChange("before/loadAndRemoveAdditionalRoot", "after/loadAndRemoveAdditionalRootY", forceFilesRewrite = true) { builder, orphanage, configLocation -> + val toRemove = builder.entities(ModuleEntity::class.java).single().contentRoots.filter { it.entitySource !is JpsImportedEntitySource } + toRemove.forEach { builder.removeEntity(it) } + } + } + private fun checkSaveProjectAfterChange(dirBefore: String, dirAfter: String, externalStorage: Boolean = true, + forceFilesRewrite: Boolean = false, change: (MutableEntityStorage, MutableEntityStorage, JpsProjectConfigLocation) -> Unit) { val initialDir = PathManagerEx.findFileUnderCommunityHome( @@ -588,7 +604,7 @@ class JpsSplitModuleAndContentRootTest { checkSaveProjectAfterChange(initialDir, dirAfter, { builder, orphanage, _, location -> change(builder, orphanage, location) }, emptySet(), virtualFileManager, "serialization/splitModuleAndContentRoot", false, - externalStorageConfigurationManager) + externalStorageConfigurationManager, forceAllFilesRewrite = forceFilesRewrite) } companion object {