[Workspace Model] Fix removing iml on removing custom root

GitOrigin-RevId: 71b945c947f3b0a043f988de8c815d6f62609527
This commit is contained in:
Alex Plate
2023-01-19 17:12:37 +02:00
committed by intellij-monorepo-bot
parent 2ace5d45cb
commit 697e0a1b03
22 changed files with 197 additions and 61 deletions

View File

@@ -595,75 +595,80 @@ internal open class ModuleImlFileEntitiesSerializer(internal val modulePath: Mod
return result
}
@Suppress("UNCHECKED_CAST")
override fun saveEntities(mainEntities: Collection<ModuleEntity>,
entities: Map<Class<out WorkspaceEntity>, List<WorkspaceEntity>>,
storage: EntityStorage,
writer: JpsFileContentWriter) {
@Suppress("UNCHECKED_CAST")
override fun saveEntities(mainEntities: Collection<ModuleEntity>,
entities: Map<Class<out WorkspaceEntity>, List<WorkspaceEntity>>,
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<ContentRootEntity> ?: emptyList()
val sourceRootEntities = (entities[SourceRootEntity::class.java] as? List<SourceRootEntity>)?.toMutableSet() ?: mutableSetOf()
val excludeRoots = (entities[ExcludeUrlEntity::class.java] as? List<ExcludeUrlEntity>)?.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<ContentRootEntity> ?: emptyList()
val sourceRootEntities = (entities[SourceRootEntity::class.java] as? List<SourceRootEntity>)?.toMutableSet() ?: mutableSetOf()
val excludeRoots = (entities[ExcludeUrlEntity::class.java] as? List<ExcludeUrlEntity>)?.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,

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" />
</project>

View File

@@ -0,0 +1,7 @@
<module version="4">
<component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="group" externalSystemModuleVersion="42.0" linkedProjectId="test" linkedProjectPath="$MODULE_DIR$" rootProjectPath="$MODULE_DIR$" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ExternalProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" />
</project>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,7 @@
<module version="4">
<component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="group" externalSystemModuleVersion="42.0" linkedProjectId="test" linkedProjectPath="$MODULE_DIR$" rootProjectPath="$MODULE_DIR$" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ExternalProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,5 @@
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$/myContentRoot" />
</component>
</module>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" />
</project>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,7 @@
<module version="4">
<component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="group" externalSystemModuleVersion="42.0" linkedProjectId="test" linkedProjectPath="$MODULE_DIR$" rootProjectPath="$MODULE_DIR$" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ExternalProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,5 @@
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$/myContentRoot" />
</component>
</module>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" />
</project>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,7 @@
<module version="4">
<component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="group" externalSystemModuleVersion="42.0" linkedProjectId="test" linkedProjectPath="$MODULE_DIR$" rootProjectPath="$MODULE_DIR$" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<project version="4">
<component name="ExternalProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,5 @@
<module version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/myContentRoot" />
</component>
</module>

View File

@@ -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 {