This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new bbcc09964562 CAMEL-22544: jbang dependency update supports multi-file 
and --scan-routes (#22208)
bbcc09964562 is described below

commit bbcc09964562838d1526bea5b45f3b65d1fd131f
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri May 8 17:01:05 2026 +0200

    CAMEL-22544: jbang dependency update supports multi-file and --scan-routes 
(#22208)
    
    * CAMEL-22544: jbang dependency update supports multi-file and --scan-routes
    
    - Accept multiple target files (pom.xml or Java source files with //DEPS)
    - Add --scan-routes flag to sync dependencies from route definitions:
      - Manages only org.apache.camel dependencies
      - Preserves non-Camel dependencies
      - Removes unused Camel dependencies
      - Idempotent on re-execution
    - Route files (YAML, XML) passed as arguments are used as source files
      for the export pipeline dependency resolution
    - In scan-routes mode, Camel //DEPS in Java target files are stripped
      before export to prevent stale deps from being resolved
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-22544: Address review feedback
    
    - Merge DependencyUpdateJBangTest into DependencyUpdateTest (single test 
class)
    - Use fixture files from src/test/resources for scan-routes Maven tests
      instead of calling Init+Export at runtime
    - Add input validation preventing mixed pom.xml and Java targets
    - Guard addMavenDeps against targetLineNumber == -1
    - Clean up blank lines left by removeMavenDeps
    - Clarify isCamelDependency javadoc on group prefix matching
    - Fix PrepareCamelJBangCommandsMojo regex to match 'this' (not just 'main')
      as constructor arg, fixing stale metadata generation
    - Regenerate all jbang command metadata and docs
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-22544: Regenerate jbang command metadata after rebase
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-22544: Fix docs gulp race with test temp directories
    
    Add strict: false to gulp.src glob options so that ENOENT errors
    during directory traversal are warnings rather than failures. This
    prevents race conditions when the docs gulp build runs in parallel
    with tests that create and delete temporary directories.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-22544: Fix docs gulp race with test temp directories
    
    Use system temp directory instead of target/ for test working dirs
    and exclude .camel-jbang directories from gulpfile source glob
    pattern to avoid race condition with docs gulp build.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-22544: Regenerate jbang metadata and fix formatting
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 docs/gulpfile.js                                   |   2 +-
 .../camel-jbang-dependency-update.adoc             |   3 +-
 .../jbang-commands/camel-jbang-dependency.adoc     |   2 +-
 .../META-INF/camel-jbang-commands-metadata.json    |   2 +-
 .../dsl/jbang/core/commands/DependencyUpdate.java  | 501 +++++++++++++++++----
 .../jbang/core/commands/DependencyUpdateTest.java  | 282 +++++++++++-
 .../test/resources/dependency-update/main-pom.xml  |  62 +++
 .../resources/dependency-update/quarkus-pom.xml    |  68 +++
 .../test/resources/dependency-update/route.yaml    |  26 ++
 .../resources/dependency-update/springboot-pom.xml |  58 +++
 .../packaging/PrepareCamelJBangCommandsMojo.java   |   7 +-
 11 files changed, 906 insertions(+), 107 deletions(-)

diff --git a/docs/gulpfile.js b/docs/gulpfile.js
index e73414e8b842..0b70d4c3bf06 100644
--- a/docs/gulpfile.js
+++ b/docs/gulpfile.js
@@ -208,7 +208,7 @@ const sources = {
         
'../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
         
'../dsl/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
         
'../dsl/*/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
-        
'../dsl/*/*/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
+        
'../dsl/*/!(target|.camel-jbang*)/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
       ],
       destination: 'components/modules/others/pages',
       keep: [
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
index 24880ad6c54d..beb8a4f4d367 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
@@ -2,7 +2,7 @@
 // AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
 = camel dependency update
 
-Updates dependencies in Maven pom.xml or Java source file (JBang style)
+Updates dependencies in Maven pom.xml or Java source files (JBang style)
 
 
 == Usage
@@ -64,6 +64,7 @@ camel dependency update [options]
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories (Use commas to separate 
multiple repositories) |  | String
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
+| `--scan-routes` | Sync dependencies from route definitions. Only manages 
org.apache.camel dependencies, preserving non-Camel dependencies. Removes 
unused Camel dependencies. |  | boolean
 | `--skip-plugins` | Skip plugins during export | false | boolean
 | `--spring-boot-version` | Spring Boot version | 
RuntimeType.SPRING_BOOT_VERSION | String
 | `--verbose` | Verbose output of startup activity (dependency resolution and 
downloading | false | boolean
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency.adoc
index 63e3f40f6cd9..33ab125c3fa8 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency.adoc
@@ -21,7 +21,7 @@ camel dependency [options]
 | xref:jbang-commands/camel-jbang-dependency-copy.adoc[copy] | Copies all 
Camel dependencies required to run to a specific directory
 | xref:jbang-commands/camel-jbang-dependency-list.adoc[list] | Displays all 
Camel dependencies required to run
 | xref:jbang-commands/camel-jbang-dependency-runtime.adoc[runtime] | Display 
Camel runtime and version for given Maven project
-| xref:jbang-commands/camel-jbang-dependency-update.adoc[update] | Updates 
dependencies in Maven pom.xml or Java source file (JBang style)
+| xref:jbang-commands/camel-jbang-dependency-update.adoc[update] | Updates 
dependencies in Maven pom.xml or Java source files (JBang style)
 |===
 
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 94f962fd266c..a4040d23eb5e 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -6,7 +6,7 @@
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
     { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
-    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
+    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
     { "name": "dirty", "fullName": "dirty", "description": "Check if there are 
dirty files from previous Camel runs that did not terminate gracefully", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Dirty", 
"options": [ { "names": "--clean", "description": "Clean dirty files which are 
no longer in use", "defaultValue": "false", "javaType": "boolean", "type": 
"boolean" }, { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", " [...]
     { "name": "doc", "fullName": "doc", "description": "Shows documentation 
for kamelet, component, and other Camel resources", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogDoc", "options": [ { 
"names": "--camel-version", "description": "To use a different Camel version 
than the default version", "javaType": "java.lang.String", "type": "string" }, 
{ "names": "--download", "description": "Whether to allow automatic downloading 
JAR dependencies (over the internet [...]
     { "name": "eval", "fullName": "eval", "description": "Evaluate Camel 
expressions and scripts", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.EvalCommand", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "expression", 
"fullName": "eval expression", "description": "Evaluates Camel expression", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.action.EvalEx [...]
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 5c96cc3fbc5d..6e08c30c4ee4 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
@@ -20,12 +20,13 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 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.dsl.jbang.core.common.RuntimeType;
@@ -34,25 +35,33 @@ import org.apache.camel.util.FileUtil;
 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 dependencies in Maven pom.xml or 
Java source file (JBang style)",
+                     description = "Updates dependencies in Maven pom.xml or 
Java source files (JBang style)",
                      sortOptions = false,
                      showDefaultValues = true)
 public class DependencyUpdate extends DependencyList {
 
-    @CommandLine.Parameters(description = "Maven pom.xml or Java source files 
(JBang Style with //DEPS) to have dependencies updated",
-                            arity = "1")
-    public Path file;
+    @CommandLine.Parameters(description = "Maven pom.xml or Java source files 
(JBang Style with //DEPS) to have dependencies updated."
+                                          + " Route definition files (YAML, 
XML) can also be included and will be used as source files"
+                                          + " for dependency resolution.",
+                            arity = "1..*")
+    public List<Path> targetFiles;
 
     @CommandLine.Option(names = { "--clean" },
                         description = "Regenerate list of dependencies (do not 
keep existing dependencies). Not supported for pom.xml")
     protected boolean clean;
 
+    @CommandLine.Option(names = { "--scan-routes" },
+                        description = "Sync dependencies from route 
definitions. Only manages org.apache.camel dependencies,"
+                                      + " preserving non-Camel dependencies. 
Removes unused Camel dependencies.")
+    protected boolean scanRoutes;
+
     private final List<String> deps = new ArrayList<>();
     private final List<MavenGav> gavs = new ArrayList<>();
+    // actual target files to update (pom.xml or Java files with //DEPS)
+    private final List<Path> updateTargets = new ArrayList<>();
 
     public DependencyUpdate(CamelJBangMain main) {
         super(main);
@@ -60,22 +69,65 @@ public class DependencyUpdate extends DependencyList {
 
     @Override
     public Integer doCall() throws Exception {
-        // source file must exist
-        if (!Files.exists(file)) {
-            printer().printErr("Source file does not exist: " + file);
+        // clear state from any previous invocation
+        deps.clear();
+        gavs.clear();
+        updateTargets.clear();
+
+        if (clean && scanRoutes) {
+            printer().printErr("Options --clean and --scan-routes are mutually 
exclusive");
+            return -1;
+        }
+
+        for (Path file : targetFiles) {
+            if (!Files.exists(file)) {
+                printer().printErr("Source file does not exist: " + file);
+                return -1;
+            }
+            String name = file.getFileName().toString();
+            String ext = FileUtil.onlyExt(name, true);
+            if ("pom.xml".equals(name) || "java".equals(ext)) {
+                updateTargets.add(file);
+            }
+        }
+
+        if (scanRoutes) {
+            // in scan-routes mode, strip existing //DEPS from Java target 
files before the export pipeline
+            // runs, so only actual route-based dependencies are resolved (not 
stale //DEPS)
+            for (Path file : updateTargets) {
+                String ext = FileUtil.onlyExt(file.getFileName().toString(), 
true);
+                if ("java".equals(ext)) {
+                    stripJBangDeps(file);
+                }
+            }
+        }
+
+        if (updateTargets.isEmpty()) {
+            printer().printErr("No target files (pom.xml or Java source files) 
specified");
+            return -1;
+        }
+
+        // validate that all update targets are of the same type (all Maven or 
all JBang)
+        boolean hasMaven = updateTargets.stream().anyMatch(f -> 
"pom.xml".equals(f.getFileName().toString()));
+        boolean hasJava = updateTargets.stream().anyMatch(f -> 
!"pom.xml".equals(f.getFileName().toString()));
+        if (hasMaven && hasJava) {
+            printer().printErr("Cannot mix pom.xml and Java source files as 
update targets");
             return -1;
         }
 
-        boolean maven = "pom.xml".equals(file.getFileName().toString());
+        Path firstTarget = updateTargets.get(0);
+        boolean maven = hasMaven;
 
         if (clean && !maven) {
-            // remove DEPS in source file first
-            updateJBangSource();
+            // in clean mode: remove all DEPS first
+            for (Path file : updateTargets) {
+                updateJBangSource(file);
+            }
         }
 
         if (maven && this.runtime == null) {
             // Basic heuristic to determine if the project is a Quarkus or 
Spring Boot one.
-            String pomContent = new String(Files.readAllBytes(file));
+            String pomContent = new String(Files.readAllBytes(firstTarget));
             if (pomContent.contains("quarkus")) {
                 runtime = RuntimeType.quarkus;
             } else if (pomContent.contains("spring-boot")) {
@@ -93,7 +145,8 @@ public class DependencyUpdate extends DependencyList {
     @Override
     protected void outputGav(MavenGav gav, int index, int total) {
         try {
-            boolean maven = "pom.xml".equals(file.getFileName().toString());
+            Path firstTarget = updateTargets.get(0);
+            boolean maven = 
"pom.xml".equals(firstTarget.getFileName().toString());
             if (maven) {
                 outputGavMaven(gav, index, total);
             } else {
@@ -109,7 +162,9 @@ public class DependencyUpdate extends DependencyList {
 
         boolean last = total - index <= 1;
         if (last) {
-            updateMavenSource();
+            for (Path file : updateTargets) {
+                updateMavenSource(file);
+            }
         }
     }
 
@@ -127,11 +182,17 @@ public class DependencyUpdate extends DependencyList {
         }
         boolean last = total - index <= 1;
         if (last) {
-            updateJBangSource();
+            for (Path file : updateTargets) {
+                if (scanRoutes) {
+                    syncJBangSource(file);
+                } else {
+                    updateJBangSource(file);
+                }
+            }
         }
     }
 
-    private void updateJBangSource() {
+    private void updateJBangSource(Path file) {
         try {
             List<String> lines = Files.readAllLines(file);
             List<String> answer = new ArrayList<>();
@@ -155,7 +216,7 @@ public class DependencyUpdate extends DependencyList {
             }
             // add after shebang in top
             if (pos == -1) {
-                if (answer.get(0).trim().startsWith("///usr/bin/env jbang")) {
+                if (!answer.isEmpty() && 
answer.get(0).trim().startsWith("///usr/bin/env jbang")) {
                     pos = 1;
                 }
             }
@@ -164,13 +225,80 @@ public class DependencyUpdate extends DependencyList {
             }
 
             // reverse collection as we insert pos based
-            Collections.reverse(deps);
+            List<String> depsToInsert = new ArrayList<>(deps);
+            Collections.reverse(depsToInsert);
+            for (String dep : depsToInsert) {
+                answer.add(pos, dep);
+            }
+
+            String text = String.join(System.lineSeparator(), answer);
+            Files.writeString(file, text);
+        } catch (Exception e) {
+            printer().printErr("Error updating source file: " + file + " due 
to: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Syncs JBang source file dependencies: preserves non-Camel //DEPS, 
replaces Camel //DEPS with the resolved set.
+     */
+    private void syncJBangSource(Path file) {
+        try {
+            List<String> lines = Files.readAllLines(file);
+            List<String> answer = new ArrayList<>();
+
+            // collect non-Camel DEPS and find insertion position
+            List<String> nonCamelDeps = new ArrayList<>();
+            int pos = -1;
+            for (int i = 0; i < lines.size(); i++) {
+                String o = lines.get(i);
+                // remove leading comment chars to inspect
+                String l = o.trim();
+                while (l.startsWith("#")) {
+                    l = l.substring(1);
+                }
+                if (l.startsWith("//DEPS ")) {
+                    if (pos == -1) {
+                        pos = i;
+                    }
+                    // check if this is a Camel dependency
+                    String depPart = l.substring("//DEPS ".length()).trim();
+                    if (!isCamelDependency(depPart)) {
+                        nonCamelDeps.add(o);
+                    }
+                } else {
+                    answer.add(o);
+                }
+            }
+            // add after shebang in top
+            if (pos == -1) {
+                if (!answer.isEmpty() && 
answer.get(0).trim().startsWith("///usr/bin/env jbang")) {
+                    pos = 1;
+                }
+            }
+            if (pos == -1) {
+                pos = 0;
+            }
+
+            // build combined deps: Camel deps (from resolved) + non-Camel 
deps (preserved)
+            Set<String> seen = new LinkedHashSet<>();
+            List<String> allDeps = new ArrayList<>();
+
+            // add resolved Camel deps first
             for (String dep : deps) {
-                // is this XML or YAML
-                String ext = FileUtil.onlyExt(file.getFileName().toString(), 
true);
-                if ("yaml".equals(ext)) {
-                    dep = "#" + dep;
+                if (seen.add(dep)) {
+                    allDeps.add(dep);
+                }
+            }
+            // add preserved non-Camel deps
+            for (String dep : nonCamelDeps) {
+                if (seen.add(dep)) {
+                    allDeps.add(dep);
                 }
+            }
+
+            // reverse collection as we insert pos based
+            Collections.reverse(allDeps);
+            for (String dep : allDeps) {
                 answer.add(pos, dep);
             }
 
@@ -181,16 +309,58 @@ public class DependencyUpdate extends DependencyList {
         }
     }
 
-    private void updateMavenSource() throws Exception {
+    /**
+     * Strips Camel //DEPS lines from a JBang-style source file (in-place), 
preserving non-Camel //DEPS. This is used in
+     * scan-routes mode to prevent stale Camel //DEPS from being picked up by 
the export pipeline.
+     */
+    private void stripJBangDeps(Path file) {
+        try {
+            List<String> lines = Files.readAllLines(file);
+            List<String> answer = new ArrayList<>();
+            for (String line : lines) {
+                String l = line.trim();
+                while (l.startsWith("#")) {
+                    l = l.substring(1);
+                }
+                if (l.startsWith("//DEPS ")) {
+                    String depPart = l.substring("//DEPS ".length()).trim();
+                    if (isCamelDependency(depPart)) {
+                        // skip Camel deps — they will be re-added from route 
resolution
+                        continue;
+                    }
+                }
+                answer.add(line);
+            }
+            String text = String.join(System.lineSeparator(), answer);
+            Files.writeString(file, text);
+        } catch (Exception e) {
+            printer().printErr("Error stripping //DEPS from: " + file + " due 
to: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Check if a JBang dependency GAV string is a Camel dependency. Uses 
exact prefix "org.apache.camel:" (with colon)
+     * because JBang files only use the org.apache.camel group (not 
springboot/quarkus variants). For Maven pom.xml, see
+     * syncMavenSource which uses startsWith("org.apache.camel") without colon 
to also match org.apache.camel.springboot
+     * and org.apache.camel.quarkus groups.
+     */
+    private static boolean isCamelDependency(String dep) {
+        // handle @pom suffix
+        String d = dep;
+        if (d.endsWith("@pom")) {
+            d = d.substring(0, d.length() - 4);
+        }
+        return d.startsWith("org.apache.camel:");
+    }
+
+    private void updateMavenSource(Path file) throws Exception {
         List<MavenGav> existingGavs = new ArrayList<>();
 
-        Node camelClone = null;
         int targetLineNumber = -1;
 
-        Path pom = file;
-        if (Files.exists(pom)) {
+        if (Files.exists(file)) {
             // use line number parser as we want to find where to add new 
Camel JARs after the existing Camel JARs
-            Document dom = 
XmlLineNumberParser.parseXml(Files.newInputStream(pom));
+            Document dom = 
XmlLineNumberParser.parseXml(Files.newInputStream(file));
             String camelVersion = null;
             NodeList nl = dom.getElementsByTagName("dependency");
             for (int i = 0; i < nl.getLength(); i++) {
@@ -222,17 +392,10 @@ public class DependencyUpdate extends DependencyList {
 
                 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;
@@ -270,62 +433,236 @@ public class DependencyUpdate extends DependencyList {
             }
             // 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 (scanRoutes) {
+                // in scan-routes mode, sync Camel deps: add missing, remove 
unused
+                syncMavenSource(file, dom, existingGavs, updates);
+            } else {
+                // default mode: only add new deps
+                addMavenDeps(file, existingGavs, updates, targetLineNumber);
+            }
+        } else {
+            outPrinter().println("pom.xml not found " + file.toAbsolutePath());
+        }
+    }
+
+    private void addMavenDeps(Path file, List<MavenGav> existingGavs, 
List<MavenGav> updates, int targetLineNumber)
+            throws Exception {
+        List<MavenGav> toBeUpdated = new ArrayList<>();
+        for (MavenGav update : updates) {
+            if (!existingGavs.contains(update)) {
+                toBeUpdated.add(update);
+            }
+        }
+
+        if (!toBeUpdated.isEmpty() && targetLineNumber > 0) {
+            String content = IOHelper.loadText(Files.newInputStream(file));
+            String[] lines = content.split("\n");
+            content = insertMavenDeps(lines, toBeUpdated, targetLineNumber);
+            Files.writeString(file, content);
+            int changes = toBeUpdated.size();
+            if (changes > 1) {
+                outPrinter().println("Updating pom.xml with " + changes + " 
dependencies added");
+            } else {
+                outPrinter().println("Updating pom.xml with 1 dependency 
added");
+            }
+        } else {
+            outPrinter().println("No updates to pom.xml");
+        }
+    }
+
+    private void syncMavenSource(
+            Path file, Document dom, List<MavenGav> existingGavs, 
List<MavenGav> resolvedGavs)
+            throws Exception {
+
+        // determine which existing Camel deps are no longer needed
+        Set<String> resolvedGAs = new LinkedHashSet<>();
+        for (MavenGav gav : resolvedGavs) {
+            resolvedGAs.add(gav.getGroupId() + ":" + gav.getArtifactId());
+        }
+        Set<String> existingGAs = new LinkedHashSet<>();
+        for (MavenGav gav : existingGavs) {
+            existingGAs.add(gav.getGroupId() + ":" + gav.getArtifactId());
+        }
+
+        // find Camel deps to remove (exist in pom but not in resolved set)
+        List<String> toRemove = new ArrayList<>();
+        for (MavenGav gav : existingGavs) {
+            String ga = gav.getGroupId() + ":" + gav.getArtifactId();
+            boolean isCamel = gav.getGroupId().startsWith("org.apache.camel");
+            if (isCamel && !resolvedGAs.contains(ga)) {
+                // skip BOM entries
+                if (!"camel-bom".equals(gav.getArtifactId())
+                        && 
!"camel-spring-boot-bom".equals(gav.getArtifactId())) {
+                    toRemove.add(ga);
                 }
             }
+        }
 
-            if (changes > 0) {
-                // respect indent from existing GAVs
-                String line = 
IOHelper.loadTextLine(Files.newInputStream(file), targetLineNumber);
-                line = StringHelper.before(line, "<");
-                int indent = StringHelper.countChar(line, ' ');
-                String pad = Strings.repeat(" ", indent);
-                line = IOHelper.loadTextLine(Files.newInputStream(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("\n").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");
-                    }
-                    if (gav.getScope() != null) {
-                        sj.add(pad2).add("<scope>" + gav.getScope() + 
"</scope>\n");
-                    }
-                    sj.add(pad).add("</dependency>");
+        // find Camel deps to add (in resolved but not in pom)
+        List<MavenGav> toAdd = new ArrayList<>();
+        for (MavenGav gav : resolvedGavs) {
+            String ga = gav.getGroupId() + ":" + gav.getArtifactId();
+            if (!existingGAs.contains(ga)) {
+                toAdd.add(gav);
+            }
+        }
+
+        int added = toAdd.size();
+        int removed = toRemove.size();
+
+        if (added == 0 && removed == 0) {
+            outPrinter().println("No updates to pom.xml");
+            return;
+        }
+
+        // process file: remove unused Camel deps and add new ones
+        String content = IOHelper.loadText(Files.newInputStream(file));
+        String[] lines = content.split("\n");
+
+        if (removed > 0) {
+            content = removeMavenDeps(lines, dom, toRemove);
+        }
+
+        if (added > 0) {
+            // re-parse to get updated line numbers after removals
+            if (removed > 0) {
+                lines = content.split("\n");
+                Document updatedDom = XmlLineNumberParser.parseXml(
+                        new 
java.io.ByteArrayInputStream(content.getBytes(java.nio.charset.StandardCharsets.UTF_8)));
+                int insertLine = findLastCamelDependencyLine(updatedDom);
+                if (insertLine > 0) {
+                    content = insertMavenDeps(lines, toAdd, insertLine);
+                }
+            } else {
+                int insertLine = findLastCamelDependencyLine(dom);
+                if (insertLine > 0) {
+                    content = insertMavenDeps(lines, toAdd, insertLine);
                 }
+            }
+        }
 
-                StringJoiner out = new StringJoiner("\n");
-                String[] lines = 
IOHelper.loadText(Files.newInputStream(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());
-                    }
+        Files.writeString(file, content);
+
+        StringBuilder msg = new StringBuilder("Updating pom.xml with ");
+        if (added > 0) {
+            msg.append(added).append(added == 1 ? " dependency added" : " 
dependencies added");
+        }
+        if (removed > 0) {
+            if (added > 0) {
+                msg.append(" and ");
+            }
+            msg.append(removed).append(removed == 1 ? " dependency removed" : 
" dependencies removed");
+        }
+        outPrinter().println(msg.toString());
+    }
+
+    private int findLastCamelDependencyLine(Document dom) {
+        int targetLineNumber = -1;
+        NodeList nl = dom.getElementsByTagName("dependency");
+        for (int i = 0; i < nl.getLength(); i++) {
+            Element node = (Element) nl.item(i);
+            String p = node.getParentNode().getNodeName();
+            String p2 = node.getParentNode().getParentNode().getNodeName();
+            boolean accept = ("dependencyManagement".equals(p2) || 
"project".equals(p2)) && (p.equals("dependencies"));
+            if (!accept) {
+                continue;
+            }
+            String g = 
node.getElementsByTagName("groupId").item(0).getTextContent();
+            if (g.startsWith("org.apache.camel")) {
+                String num = (String) 
node.getUserData(XmlLineNumberParser.LINE_NUMBER_END);
+                if (num != null) {
+                    targetLineNumber = Integer.parseInt(num);
                 }
-                if (changes > 1) {
-                    outPrinter().println("Updating pom.xml with " + changes + 
" dependencies added");
-                } else {
-                    outPrinter().println("Updating pom.xml with 1 dependency 
added");
+            }
+        }
+        return targetLineNumber;
+    }
+
+    private String removeMavenDeps(String[] lines, Document dom, List<String> 
toRemove) {
+        // find line ranges of dependencies to remove
+        List<int[]> rangesToRemove = new ArrayList<>();
+        NodeList nl = dom.getElementsByTagName("dependency");
+        for (int i = 0; i < nl.getLength(); i++) {
+            Element node = (Element) nl.item(i);
+            String p = node.getParentNode().getNodeName();
+            String p2 = node.getParentNode().getParentNode().getNodeName();
+            boolean accept = ("dependencyManagement".equals(p2) || 
"project".equals(p2)) && (p.equals("dependencies"));
+            if (!accept) {
+                continue;
+            }
+            String g = 
node.getElementsByTagName("groupId").item(0).getTextContent();
+            String a = 
node.getElementsByTagName("artifactId").item(0).getTextContent();
+            String ga = g + ":" + a;
+            if (toRemove.contains(ga)) {
+                String startNum = (String) 
node.getUserData(XmlLineNumberParser.LINE_NUMBER);
+                String endNum = (String) 
node.getUserData(XmlLineNumberParser.LINE_NUMBER_END);
+                if (startNum != null && endNum != null) {
+                    rangesToRemove.add(new int[] { Integer.parseInt(startNum), 
Integer.parseInt(endNum) });
                 }
-                Files.writeString(file, out.toString());
-            } else {
-                outPrinter().println("No updates to pom.xml");
             }
-        } else {
-            outPrinter().println("pom.xml not found " + pom.toAbsolutePath());
         }
+
+        StringBuilder sb = new StringBuilder();
+        boolean previousSkipped = false;
+        for (int i = 0; i < lines.length; i++) {
+            int lineNum = i + 1; // 1-based
+            boolean skip = false;
+            for (int[] range : rangesToRemove) {
+                if (lineNum >= range[0] && lineNum <= range[1]) {
+                    skip = true;
+                    break;
+                }
+            }
+            if (!skip) {
+                // skip blank line immediately following a removed block to 
avoid double-blank-lines
+                if (previousSkipped && lines[i].trim().isEmpty()) {
+                    previousSkipped = false;
+                    continue;
+                }
+                if (sb.length() > 0) {
+                    sb.append("\n");
+                }
+                sb.append(lines[i]);
+            }
+            previousSkipped = skip;
+        }
+        return sb.toString();
+    }
+
+    private String insertMavenDeps(String[] lines, List<MavenGav> toAdd, int 
targetLineNumber) {
+        // respect indent from existing lines
+        String line = lines[targetLineNumber - 1];
+        String beforeTag = StringHelper.before(line, "<");
+        int indent = beforeTag != null ? StringHelper.countChar(beforeTag, ' 
') : 8;
+        String pad = " ".repeat(indent);
+        String line2 = targetLineNumber >= 2 ? lines[targetLineNumber - 2] : 
line;
+        String beforeTag2 = StringHelper.before(line2, "<");
+        int indent2 = beforeTag2 != null ? StringHelper.countChar(beforeTag2, 
' ') : indent + 4;
+        String pad2 = " ".repeat(indent2);
+
+        StringJoiner sj = new StringJoiner("");
+        for (MavenGav gav : toAdd) {
+            sj.add("\n").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");
+            }
+            if (gav.getScope() != null) {
+                sj.add(pad2).add("<scope>" + gav.getScope() + "</scope>\n");
+            }
+            sj.add(pad).add("</dependency>");
+        }
+
+        StringJoiner out = new StringJoiner("\n");
+        for (int i = 0; i < lines.length; i++) {
+            out.add(lines[i]);
+            if (i == targetLineNumber - 1) {
+                out.add(sj.toString());
+            }
+        }
+        return out.toString();
     }
 
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
index 4475d190267b..f1ce75e02ea5 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyUpdateTest.java
@@ -17,10 +17,10 @@
 package org.apache.camel.dsl.jbang.core.commands;
 
 import java.io.File;
-import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.List;
 import java.util.stream.Stream;
 
@@ -30,6 +30,7 @@ import org.apache.camel.util.FileUtil;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -45,8 +46,7 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
     @Override
     public void setup() throws Exception {
         super.setup();
-        Path base = Paths.get("target");
-        workingDir = Files.createTempDirectory(base, 
"camel-dependency-update-tests").toFile();
+        workingDir = 
Files.createTempDirectory("camel-dependency-update-tests").toFile();
     }
 
     @AfterEach
@@ -55,6 +55,8 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
         FileUtil.removeDir(workingDir);
     }
 
+    // ==================== Maven dependency update (existing export-based 
tests) ====================
+
     @ParameterizedTest
     @MethodSource("runtimeProvider")
     void shouldDependencyUpdate(RuntimeType rt) throws Exception {
@@ -64,7 +66,7 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
         checkOneDependencyAddedForArangoDb(rt);
     }
 
-    private void checkOneDependencyAddedForArangoDb(RuntimeType rt) throws 
Exception, IOException {
+    private void checkOneDependencyAddedForArangoDb(RuntimeType rt) throws 
Exception {
         StringPrinter secondUpdateCommandPrinter = new StringPrinter();
         DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(secondUpdateCommandPrinter));
         CommandLine.populateCommand(command,
@@ -94,18 +96,6 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
         }
     }
 
-    private void addArangodbToCamelFile() throws IOException {
-        File camelFile = new File(workingDir, 
"src/main/resources/camel/my.camel.yaml");
-        String camelFileContent = new 
String(Files.readAllBytes(camelFile.toPath()));
-        camelFileContent = camelFileContent.replace("- log: ${body}", """
-                - to:
-                             uri: arangodb
-                             parameters:
-                               database: demo
-                """);
-        Files.writeString(camelFile.toPath(), camelFileContent);
-    }
-
     private void checkNoUpdateOnFreshlyGeneratedproject() throws Exception {
         DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(printer));
         CommandLine.populateCommand(command,
@@ -137,6 +127,264 @@ class DependencyUpdateTest extends 
CamelCommandBaseTestSupport {
         Assertions.assertEquals(0, exportCommand.doCall(), 
exportCommandPrinter.getLines().toString());
     }
 
+    // ==================== scan-routes with Maven (fixture-based tests) 
====================
+
+    @ParameterizedTest
+    @MethodSource("runtimeProvider")
+    void shouldScanRoutesAddDependency(RuntimeType rt) throws Exception {
+        prepareFixtureProject(rt);
+
+        // add arangodb to the route
+        addArangodbToCamelFile();
+
+        // run with --scan-routes
+        StringPrinter updatePrinter = new StringPrinter();
+        DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(updatePrinter));
+        CommandLine.populateCommand(command,
+                "--scan-routes",
+                "--dir=" + workingDir,
+                new File(workingDir, "pom.xml").getAbsolutePath());
+        int exit = command.doCall();
+        Assertions.assertEquals(0, exit, updatePrinter.getLines().toString());
+
+        String pomContent = Files.readString(new File(workingDir, 
"pom.xml").toPath());
+        switch (rt) {
+            case quarkus:
+                assertThat(pomContent).contains("camel-quarkus-arangodb");
+                break;
+            case springBoot:
+                assertThat(pomContent).contains("camel-arangodb-starter");
+                break;
+            case main:
+                assertThat(pomContent).contains("camel-arangodb<");
+                break;
+        }
+    }
+
+    @Test
+    void shouldScanRoutesRemoveUnusedMavenDependency() throws Exception {
+        prepareFixtureProject(RuntimeType.main);
+
+        // manually add camel-kafka to the pom.xml (which is not used by the 
route)
+        File pomFile = new File(workingDir, "pom.xml");
+        String pomContent = Files.readString(pomFile.toPath());
+        // insert before the closing </dependencies> tag
+        String kafkaDep = "        <dependency>\n"
+                          + "            <groupId>org.apache.camel</groupId>\n"
+                          + "            
<artifactId>camel-kafka</artifactId>\n"
+                          + "        </dependency>\n    ";
+        pomContent = pomContent.replaceFirst("(</dependencies>)", kafkaDep + 
"$1");
+        Files.writeString(pomFile.toPath(), pomContent);
+
+        // verify kafka is there
+        assertThat(Files.readString(pomFile.toPath())).contains("camel-kafka");
+
+        // run with --scan-routes to sync
+        StringPrinter updatePrinter = new StringPrinter();
+        DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(updatePrinter));
+        CommandLine.populateCommand(command,
+                "--scan-routes",
+                "--dir=" + workingDir,
+                pomFile.getAbsolutePath());
+        int exit = command.doCall();
+        Assertions.assertEquals(0, exit, updatePrinter.getLines().toString());
+
+        // camel-kafka should be removed (not used in routes)
+        String updatedPom = Files.readString(pomFile.toPath());
+        assertThat(updatedPom).doesNotContain("camel-kafka");
+        // should still have camel-yaml-dsl (used for the route file)
+        assertThat(updatedPom).contains("camel-yaml-dsl");
+    }
+
+    @Test
+    void shouldScanRoutesAddAndRemoveMavenDependency() throws Exception {
+        prepareFixtureProject(RuntimeType.main);
+
+        // manually add camel-kafka to the pom.xml (which is not used by the 
route)
+        File pomFile = new File(workingDir, "pom.xml");
+        String pomContent = Files.readString(pomFile.toPath());
+        String kafkaDep = "        <dependency>\n"
+                          + "            <groupId>org.apache.camel</groupId>\n"
+                          + "            
<artifactId>camel-kafka</artifactId>\n"
+                          + "        </dependency>\n    ";
+        pomContent = pomContent.replaceFirst("(</dependencies>)", kafkaDep + 
"$1");
+        Files.writeString(pomFile.toPath(), pomContent);
+
+        // add arangodb to the route
+        addArangodbToCamelFile();
+
+        // run with --scan-routes to sync
+        StringPrinter updatePrinter = new StringPrinter();
+        DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(updatePrinter));
+        CommandLine.populateCommand(command,
+                "--scan-routes",
+                "--dir=" + workingDir,
+                pomFile.getAbsolutePath());
+        int exit = command.doCall();
+        Assertions.assertEquals(0, exit, updatePrinter.getLines().toString());
+
+        String updatedPom = Files.readString(pomFile.toPath());
+        // camel-kafka should be removed (not used in routes)
+        assertThat(updatedPom).doesNotContain("camel-kafka");
+        // camel-arangodb should be added (used in the route)
+        assertThat(updatedPom).contains("camel-arangodb<");
+        // should still have camel-yaml-dsl (used for the route file)
+        assertThat(updatedPom).contains("camel-yaml-dsl");
+    }
+
+    // ==================== JBang file tests (inline fixtures) 
====================
+
+    @Test
+    void shouldPreserveNonCamelDepsInJBangFile() throws Exception {
+        // create a Java file with mixed Camel and non-Camel //DEPS
+        Path javaFile = createFile("MyRoute.java", """
+                ///usr/bin/env jbang
+                //DEPS org.apache.camel:camel-bom:4.13.0@pom
+                //DEPS org.apache.camel:camel-kafka
+                //DEPS com.google.guava:guava:33.0.0-jre
+                //DEPS io.netty:netty-all:4.1.100.Final
+                import org.apache.camel.builder.RouteBuilder;
+                public class MyRoute extends RouteBuilder {
+                    public void configure() {
+                        from("timer:tick").to("log:info");
+                    }
+                }
+                """);
+
+        // run scan-routes with just the Java file (no separate route files)
+        StringPrinter p = new StringPrinter();
+        DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(p));
+        CommandLine.populateCommand(command,
+                "--scan-routes",
+                "--dir=" + workingDir,
+                javaFile.toAbsolutePath().toString());
+        int exit = command.doCall();
+        Assertions.assertEquals(0, exit, p.getLines().toString());
+
+        String content = Files.readString(javaFile);
+        // non-Camel deps should be preserved
+        assertThat(content).contains("//DEPS 
com.google.guava:guava:33.0.0-jre");
+        assertThat(content).contains("//DEPS 
io.netty:netty-all:4.1.100.Final");
+        // should have camel-bom (resolved fresh)
+        assertThat(content).contains("//DEPS org.apache.camel:camel-bom:");
+        // kafka should be removed (not used in the route definition)
+        assertThat(content).doesNotContain("camel-kafka");
+    }
+
+    @Test
+    void shouldScanRoutesIdempotentJBang() throws Exception {
+        Path javaFile = createFile("MyRoute.java", """
+                ///usr/bin/env jbang
+                //DEPS com.google.guava:guava:33.0.0-jre
+                import org.apache.camel.builder.RouteBuilder;
+                public class MyRoute extends RouteBuilder {
+                    public void configure() {
+                        from("timer:tick").to("log:info");
+                    }
+                }
+                """);
+
+        // run scan-routes twice
+        for (int run = 0; run < 2; run++) {
+            StringPrinter p = new StringPrinter();
+            DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(p));
+            CommandLine.populateCommand(command,
+                    "--scan-routes",
+                    "--dir=" + workingDir,
+                    javaFile.toAbsolutePath().toString());
+            int exit = command.doCall();
+            Assertions.assertEquals(0, exit, p.getLines().toString());
+        }
+
+        String content = Files.readString(javaFile);
+        // should have exactly one camel-bom line
+        long bomCount = content.lines().filter(l -> 
l.contains("camel-bom")).count();
+        assertThat(bomCount).isEqualTo(1);
+        // non-Camel deps should still be there
+        assertThat(content).contains("//DEPS 
com.google.guava:guava:33.0.0-jre");
+    }
+
+    @Test
+    void shouldUpdateMultipleJBangFiles() throws Exception {
+        Path java1 = createFile("MyRoute1.java", """
+                ///usr/bin/env jbang
+                import org.apache.camel.builder.RouteBuilder;
+                public class MyRoute1 extends RouteBuilder {
+                    public void configure() {
+                        from("timer:tick").to("log:info");
+                    }
+                }
+                """);
+        Path java2 = createFile("MyRoute2.java", """
+                ///usr/bin/env jbang
+                import org.apache.camel.builder.RouteBuilder;
+                public class MyRoute2 extends RouteBuilder {
+                    public void configure() {
+                        from("timer:tick").to("log:info");
+                    }
+                }
+                """);
+
+        DependencyUpdate command = new DependencyUpdate(new 
CamelJBangMain().withPrinter(printer));
+        CommandLine.populateCommand(command,
+                "--dir=" + workingDir,
+                java1.toAbsolutePath().toString(),
+                java2.toAbsolutePath().toString());
+
+        int exit = command.doCall();
+        Assertions.assertEquals(0, exit, printer.getLines().toString());
+
+        // both files should have //DEPS
+        String content1 = Files.readString(java1);
+        String content2 = Files.readString(java2);
+        assertThat(content1).contains("//DEPS org.apache.camel:camel-bom:");
+        assertThat(content2).contains("//DEPS org.apache.camel:camel-bom:");
+    }
+
+    // ==================== Helpers ====================
+
+    private void addArangodbToCamelFile() throws Exception {
+        File camelFile = new File(workingDir, 
"src/main/resources/camel/my.camel.yaml");
+        String content = Files.readString(camelFile.toPath());
+        content = content.replace("- log: ${body}", """
+                - to:
+                             uri: arangodb
+                             parameters:
+                               database: demo
+                """);
+        Files.writeString(camelFile.toPath(), content);
+    }
+
+    /**
+     * Prepares a project from fixture files in 
src/test/resources/dependency-update. Faster than Init+Export since no
+     * command invocation is needed.
+     */
+    private void prepareFixtureProject(RuntimeType rt) throws Exception {
+        String pomResource = switch (rt) {
+            case quarkus -> "dependency-update/quarkus-pom.xml";
+            case springBoot -> "dependency-update/springboot-pom.xml";
+            case main -> "dependency-update/main-pom.xml";
+        };
+
+        // copy pom.xml
+        try (InputStream in = 
getClass().getClassLoader().getResourceAsStream(pomResource)) {
+            Files.copy(in, new File(workingDir, "pom.xml").toPath(), 
StandardCopyOption.REPLACE_EXISTING);
+        }
+
+        // copy route file
+        Path routeDir = new File(workingDir, 
"src/main/resources/camel").toPath();
+        Files.createDirectories(routeDir);
+        try (InputStream in = 
getClass().getClassLoader().getResourceAsStream("dependency-update/route.yaml"))
 {
+            Files.copy(in, routeDir.resolve("my.camel.yaml"), 
StandardCopyOption.REPLACE_EXISTING);
+        }
+    }
+
+    private Path createFile(String name, String content) throws Exception {
+        Path file = workingDir.toPath().resolve(name);
+        Files.writeString(file, content);
+        return file;
+    }
+
     private static Stream<Arguments> runtimeProvider() {
         Stream.Builder<Arguments> builder = Stream.builder();
         builder.add(Arguments.of(RuntimeType.quarkus));
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/main-pom.xml
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/main-pom.xml
new file mode 100644
index 000000000000..a8fa3566579b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/main-pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>examples</groupId>
+    <artifactId>route</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <maven.compiler.release>21</maven.compiler.release>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-bom</artifactId>
+                <version>4.13.0</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-yaml-dsl</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/quarkus-pom.xml
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/quarkus-pom.xml
new file mode 100644
index 000000000000..ff304cc4d770
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/quarkus-pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>examples</groupId>
+    <artifactId>route</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <maven.compiler.release>21</maven.compiler.release>
+        
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
+        
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
+        <quarkus.platform.version>3.23.0</quarkus.platform.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>${quarkus.platform.group-id}</groupId>
+                <artifactId>${quarkus.platform.artifact-id}</artifactId>
+                <version>${quarkus.platform.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>${quarkus.platform.group-id}</groupId>
+                <artifactId>quarkus-camel-bom</artifactId>
+                <version>${quarkus.platform.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-yaml-dsl</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/route.yaml
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/route.yaml
new file mode 100644
index 000000000000..df0f91ed45f8
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/route.yaml
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+- route:
+    from:
+      uri: timer:yaml
+      parameters:
+        period: "1000"
+      steps:
+        - setBody:
+            simple: Hello Camel from my
+        - log: ${body}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/springboot-pom.xml
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/springboot-pom.xml
new file mode 100644
index 000000000000..98ab74b3ef7b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/dependency-update/springboot-pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>examples</groupId>
+    <artifactId>route</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <maven.compiler.release>21</maven.compiler.release>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.camel.springboot</groupId>
+                <artifactId>camel-spring-boot-bom</artifactId>
+                <version>4.13.0</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.springboot</groupId>
+            <artifactId>camel-yaml-dsl-starter</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
index d2bc45458120..44d099505283 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
@@ -57,9 +57,9 @@ import org.jboss.forge.roaster.model.source.JavaSource;
       requiresDependencyResolution = ResolutionScope.COMPILE)
 public class PrepareCamelJBangCommandsMojo extends AbstractGeneratorMojo {
 
-    // Pattern to match .addSubcommand("name", new CommandLine(new 
ClassName(this/main))
+    // Pattern to match .addSubcommand("name", new CommandLine(new 
ClassName(main)) or (this))
     private static final Pattern SUBCOMMAND_PATTERN = Pattern.compile(
-            
"\\.addSubcommand\\(\\s*\"([^\"]+)\"\\s*,\\s*new\\s+CommandLine\\(\\s*new\\s+([A-Za-z0-9_]+)\\s*\\(\\s*(?:this|main)\\s*\\)\\s*\\)");
+            
"\\.addSubcommand\\(\\s*\"([^\"]+)\"\\s*,\\s*new\\s+CommandLine\\(\\s*new\\s+([A-Za-z0-9_]+)\\s*\\(\\s*(?:main|this)\\s*\\)\\s*\\)");
 
     @Parameter(defaultValue = "${project.basedir}/src/generated/resources")
     protected File outFolder;
@@ -165,8 +165,7 @@ public class PrepareCamelJBangCommandsMojo extends 
AbstractGeneratorMojo {
         // Find the start of the commandLine builder chain
         int startLine = -1;
         for (int i = 0; i < lines.size(); i++) {
-            if (lines.get(i).contains("commandLine = new CommandLine(this)")
-                    || lines.get(i).contains("commandLine = new 
CommandLine(main)")) {
+            if (lines.get(i).contains("commandLine = new CommandLine(")) {
                 startLine = i;
                 break;
             }

Reply via email to