diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsGlobalLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsGlobalLoader.java index 85af891c2851..273135fce40d 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsGlobalLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsGlobalLoader.java @@ -24,7 +24,7 @@ public class JpsGlobalLoader extends JpsLoaderBase { private final JpsGlobalExtensionSerializer @NotNull [] myBundledSerializers; public JpsGlobalLoader(JpsMacroExpander macroExpander, JpsGlobal global, JpsGlobalExtensionSerializer @NotNull [] bundledSerializers) { - super(macroExpander); + super(macroExpander, null); myGlobal = global; myBundledSerializers = bundledSerializers; } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java index 27b401c15a2f..76b902fdc08a 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLoaderBase.java @@ -14,6 +14,7 @@ import org.jetbrains.jps.TimingLog; import org.jetbrains.jps.model.JpsElement; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; @@ -21,10 +22,12 @@ import java.nio.file.Path; public abstract class JpsLoaderBase { private static final Logger LOG = Logger.getInstance(JpsLoaderBase.class); private static final int MAX_ATTEMPTS = 5; + protected final @Nullable Path myExternalConfigurationDirectory; private final JpsMacroExpander myMacroExpander; - protected JpsLoaderBase(JpsMacroExpander macroExpander) { + protected JpsLoaderBase(JpsMacroExpander macroExpander, @Nullable Path externalConfigurationDirectory) { myMacroExpander = macroExpander; + myExternalConfigurationDirectory = externalConfigurationDirectory; } /** @@ -51,8 +54,36 @@ public abstract class JpsLoaderBase { timingLog.run(); } - protected @Nullable Element loadComponentData(@NotNull JpsElementExtensionSerializerBase serializer, @NotNull Path configFile) { - return JDomSerializationUtil.findComponent(loadRootElement(configFile), serializer.getComponentName()); + private @Nullable Element loadComponentData(@NotNull JpsElementExtensionSerializerBase serializer, @NotNull Path configFile) { + String componentName = serializer.getComponentName(); + Element component = JDomSerializationUtil.findComponent(loadRootElement(configFile), componentName); + if (!(serializer instanceof JpsProjectExtensionWithExternalDataSerializer) || myExternalConfigurationDirectory == null) { + return component; + } + JpsProjectExtensionWithExternalDataSerializer externalDataSerializer = (JpsProjectExtensionWithExternalDataSerializer)serializer; + Path externalConfigFile = myExternalConfigurationDirectory.resolve(externalDataSerializer.getExternalConfigFilePath()); + if (!Files.exists(externalConfigFile)) { + return component; + } + + Element externalData = null; + String externalComponentName = externalDataSerializer.getExternalComponentName(); + for (Element child : JDOMUtil.getChildren(loadRootElement(externalConfigFile))) { + // be ready to handle both original name and prefixed + if (child.getName().equals(externalComponentName) || JDomSerializationUtil.isComponent(externalComponentName, child) || + child.getName().equals(componentName) || JDomSerializationUtil.isComponent(componentName, child)) { + externalData = child; + break; + } + } + if (externalData == null) { + return component; + } + if (component == null) { + return externalData; + } + externalDataSerializer.mergeExternalData(component, externalData); + return component; } /** diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectExtensionWithExternalDataSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectExtensionWithExternalDataSerializer.java new file mode 100644 index 000000000000..21647c946d05 --- /dev/null +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectExtensionWithExternalDataSerializer.java @@ -0,0 +1,31 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.jps.model.serialization; + +import org.jdom.Element; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +@ApiStatus.Internal +public abstract class JpsProjectExtensionWithExternalDataSerializer extends JpsProjectExtensionSerializer { + private final String myExternalComponentName; + private final String myExternalConfigFilePath; + + protected JpsProjectExtensionWithExternalDataSerializer(@NotNull String configFileName, + @NotNull String componentName, + @NotNull String externalConfigFilePath, + @NotNull String externalComponentName) { + super(configFileName, componentName); + myExternalConfigFilePath = externalConfigFilePath; + myExternalComponentName = externalComponentName; + } + + public abstract void mergeExternalData(@NotNull Element internalComponent, @NotNull Element externalComponent); + + public String getExternalConfigFilePath() { + return myExternalConfigFilePath; + } + + public final @NotNull String getExternalComponentName() { + return myExternalComponentName; + } +} 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 a427ac3b1443..531074f8aa7d 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 @@ -44,8 +44,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import static org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL; - /** * Use {@link JpsSerializationManager} to load a project. */ @@ -73,7 +71,6 @@ public final class JpsProjectLoader extends JpsLoaderBase { private final Map myPathVariables; private final JpsPathMapper myPathMapper; private final boolean myLoadUnloadedModules; - private final @Nullable Path myExternalConfigurationDirectory; private JpsProjectLoader(JpsProject project, Map pathVariables, @@ -81,11 +78,10 @@ public final class JpsProjectLoader extends JpsLoaderBase { @NotNull Path baseDir, @Nullable Path externalConfigurationDirectory, boolean loadUnloadedModules) { - super(createProjectMacroExpander(pathVariables, baseDir)); + super(createProjectMacroExpander(pathVariables, baseDir), externalConfigurationDirectory); myProject = project; myPathVariables = pathVariables; myPathMapper = pathMapper; - myExternalConfigurationDirectory = externalConfigurationDirectory; myProject.getContainer().setChild(JpsProjectSerializationDataExtensionImpl.ROLE, new JpsProjectSerializationDataExtensionImpl(baseDir)); myLoadUnloadedModules = loadUnloadedModules; } @@ -158,36 +154,6 @@ public final class JpsProjectLoader extends JpsLoaderBase { return name != null ? name : JpsPathUtil.getDefaultProjectName(dir); } - @Override - protected @Nullable Element loadComponentData(@NotNull JpsElementExtensionSerializerBase serializer, @NotNull Path configFile) { - Path externalConfigDir = myExternalConfigurationDirectory != null ? myExternalConfigurationDirectory.resolve("project") : null; - Element data = super.loadComponentData(serializer, configFile); - String componentName = serializer.getComponentName(); - if (externalConfigDir == null || !(componentName.equals("CompilerConfiguration"))) { - return data; - } - - String prefixedComponentName = "External" + componentName; - Element externalData = null; - for (Element child : JDOMUtil.getChildren(loadRootElement(externalConfigDir.resolve(configFile.getFileName())))) { - // be ready to handle both original name and prefixed - if (child.getName().equals(prefixedComponentName) || JDomSerializationUtil.isComponent(prefixedComponentName, child) || - child.getName().equals(componentName) || JDomSerializationUtil.isComponent(componentName, child)) { - externalData = child; - break; - } - } - return deepMergeCompilerConfigurations(data, externalData); - } - - private static @Nullable Element deepMergeCompilerConfigurations(@Nullable Element data, @Nullable Element externalData) { - if (data == null) return externalData; - if (externalData == null) return data; - JDOMUtil.deepMerge(data, externalData); - JDOMUtil.reduceChildren(BYTECODE_TARGET_LEVEL, data); - return data; - } - private void loadFromDirectory(@NotNull Path dir, @NotNull Executor executor) { myProject.setName(getDirectoryBaseProjectName(dir)); Path defaultConfigFile = dir.resolve("misc.xml"); diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerConfigurationSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerConfigurationSerializer.java index b1c15cb4398d..bc67a03436e1 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerConfigurationSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerConfigurationSerializer.java @@ -10,11 +10,11 @@ import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes; import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration; -import org.jetbrains.jps.model.serialization.JpsProjectExtensionSerializer; +import org.jetbrains.jps.model.serialization.JpsProjectExtensionWithExternalDataSerializer; import java.util.List; -public final class JpsJavaCompilerConfigurationSerializer extends JpsProjectExtensionSerializer { +public final class JpsJavaCompilerConfigurationSerializer extends JpsProjectExtensionWithExternalDataSerializer { public static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile"; public static final String RESOURCE_EXTENSIONS = "resourceExtensions"; public static final String ANNOTATION_PROCESSING = "annotationProcessing"; @@ -32,7 +32,9 @@ public final class JpsJavaCompilerConfigurationSerializer extends JpsProjectExte List.of("!?*.java", "!?*.form", "!?*.class", "!?*.groovy", "!?*.scala", "!?*.flex", "!?*.kt", "!?*.clj", "!?*.aj"); public JpsJavaCompilerConfigurationSerializer() { - super("compiler.xml", "CompilerConfiguration"); + super("compiler.xml", "CompilerConfiguration", + "project/compiler.xml", + "ExternalCompilerConfiguration"); } @Override @@ -96,6 +98,12 @@ public final class JpsJavaCompilerConfigurationSerializer extends JpsProjectExte } } + @Override + public void mergeExternalData(@NotNull Element internalComponent, @NotNull Element externalComponent) { + JDOMUtil.deepMerge(internalComponent, externalComponent); + JDOMUtil.reduceChildren(BYTECODE_TARGET_LEVEL, internalComponent); + } + @Override public void loadExtensionWithDefaultSettings(@NotNull JpsProject project) { JpsJavaCompilerConfiguration configuration = JpsJavaExtensionService.getInstance().getCompilerConfiguration(project); diff --git a/platform/workspace/jps/src/com/intellij/platform/workspace/jps/bridge/impl/serialization/DirectJpsFileContentReader.kt b/platform/workspace/jps/src/com/intellij/platform/workspace/jps/bridge/impl/serialization/DirectJpsFileContentReader.kt index 7a225ea190a0..69ade87629bb 100644 --- a/platform/workspace/jps/src/com/intellij/platform/workspace/jps/bridge/impl/serialization/DirectJpsFileContentReader.kt +++ b/platform/workspace/jps/src/com/intellij/platform/workspace/jps/bridge/impl/serialization/DirectJpsFileContentReader.kt @@ -10,7 +10,7 @@ import org.jetbrains.jps.model.serialization.JpsMacroExpander import org.jetbrains.jps.util.JpsPathUtil import kotlin.io.path.Path -internal class DirectJpsFileContentReader(private val macroExpander: JpsMacroExpander) : JpsLoaderBase(macroExpander), JpsFileContentReader { +internal class DirectJpsFileContentReader(private val macroExpander: JpsMacroExpander) : JpsLoaderBase(macroExpander, null), JpsFileContentReader { override fun loadComponent(fileUrl: String, componentName: String, customModuleFilePath: String?): Element? { val rootElement = loadRootElement(Path(JpsPathUtil.urlToPath(fileUrl))) ?: return null return JDomSerializationUtil.findComponent(rootElement, componentName)