diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 270f84afd1dc..ff7687913212 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -724,7 +724,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } - public void readExternal(Element parentNode) { + public void readExternal(@NotNull Element parentNode) { myState = XmlSerializer.deserialize(parentNode, State.class); if (!myProject.isDefault()) { for (Element option : parentNode.getChildren("option")) { @@ -778,7 +778,6 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements LOG.error(e); } - myModuleProcessorProfiles.clear(); myProcessorsProfilesMap = null; diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index d277587f761e..c975881354e5 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 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 org.jetbrains.jps.model.serialization; import com.intellij.openapi.diagnostic.Logger; @@ -133,17 +119,35 @@ public class JpsProjectLoader extends JpsLoaderBase { loadComponents(dir, defaultConfigFile, serializer, myProject); } } + + Path externalConfigDir = resolveExternalProjectConfig("project"); + if (externalConfigDir != null) { + LOG.info("External project config dir is used: " + externalConfigDir); + } + + Element moduleData = JDomSerializationUtil.findComponent(loadRootElement(dir.resolve("modules.xml")), "ProjectModuleManager"); + Element externalModuleData = externalConfigDir == null ? null : loadRootElement(externalConfigDir.resolve("modules.xml")); + if (externalModuleData != null) { + String componentName = externalModuleData.getAttributeValue("name"); + LOG.assertTrue(componentName != null && componentName.startsWith("External")); + externalModuleData.setAttribute("name", componentName.substring("External".length())); + if (moduleData == null) { + moduleData = externalModuleData; + } + else { + JDOMUtil.deepMerge(moduleData, externalModuleData); + } + } + Path workspaceFile = dir.resolve("workspace.xml"); - loadModules(loadRootElement(dir.resolve("modules.xml")), projectSdkType, workspaceFile); + loadModules(moduleData, projectSdkType, workspaceFile); Runnable timingLog = TimingLog.startActivity("loading project libraries"); for (Path libraryFile : listXmlFiles(dir.resolve("libraries"))) { loadProjectLibraries(loadRootElement(libraryFile)); } - Path externalConfigDir = resolveExternalProjectConfig("project"); if (externalConfigDir != null) { - LOG.info("External project config dir is used: " + externalConfigDir); loadProjectLibraries(loadRootElement(externalConfigDir.resolve("libraries.xml"))); } @@ -207,7 +211,7 @@ public class JpsProjectLoader extends JpsLoaderBase { } } } - loadModules(iprRoot, projectSdkType, iwsFile); + loadModules(JDomSerializationUtil.findComponent(iprRoot, "ProjectModuleManager"), projectSdkType, iwsFile); loadProjectLibraries(JDomSerializationUtil.findComponent(iprRoot, "libraryTable")); loadArtifacts(JDomSerializationUtil.findComponent(iprRoot, "ArtifactManager")); if (hasRunConfigurationSerializers()) { @@ -239,10 +243,11 @@ public class JpsProjectLoader extends JpsLoaderBase { JpsLibraryTableSerializer.loadLibraries(libraryTableElement, myProject.getLibraryCollection()); } - private void loadModules(@Nullable Element root, final @Nullable JpsSdkType projectSdkType, Path workspaceFile) { + private void loadModules(@Nullable Element componentElement, final @Nullable JpsSdkType projectSdkType, @NotNull Path workspaceFile) { Runnable timingLog = TimingLog.startActivity("loading modules"); - Element componentRoot = JDomSerializationUtil.findComponent(root, "ProjectModuleManager"); - if (componentRoot == null) return; + if (componentElement == null) { + return; + } Set unloadedModules = new HashSet<>(); if (!myLoadUnloadedModules && Files.exists(workspaceFile)) { @@ -254,7 +259,7 @@ public class JpsProjectLoader extends JpsLoaderBase { final Set foundFiles = new THashSet<>(); final List moduleFiles = new ArrayList<>(); - for (Element moduleElement : JDOMUtil.getChildren(componentRoot.getChild("modules"), "module")) { + for (Element moduleElement : JDOMUtil.getChildren(componentElement.getChild("modules"), "module")) { final String path = moduleElement.getAttributeValue("filepath"); final Path file = Paths.get(path); if (foundFiles.add(file) && !unloadedModules.contains(getModuleName(file))) { diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt index 69b6a2cf0d71..2509f15e7528 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ExternalModuleListStorage.kt @@ -12,7 +12,7 @@ import com.intellij.openapi.roots.ProjectModelElement import com.intellij.openapi.roots.ProjectModelExternalSource import org.jdom.Element -@State(name = "ExternalModuleListStorage", storages = arrayOf(Storage("externalModules.xml"))) +@State(name = "ExternalModuleListStorage", storages = arrayOf(Storage("modules.xml"))) internal class ExternalModuleListStorage(private val project: Project) : PersistentStateComponent, ProjectModelElement { var loadedState: Set? = null private set diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index bcbd14d5596a..3c6399bbcbaf 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -1,18 +1,16 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package com.intellij.openapi.util; import com.intellij.openapi.diagnostic.Logger; @@ -54,7 +52,7 @@ import java.util.List; @SuppressWarnings({"HardCodedStringLiteral"}) public class JDOMUtil { private static final ThreadLocal> ourSaxBuilder = new ThreadLocal>(); - public static final Condition NOT_EMPTY_VALUE_CONDITION = new Condition() { + private static final Condition NOT_EMPTY_VALUE_CONDITION = new Condition() { @Override public boolean value(Attribute attribute) { return !StringUtil.isEmpty(attribute.getValue()); @@ -104,7 +102,7 @@ public class JDOMUtil { if (e1 == null || e2 == null) return false; return Comparing.equal(e1.getName(), e2.getName()) - && attListsEqual(e1.getAttributes(), e2.getAttributes(), ignoreEmptyAttrValues) + && isAttributesEqual(e1.getAttributes(), e2.getAttributes(), ignoreEmptyAttrValues) && contentListsEqual(e1.getContent(CONTENT_FILTER), e2.getContent(CONTENT_FILTER), ignoreEmptyAttrValues); } @@ -224,7 +222,7 @@ public class JDOMUtil { return c1 instanceof Element && c2 instanceof Element && areElementsEqual((Element)c1, (Element)c2, ignoreEmptyAttrValues); } - private static boolean attListsEqual(@NotNull List l1, @NotNull List l2, boolean ignoreEmptyAttrValues) { + private static boolean isAttributesEqual(@NotNull List l1, @NotNull List l2, boolean ignoreEmptyAttrValues) { if (ignoreEmptyAttrValues) { l1 = ContainerUtil.filter(l1, NOT_EMPTY_VALUE_CONDITION); l2 = ContainerUtil.filter(l2, NOT_EMPTY_VALUE_CONDITION); @@ -720,4 +718,27 @@ public class JDOMUtil { to.setAttribute(attribute); } } + + @NotNull + public static Element deepMerge(@NotNull Element to, @NotNull Element from) { + for (Iterator iterator = from.getChildren().iterator(); iterator.hasNext(); ) { + Element child = iterator.next(); + iterator.remove(); + + Element existingChild = to.getChild(child.getName()); + // if no children (e.g. ``), it means that element should be added as list item + if (existingChild == null || existingChild.getChildren().isEmpty() || !isAttributesEqual(existingChild.getAttributes(), child.getAttributes(), false)) { + to.addContent(child); + } + else { + deepMerge(existingChild, child); + } + } + for (Iterator iterator = from.getAttributes().iterator(); iterator.hasNext(); ) { + Attribute attribute = iterator.next(); + iterator.remove(); + to.setAttribute(attribute); + } + return to; + } }