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) {

Reply via email to