This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch du in repository https://gitbox.apache.org/repos/asf/camel.git
commit 3196b08a86179e4c97cfd5232578da94f5239574 Author: Claus Ibsen <[email protected]> AuthorDate: Fri Feb 7 13:48:57 2025 +0100 CAMEL-21729: camel-jbang: dependency update pom.xml that can automatic add new Camel JARs --- .../dsl/jbang/core/commands/DependencyList.java | 9 + .../dsl/jbang/core/commands/DependencyUpdate.java | 205 +++++++++++++++++++-- .../org/apache/camel/tooling/maven/MavenGav.java | 23 +++ 3 files changed, 220 insertions(+), 17 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java index 2c4565a4e4c..c2c8a3d4ae6 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java @@ -88,6 +88,15 @@ public class DependencyList extends Export { String quarkusVersion = null; for (int i = 0; i < nl.getLength(); i++) { Element node = (Element) nl.item(i); + + // must be child at <project/dependencyManagement> or <project/dependencies> + String p = node.getParentNode().getNodeName(); + String p2 = node.getParentNode().getParentNode().getNodeName(); + boolean accept = "project".equals(p2) && (p.equals("dependencyManagement") || p.equals("dependencies")); + if (!accept) { + continue; + } + String g = node.getElementsByTagName("groupId").item(0).getTextContent(); String a = node.getElementsByTagName("artifactId").item(0).getTextContent(); String v = null; diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdate.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdate.java index d4b8f0dbf33..bf932b5f031 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdate.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdate.java @@ -17,31 +17,40 @@ package org.apache.camel.dsl.jbang.core.commands; import java.io.File; +import java.io.FileInputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.StringJoiner; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.apache.camel.tooling.maven.MavenGav; import org.apache.camel.util.IOHelper; +import org.apache.camel.util.StringHelper; +import org.apache.camel.util.xml.XmlLineNumberParser; +import org.apache.logging.log4j.util.Strings; import picocli.CommandLine; @CommandLine.Command(name = "update", - description = "Updates JBang style dependencies in source file", sortOptions = false, + description = "Updates dependencies in Maven pom.xml or Java source file (JBang style)", + sortOptions = false, showDefaultValues = true) public class DependencyUpdate extends DependencyList { - @CommandLine.Option(names = { "--source" }, - description = "Camel source such as .java file to have dependencies updated (//DEPS)", - required = true) - protected String source; + @CommandLine.Parameters(description = "Maven pom.xml or Java source files (JBang Style with //DEPS) to have dependencies updated", arity = "1") + public File file; @CommandLine.Option(names = { "--clean" }, - description = "Regenerate list of dependencies (do not keep existing dependencies)") + description = "Regenerate list of dependencies (do not keep existing dependencies). Not supported for pom.xml") protected boolean clean; private final List<String> deps = new ArrayList<>(); - private File target; + private final List<MavenGav> gavs = new ArrayList<>(); public DependencyUpdate(CamelJBangMain main) { super(main); @@ -50,15 +59,16 @@ public class DependencyUpdate extends DependencyList { @Override public Integer doCall() throws Exception { // source file must exist - target = new File(source); - if (!target.exists()) { - printer().printErr("Source file does not exist: " + target); + if (!file.exists()) { + printer().printErr("Source file does not exist: " + file); return -1; } - if (clean) { + boolean maven = "pom.xml".equals(file.getName()); + + if (clean && !maven) { // remove DEPS in source file first - updateSource(); + updateJBangSource(); } return super.doCall(); @@ -66,6 +76,28 @@ public class DependencyUpdate extends DependencyList { @Override protected void outputGav(MavenGav gav, int index, int total) { + try { + boolean maven = "pom.xml".equals(file.getName()); + if (maven) { + outputGavMaven(gav, index, total); + } else { + outputGavJBang(gav, index, total); + } + } catch (Exception e) { + printer().printErr("Cannot update dependencies due to " + e.getMessage(), e); + } + } + + protected void outputGavMaven(MavenGav gav, int index, int total) throws Exception { + gavs.add(gav); + + boolean last = total - index <= 1; + if (last) { + updateMavenSource(); + } + } + + protected void outputGavJBang(MavenGav gav, int index, int total) { if (index == 0) { deps.add("//DEPS org.apache.camel:camel-bom:" + gav.getVersion() + "@pom"); } @@ -79,13 +111,13 @@ public class DependencyUpdate extends DependencyList { } boolean last = total - index <= 1; if (last) { - updateSource(); + updateJBangSource(); } } - private void updateSource() { + private void updateJBangSource() { try { - List<String> lines = Files.readAllLines(target.toPath()); + List<String> lines = Files.readAllLines(file.toPath()); List<String> answer = new ArrayList<>(); // find position of where the old DEPS was @@ -117,9 +149,148 @@ public class DependencyUpdate extends DependencyList { } String text = String.join(System.lineSeparator(), answer); - IOHelper.writeText(text, target); + IOHelper.writeText(text, file); } catch (Exception e) { - printer().printErr("Error updating source file: " + target + " due to: " + e.getMessage()); + printer().printErr("Error updating source file: " + file + " due to: " + e.getMessage()); + } + } + + private void updateMavenSource() throws Exception { + List<MavenGav> existingGavs = new ArrayList<>(); + + Node camelClone = null; + int targetLineNumber = -1; + + File pom = new File(file.getName()); + if (pom.exists()) { + // use line number parser as we want to find where to add new Camel JARs after the existing Camel JARs + Document dom = XmlLineNumberParser.parseXml(new FileInputStream(pom)); + String camelVersion = null; + NodeList nl = dom.getElementsByTagName("dependency"); + for (int i = 0; i < nl.getLength(); i++) { + Element node = (Element) nl.item(i); + + // must be child at <project/dependencyManagement> or <project/dependencies> + String p = node.getParentNode().getNodeName(); + String p2 = node.getParentNode().getParentNode().getNodeName(); + boolean accept = "project".equals(p2) && (p.equals("dependencyManagement") || p.equals("dependencies")); + if (!accept) { + continue; + } + + String g = node.getElementsByTagName("groupId").item(0).getTextContent(); + String a = node.getElementsByTagName("artifactId").item(0).getTextContent(); + String v = null; + NodeList vl = node.getElementsByTagName("version"); + if (vl.getLength() > 0) { + v = vl.item(0).getTextContent(); + } + String scope = null; + vl = node.getElementsByTagName("scope"); + if (vl.getLength() > 0) { + scope = vl.item(0).getTextContent(); + } + if (scope != null && !"compile".equals(scope)) { + continue; + } + + if ("org.apache.camel".equals(g)) { + camelVersion = v; + if (camelClone == null && !"camel-bom".equals(a)) { + camelClone = node.cloneNode(true); + } + String num = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER_END); + if (num != null) { + targetLineNumber = Integer.parseInt(num); + } + num = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER_END); + if (num != null) { + targetLineNumber = Integer.parseInt(num); + } + } + if ("org.apache.camel.springboot".equals(g)) { + camelVersion = v; + String num = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER_END); + if (num != null) { + targetLineNumber = Integer.parseInt(num); + } + } + if ("org.apache.camel.quarkus".equals(g)) { + String num = (String) node.getUserData(XmlLineNumberParser.LINE_NUMBER_END); + if (num != null) { + targetLineNumber = Integer.parseInt(num); + } + } + if (v != null) { + existingGavs.add(MavenGav.parseGav(g + ":" + a + ":" + v)); + } else { + existingGavs.add(MavenGav.parseGav(g + ":" + a)); + } + } + + // find out which JARs are new + List<MavenGav> updates = new ArrayList<>(); + for (MavenGav gav : gavs) { + MavenGav target; + if (camelVersion != null) { + target = MavenGav.parseGav(gav.getGroupId() + ":" + gav.getArtifactId() + ":" + camelVersion); + } else { + target = MavenGav.parseGav(gav.getGroupId() + ":" + gav.getArtifactId()); + } + updates.add(target); + } + // sort the new JARs being added + updates.sort(mavenGavComparator()); + List<MavenGav> toBeUpdated = new ArrayList<>(); + int changes = 0; + for (MavenGav update : updates) { + if (!existingGavs.contains(update)) { + toBeUpdated.add(update); + changes++; + } + } + + if (changes > 0) { + // respect indent from existing GAVs + String line = IOHelper.loadTextLine(new FileInputStream(file), targetLineNumber); + line = StringHelper.before(line, "<"); + int indent = StringHelper.countChar(line, ' '); + String pad = Strings.repeat(" ", indent); + line = IOHelper.loadTextLine(new FileInputStream(file), targetLineNumber - 1); + line = StringHelper.before(line, "<"); + int indent2 = StringHelper.countChar(line, ' '); + String pad2 = Strings.repeat(" ", indent2); + + // build GAVs to be added to pom.xml + StringJoiner sj = new StringJoiner(""); + for (MavenGav gav : toBeUpdated) { + sj.add(pad).add("<dependency>\n"); + sj.add(pad2).add("<groupId>" + gav.getGroupId() + "</groupId>\n"); + sj.add(pad2).add("<artifactId>" + gav.getArtifactId() + "</artifactId>\n"); + if (gav.getVersion() != null) { + sj.add(pad2).add("<version>" + gav.getVersion() + "</version>\n"); + } + sj.add(pad).add("</dependency>"); + } + + StringJoiner out = new StringJoiner("\n"); + String[] lines = IOHelper.loadText(new FileInputStream(file)).split("\n"); + for (int i = 0; i < lines.length; i++) { + String txt = lines[i]; + out.add(txt); + if (i == targetLineNumber - 1) { + out.add(sj.toString()); + } + } + if (changes > 1) { + outPrinter().println("Updating pom.xml with " + changes + " dependencies added"); + } else { + outPrinter().println("Updating pom.xml with 1 dependency added"); + } + IOHelper.writeText(out.toString(), file); + } else { + outPrinter().println("No updates to pom.xml"); + } } } diff --git a/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java index 2237c0abeca..dcfb5c515d4 100644 --- a/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java +++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java @@ -16,6 +16,8 @@ */ package org.apache.camel.tooling.maven; +import java.util.Objects; + /** * Maven GAV model with parsing support and special rules for some names: * <ul> @@ -171,6 +173,27 @@ public final class MavenGav { this.classifier = classifier; } + @Override + public boolean equals(Object o) { + if (!(o instanceof MavenGav mavenGav)) { + return false; + } + + return groupId.equals(mavenGav.groupId) && artifactId.equals(mavenGav.artifactId) + && Objects.equals(version, mavenGav.version) && Objects.equals(packaging, mavenGav.packaging) + && Objects.equals(classifier, mavenGav.classifier); + } + + @Override + public int hashCode() { + int result = groupId.hashCode(); + result = 31 * result + artifactId.hashCode(); + result = 31 * result + Objects.hashCode(version); + result = 31 * result + Objects.hashCode(packaging); + result = 31 * result + Objects.hashCode(classifier); + return result; + } + @Override public String toString() { if (version != null) {
