From 1cac02ef6f6d4749760564bf17b13e3a89dfdc39 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 18 Jun 2026 11:17:22 -0500 Subject: [PATCH] IVY-1656: write inherited dependencies first to preserve resolve order --- .../xml/XmlModuleDescriptorUpdater.java | 47 +++++++++++-------- .../org/apache/ivy/ant/ivy-extends-merged.xml | 12 ++--- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java index a6002542..0ce2c54a 100644 --- a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java +++ b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java @@ -292,12 +292,10 @@ public final class XmlModuleDescriptorUpdater { // according to ivy.xsd, all elements must occur before // the , or elements if (options.isMerge() - && ("exclude".equals(localName) || "override".equals(localName) || "conflict" - .equals(localName)) && "ivy-module/dependencies".equals(getContext())) { + && !mergedDependencies + && "ivy-module/dependencies".equals(getContext())) { ModuleDescriptor merged = options.getMergedDescriptor(); writeInheritedDependencies(merged); - out.println(); - out.print(getIndent()); } context.push(qName); @@ -991,7 +989,7 @@ public final class XmlModuleDescriptorUpdater { * just write the inherited items inline, with a comment indicating where they * came from. */ - private void writeInheritedItems(ModuleDescriptor merged, InheritableItem[] items, + private boolean writeInheritedItems(ModuleDescriptor merged, InheritableItem[] items, ItemPrinter printer, String itemName, boolean includeContainer) { // first categorize inherited items by their source module, so that // we can add some useful comments @@ -1014,6 +1012,10 @@ public final class XmlModuleDescriptorUpdater { newMapping.isEmpty() ? "" : " defaultconfmapping=\"" + newMapping + "\"", (confMappingOverride != null) ? " confmappingoverride=\"" + confMappingOverride + "\"" : "")); context.push(itemName); + if ("dependencies".equals(itemName)) { + out.println(); + out.print(getIndent()); + } justOpen = null; } @@ -1039,13 +1041,17 @@ public final class XmlModuleDescriptorUpdater { // restore the prior indent out.print(currentIndent); } + + return hasItems; } private void writeInheritanceComment(String itemDescription, Object parentInfo) { PrintWriter out = getWriter(); - out.println(); - out.println(getIndent() + ""); + if (!"dependencies".equals(itemDescription)) { + out.println(); + out.print(getIndent()); + } + out.println(""); } /** @@ -1113,8 +1119,11 @@ public final class XmlModuleDescriptorUpdater { private void writeInheritedDependencies(ModuleDescriptor merged) { if (!mergedDependencies) { mergedDependencies = true; - writeInheritedItems(merged, getDependencies(merged), DependencyPrinter.INSTANCE, - "dependencies", false); + InheritableItem[] items = getDependencies(merged); + if (writeInheritedItems(merged, items, DependencyPrinter.INSTANCE, "dependencies", false)) { + out.println(""); + out.print(getIndent()); + } } } @@ -1149,7 +1158,7 @@ public final class XmlModuleDescriptorUpdater { * a descriptor element name, for example "configurations" or "info" */ private void flushMergedElementsBefore(String moduleElement) { - if (options.isMerge() && context.size() == 1 && "ivy-module".equals(context.peek()) + if (options.isMerge() && "ivy-module".equals(getContext()) && !(mergedConfigurations && mergedDependencies)) { // calculate the position of the element in ivy-module @@ -1184,7 +1193,6 @@ public final class XmlModuleDescriptorUpdater { } public void endElement(String uri, String localName, String qName) throws SAXException { - String path = getContext(); if (options.isMerge()) { ModuleDescriptor merged = options.getMergedDescriptor(); @@ -1198,10 +1206,6 @@ public final class XmlModuleDescriptorUpdater { // write inherited configurations after all child configurations writeInheritedConfigurations(merged); break; - case "ivy-module/dependencies": - // write inherited dependencies after all child dependencies - writeInheritedDependencies(merged); - break; case "ivy-module": // write any remaining inherited data before we close the // descriptor. @@ -1284,9 +1288,14 @@ public final class XmlModuleDescriptorUpdater { justOpen = null; } - write(""); + if (options.isMerge() + && !mergedDependencies + && "ivy-module/dependencies".equals(getContext())) { + ModuleDescriptor merged = options.getMergedDescriptor(); + writeInheritedDependencies(merged); + } + + write(new StringBuilder("").toString()); if (inHeader) { write(LINE_SEPARATOR); diff --git a/test/java/org/apache/ivy/ant/ivy-extends-merged.xml b/test/java/org/apache/ivy/ant/ivy-extends-merged.xml index 00f32aa7..b3010b84 100644 --- a/test/java/org/apache/ivy/ant/ivy-extends-merged.xml +++ b/test/java/org/apache/ivy/ant/ivy-extends-merged.xml @@ -31,7 +31,7 @@ - + @@ -39,14 +39,14 @@ + + + + - - - - - +