From 75d2e2cd583cce5083f4934d9dad4f70f851251e Mon Sep 17 00:00:00 2001 From: Mikhail Mazurkevich Date: Tue, 16 Jun 2020 14:20:53 +0300 Subject: [PATCH] [workspace model] WM-T-57 Update facet xml config in the store before commit Prior to this fix, we don't have actual state of facet config in the store because it was serialized only once at `ModifiableFacetModelBridge#addFacet`. But for example in Kotlin plugin, facet configuration changed before the model commit at maven project import `MavenProjectImportHandler#configureFacet` and these changes weren't reflected in the store. GitOrigin-RevId: ec1227b91f87b440f4a58336598ab4feda4f9c57 --- .../com/intellij/facet/FacetManagerTest.java | 13 +++ .../facet/ModifiableFacetModelBridge.kt | 14 +++ .../ide/FacetModelBridgeTest.kt | 90 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 platform/workspaceModel/ide/tests/testSrc/com/intellij/workspaceModel/ide/FacetModelBridgeTest.kt diff --git a/java/idea-ui/testSrc/com/intellij/facet/FacetManagerTest.java b/java/idea-ui/testSrc/com/intellij/facet/FacetManagerTest.java index 060774cc54e4..f20c61588b69 100644 --- a/java/idea-ui/testSrc/com/intellij/facet/FacetManagerTest.java +++ b/java/idea-ui/testSrc/com/intellij/facet/FacetManagerTest.java @@ -104,6 +104,19 @@ public class FacetManagerTest extends FacetTestCase { commit(model); assertNull(getFacetManager().getFacetByType(MockFacetType.ID)); } + + public void testChangeFacetConfiguration() { + String configData = "data"; + ModifiableFacetModel model = getFacetManager().createModifiableModel(); + MockFacet mockFacet = new MockFacet(myModule, "mock"); + model.addFacet(mockFacet); + mockFacet.getConfiguration().setData(configData); + commit(model); + + MockFacet facetByType = getFacetManager().getFacetByType(MockFacetType.ID); + assertEquals(configData, facetByType.getConfiguration().getData()); + assertSame(mockFacet, facetByType); + } public void testAddRemoveFacetWithSubFacet() { assertNull(getFacetManager().getFacetByType(MockSubFacetType.ID)); diff --git a/platform/workspaceModel/ide/src/com/intellij/workspaceModel/ide/impl/legacyBridge/facet/ModifiableFacetModelBridge.kt b/platform/workspaceModel/ide/src/com/intellij/workspaceModel/ide/impl/legacyBridge/facet/ModifiableFacetModelBridge.kt index 8ae3e688fd4a..f51ea052189c 100644 --- a/platform/workspaceModel/ide/src/com/intellij/workspaceModel/ide/impl/legacyBridge/facet/ModifiableFacetModelBridge.kt +++ b/platform/workspaceModel/ide/src/com/intellij/workspaceModel/ide/impl/legacyBridge/facet/ModifiableFacetModelBridge.kt @@ -98,6 +98,7 @@ internal class ModifiableFacetModelBridge(private val initialStorage: WorkspaceE override fun commit() { val moduleDiff = moduleBridge.diff + updateFacetConfiguration() if (moduleDiff != null) { val res = moduleDiff.addDiff(diff) populateModel(res) @@ -110,6 +111,19 @@ internal class ModifiableFacetModelBridge(private val initialStorage: WorkspaceE } } + // In some cases configuration for newly added facets changes before the actual commit e.g. MavenProjectImportHandler#configureFacet. + private fun updateFacetConfiguration() { + entityToFacet.forEach { (facetEntity, facet) -> + if (initialStorage.resolve(facetEntity.persistentId()) != null) return@forEach + val newFacetConfiguration = FacetUtil.saveFacetConfiguration(facet)?.let { JDOMUtil.write(it) } + if (facetEntity.configurationXmlTag == newFacetConfiguration) return@forEach + val newEntity = diff.modifyEntity(ModifiableFacetEntity::class.java, facetEntity) { + this.configurationXmlTag = newFacetConfiguration + } + entityToFacet.inverse()[facet] = newEntity + } + } + private fun populateModel(replaceMap: Map) { val mapInNewStore: HashBiMap> = HashBiMap.create() entityToFacet.forEach { (key, value) -> mapInNewStore[replaceMap.getOrDefault(key, key) as FacetEntity] = value } diff --git a/platform/workspaceModel/ide/tests/testSrc/com/intellij/workspaceModel/ide/FacetModelBridgeTest.kt b/platform/workspaceModel/ide/tests/testSrc/com/intellij/workspaceModel/ide/FacetModelBridgeTest.kt new file mode 100644 index 000000000000..61299ac291a6 --- /dev/null +++ b/platform/workspaceModel/ide/tests/testSrc/com/intellij/workspaceModel/ide/FacetModelBridgeTest.kt @@ -0,0 +1,90 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.workspaceModel.ide + +import com.intellij.facet.FacetManager +import com.intellij.facet.FacetType +import com.intellij.facet.impl.FacetUtil +import com.intellij.facet.mock.MockFacet +import com.intellij.facet.mock.MockFacetType +import com.intellij.openapi.application.runWriteActionAndWait +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.module.EmptyModuleType +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.JDOMUtil +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.DisposableRule +import com.intellij.testFramework.TemporaryDirectory +import com.intellij.workspaceModel.ide.impl.legacyBridge.facet.ModifiableFacetModelBridge +import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge +import com.intellij.workspaceModel.storage.bridgeEntities.FacetEntity +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.io.File + +class FacetModelBridgeTest { + @Rule + @JvmField + var application = ApplicationRule() + + @Rule + @JvmField + var temporaryDirectoryRule = TemporaryDirectory() + + @Rule + @JvmField + var disposableRule = DisposableRule() + + private lateinit var project: Project + private lateinit var module: Module + + @Before + fun prepareProject() { + project = createEmptyTestProject(temporaryDirectoryRule, disposableRule) + module = createModule() + FacetType.EP_NAME.point.registerExtension(MockFacetType(), module) + } + + @Test + fun `test changed facet config saved correctly`() = WriteCommandAction.runWriteCommandAction(project) { + val facetData = "mock" + val facet = MockFacet(module, facetData) + getFacetManager().createModifiableModel().let { modifiableModel -> + modifiableModel.addFacet(facet) + Assert.assertTrue(facet.configuration.data.isEmpty()) + facet.configuration.data = facetData + modifiableModel.commit() + } + val facetConfigXml = FacetUtil.saveFacetConfiguration(facet)?.let { JDOMUtil.write(it) } + + val facetByType = getFacetManager().getFacetByType(MockFacetType.ID) + assertNotNull(facetByType) + assertEquals(facetData, facetByType!!.configuration.data) + + val entityStorage = WorkspaceModel.getInstance(project).entityStorage + val facetEntity = entityStorage.current.entities(FacetEntity::class.java).first() + assertEquals(facetConfigXml, facetEntity.configurationXmlTag) + + getFacetManager().createModifiableModel().let { modifiableModel -> + modifiableModel as ModifiableFacetModelBridge + assertEquals(facetConfigXml, modifiableModel.getEntity(facet)!!.configurationXmlTag) + } + } + + private fun createModule(): Module = runWriteActionAndWait { + ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = moduleModel.newModule(File(project.basePath, "test.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge + moduleModel.commit() + module + } + } + + private fun getFacetManager(): FacetManager { + return FacetManager.getInstance(module) + } +} \ No newline at end of file