diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index bc95c932e..a97852040 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -87,7 +87,7 @@ Export-Package: org.apache.ivy;version="2.0.0", org.apache.ivy.plugins.namespace;version="2.0.0", org.apache.ivy.plugins.pack;version="2.6.0", org.apache.ivy.plugins.parser;version="2.0.0", - org.apache.ivy.plugins.parser.m2;version="2.0.0", + org.apache.ivy.plugins.parser.m2;version="2.6.0", org.apache.ivy.plugins.parser.xml;version="2.0.0", org.apache.ivy.plugins.report;version="2.0.0", org.apache.ivy.plugins.repository;version="2.0.0", diff --git a/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorWriter.java b/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorWriter.java index 258fc7e2b..6145caa05 100644 --- a/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorWriter.java +++ b/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorWriter.java @@ -38,11 +38,15 @@ import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; +import org.apache.ivy.core.module.descriptor.DependencyDescriptorMediator; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; +import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; import org.apache.ivy.core.module.id.ModuleRevisionId; +import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.settings.IvyVariableContainer; +import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.parser.m2.PomWriterOptions.ConfigurationScopeMapping; import org.apache.ivy.plugins.parser.m2.PomWriterOptions.ExtraDependency; import org.apache.ivy.util.ConfigurationUtils; @@ -72,22 +76,18 @@ public static void write(ModuleDescriptor md, File output, PomWriterOptions opti throws IOException { LineNumberReader in; if (options.getTemplate() == null) { - in = new LineNumberReader(new InputStreamReader( - PomModuleDescriptorWriter.class.getResourceAsStream("pom.template"))); + in = new LineNumberReader(new InputStreamReader(PomModuleDescriptorWriter.class.getResourceAsStream("pom.template"))); } else { - in = new LineNumberReader(new InputStreamReader(new FileInputStream( - options.getTemplate()))); + in = new LineNumberReader(new InputStreamReader(new FileInputStream(options.getTemplate()))); } if (output.getParentFile() != null) { output.getParentFile().mkdirs(); } - PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), - StandardCharsets.UTF_8)); - try { + + try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), StandardCharsets.UTF_8))) { IvySettings settings = IvyContext.getContext().getSettings(); - IvyVariableContainer variables = new IvyVariableContainerWrapper( - settings.getVariableContainer()); + IvyVariableContainer variables = new IvyVariableContainerWrapper(settings.getVariableContainer()); variables.setVariable("ivy.pom.license", SKIP_LINE, true); variables.setVariable("ivy.pom.header", SKIP_LINE, true); @@ -103,53 +103,69 @@ public static void write(ModuleDescriptor md, File output, PomWriterOptions opti variables.setVariable("ivy.pom.license", options.getLicenseHeader(), true); } if (options.isPrintIvyInfo()) { - String header = ""; + String header + = ""; variables.setVariable("ivy.pom.header", header, true); } setModuleVariables(md, variables, options); + boolean dependencyManagement = false; boolean dependenciesPrinted = false; + boolean overridesPrinted = false; int lastIndent = 0; int indent = 0; - String line = in.readLine(); - while (line != null) { + String line; + while ((line = in.readLine()) != null) { line = IvyPatternHelper.substituteVariables(line, variables); if (line.contains(SKIP_LINE)) { // skip this line - line = in.readLine(); continue; } - if (line.trim().isEmpty()) { - // empty line - out.println(line); - line = in.readLine(); - continue; - } + if (!line.trim().isEmpty()) { + lastIndent = indent; + indent = line.indexOf('<'); - lastIndent = indent; - indent = line.indexOf('<'); + if (line.contains("")) { + dependencyManagement = true; + } - if (!dependenciesPrinted && line.contains("")) { - printDependencies(md, out, options, indent, false); - dependenciesPrinted = true; - } + if (line.contains("")) { + dependencyManagement = false; + } - if (!dependenciesPrinted && line.contains("")) { - printDependencies(md, out, options, lastIndent, true); - dependenciesPrinted = true; - } + if (line.contains("")) { + if (!dependenciesPrinted && !dependencyManagement) { + printDependencies(md, out, options, indent, false); + dependenciesPrinted = true; + } + if (!overridesPrinted && dependencyManagement) { + printOverrides(md, out, indent, false); + overridesPrinted = true; + } + } + if (line.contains("")) { + if (!dependenciesPrinted) { + printDependencies(md, out, options, lastIndent, true); + dependenciesPrinted = true; + } + if (!overridesPrinted) { + printOverrides(md, out, lastIndent, true); + overridesPrinted = true; + } + } + } out.println(line); - line = in.readLine(); } } finally { in.close(); - out.close(); } } @@ -343,8 +359,51 @@ private static void printExclusions(ExcludeRule[] exclusions, PrintWriter out, i out.println(""); } - private static DependencyDescriptor[] getDependencies(ModuleDescriptor md, - PomWriterOptions options) { + private static void printOverrides(ModuleDescriptor md, PrintWriter out, int indent, boolean container) { + ModuleRules mr = md.getAllDependencyDescriptorMediators(); + if (mr.getAllRules().isEmpty()) { + return; + } + + if (container) { + indent(out, indent); + out.println(""); + indent(out, indent * 2); + out.println(""); + } else { + indent /= 3; // is third-level child of + } + + for (Map.Entry entry : mr.getAllRules().entrySet()) { + if (entry.getValue() instanceof OverrideDependencyDescriptorMediator) { + String artifactId = entry.getKey().getAttributes().get("module"); + String groupId = entry.getKey().getAttributes().get("organisation"); + String version = ((OverrideDependencyDescriptorMediator) entry.getValue()).getVersion(); + + if (artifactId == null || artifactId.equals("*") || groupId == null || groupId.equals("*")) continue; + + indent(out, indent * 3); + out.println(""); + indent(out, indent * 4); + out.println("" + groupId + ""); + indent(out, indent * 4); + out.println("" + artifactId + ""); + indent(out, indent * 4); + out.println("" + version + ""); + indent(out, indent * 3); + out.println(""); + } + } + + if (container) { + indent(out, indent * 2); + out.println(""); + indent(out, indent); + out.println(""); + } + } + + private static DependencyDescriptor[] getDependencies(ModuleDescriptor md, PomWriterOptions options) { String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md); List result = new ArrayList<>(); diff --git a/test/java/org/apache/ivy/core/module/descriptor/IvyMakePomTest.java b/test/java/org/apache/ivy/core/module/descriptor/IvyMakePomTest.java index fea6b0f8a..a5d224d9f 100644 --- a/test/java/org/apache/ivy/core/module/descriptor/IvyMakePomTest.java +++ b/test/java/org/apache/ivy/core/module/descriptor/IvyMakePomTest.java @@ -15,15 +15,10 @@ * limitations under the License. * */ - package org.apache.ivy.core.module.descriptor; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - import java.io.File; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -32,59 +27,61 @@ import org.apache.ivy.TestHelper; import org.apache.ivy.ant.IvyMakePom; import org.apache.ivy.util.TestXmlHelper; + import org.apache.tools.ant.Project; -import org.junit.Before; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.apache.commons.io.FileUtils.writeLines; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + /** - * Tests {@link IvyMakePom} + * Tests {@link IvyMakePom}. */ public class IvyMakePomTest { - private Project project; + private Project project = TestHelper.newProject(); @Rule public TemporaryFolder workdir = new TemporaryFolder(); - @Before - public void beforeTest() { - this.project = TestHelper.newProject(); - } - /** - * Test case for IVY-1528. An Ivy file containing a classifier extra attribute in - * its dependency, must retain the classifier in the generated POM when converted - * to a POM file through {@link IvyMakePom}. - * - * @throws Exception if something goes wrong - * @see IVY-1528 + * Test case for IVY-1528. + *

+ * An Ivy file containing a classifier extra attribute in its + * dependency, must retain the classifier in the generated POM + * when converted to a POM file through {@link IvyMakePom}. */ @Test - public void testClassifier() throws Exception { - final File ivyFile = new File(IvyMakePomTest.class.getResource("ivy-to-pom-classifier.xml").toURI()); + public void testMakePom1528() throws Exception { + File ivyFile = new File(IvyMakePomTest.class.getResource("ivy-to-pom-classifier.xml").toURI()); assertTrue(ivyFile + " is either missing or not a file", ivyFile.isFile()); - final IvyMakePom makepom = new IvyMakePom(); - makepom.setProject(project); - final File generatedPomFile = workdir.newFile("test-ivy-to-pom-classifier.pom"); - makepom.setPomFile(generatedPomFile); - makepom.setIvyFile(ivyFile); - // run the task - makepom.execute(); - - // read the generated pom - final NodeList dependencies = (NodeList) TestXmlHelper.evaluateXPathExpr(generatedPomFile, "/project/dependencies/dependency", XPathConstants.NODESET); + File pomFile = workdir.newFile("test-ivy-to-pom-classifier.pom"); + + IvyMakePom task = new IvyMakePom(); + task.setIvyFile(ivyFile); + task.setPomFile(pomFile); + task.setProject(project); + task.execute(); + + NodeList dependencies = (NodeList) TestXmlHelper.evaluateXPathExpr(pomFile, "/project/dependencies/dependency", XPathConstants.NODESET); assertNotNull("Dependencies element wasn't found in the generated POM file", dependencies); assertEquals("Unexpected number of dependencies in the generated POM file", 2, dependencies.getLength()); - final Set expectedPomArtifactIds = new HashSet<>(); + Set expectedPomArtifactIds = new HashSet<>(); expectedPomArtifactIds.add("foo"); expectedPomArtifactIds.add("bar"); for (int i = 0; i < dependencies.getLength(); i++) { - final PomDependency pomDependency = PomDependency.parse(dependencies.item(i)); + PomDependency pomDependency = PomDependency.parse(dependencies.item(i)); assertNotNull("Dependency generated was null", pomDependency); assertTrue("Unexpected dependency " + pomDependency, expectedPomArtifactIds.contains(pomDependency.artifactId)); // we no longer expect this, so remove it @@ -103,6 +100,225 @@ public void testClassifier() throws Exception { assertTrue("Some expected dependencies " + expectedPomArtifactIds + " were not found in the generated POM file", expectedPomArtifactIds.isEmpty()); } + /** + * Test case for IVY-1653. + */ + @Test + public void testMakePom1653() throws Exception { + File ivyFile = workdir.newFile("ivy-1653.xml"); + writeLines(ivyFile, "UTF-8", Arrays.asList( + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + )); + + File pomFile = workdir.newFile("ivy-1653.pom"); + + IvyMakePom task = new IvyMakePom(); + task.setIvyFile(ivyFile); + task.setPomFile(pomFile); + task.setPrintIvyInfo(false); + task.setProject(project); + + IvyMakePom.Mapping mapping = task.createMapping(); + mapping.setConf("default"); + mapping.setScope("compile"); + + task.execute(); + + String[] expect = { + "", + "", + "", + " 4.0.0", + " org", + " name", + " jar", + " 1.0.0-SNAPSHOT", + " ", + " ", + " org.springframework", + " spring-aop", + " 6.2.9", + " compile", + " ", + " ", + " ", + " ", + " ", + " org.aspectj", + " aspectjrt", + " 1.9.24", + " ", + " ", + " ", + "", + "" + }; + + assertEquals(String.join(System.lineSeparator(), expect), readFileToString(pomFile, "UTF-8")); + } + + @Test + public void testMakePomWithTemplate() throws Exception { + File ivyFile = workdir.newFile("ivy.xml"); + writeLines(ivyFile, "UTF-8", Arrays.asList( + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + )); + + File pomFile = workdir.newFile("ivy.pom"); + + File templateFile = workdir.newFile("the.pom"); + writeLines(templateFile, "UTF-8", Arrays.asList( + "", + " ${ivy.pom.groupId}", + " ${ivy.pom.artifactId}", + " ${ivy.pom.version}", + " ", + " ", + " org.springframework", + " spring-core", + " 6.2.9", + " compile", + " ", + " ", + "" + )); + + IvyMakePom task = new IvyMakePom(); + task.setIvyFile(ivyFile); + task.setPomFile(pomFile); + task.setPrintIvyInfo(false); + task.setProject(project); + task.setTemplateFile(templateFile); + + IvyMakePom.Mapping mapping = task.createMapping(); + mapping.setConf("default"); + mapping.setScope("compile"); + + task.execute(); + + String[] expect = { + "", + " org", + " name", + " 1.0.0-SNAPSHOT", + " ", + " ", + " org.springframework", + " spring-core", + " 6.2.9", + " compile", + " ", + " ", + " org.springframework", + " spring-aop", + " 6.2.9", + " compile", + " ", + " ", + "", + "" + }; + + assertEquals(String.join(System.lineSeparator(), expect), readFileToString(pomFile, "UTF-8")); + } + + @Test + public void testMakePomWithTemplate2() throws Exception { + File ivyFile = workdir.newFile("ivy.xml"); + writeLines(ivyFile, "UTF-8", Arrays.asList( + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + )); + + File pomFile = workdir.newFile("ivy.pom"); + + File templateFile = workdir.newFile("the.pom"); + writeLines(templateFile, "UTF-8", Arrays.asList( + "", + " ${ivy.pom.groupId}", + " ${ivy.pom.artifactId}", + " ${ivy.pom.version}", + " ", + " ", + " ", + " org.aspectj", + " aspectjrt", + " 1.9.24", + " ", + " ", + " ", + "" + )); + + IvyMakePom task = new IvyMakePom(); + task.setIvyFile(ivyFile); + task.setPomFile(pomFile); + task.setPrintIvyInfo(false); + task.setProject(project); + task.setTemplateFile(templateFile); + + IvyMakePom.Mapping mapping = task.createMapping(); + mapping.setConf("default"); + mapping.setScope("compile"); + + task.execute(); + + String[] expect = { + "", + " org", + " name", + " 1.0.0-SNAPSHOT", + " ", + " ", + " ", + " org.aspectj", + " aspectjrt", + " 1.9.24", + " ", + " ", + " ", + " ", + " ", + " org.springframework", + " spring-aop", + " 6.2.9", + " compile", + " ", + " ", + "", + "" + }; + + assertEquals(String.join(System.lineSeparator(), expect), readFileToString(pomFile, "UTF-8")); + } + + //-------------------------------------------------------------------------- + private static final class PomDependency { private final String groupId; private final String artifactId;