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 5f40eb4fb576 CAMEL-26930: camel-jbang - --jvm-debug and --jvm-args run 
in a JVM of the launcher, not through jbang (#29921)
5f40eb4fb576 is described below

commit 5f40eb4fb5768f9f989d3b7b472d0f812119cf1d
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Nov 14 19:25:19 2026 +0100

    CAMEL-26930: camel-jbang - --jvm-debug and --jvm-args run in a JVM of the 
launcher, not through jbang (#29921)
    
    Under the Camel launcher, --jvm-debug, --jvm-args and 
--open-telemetry-agent re-ran the
    integration through jbang: without jbang they failed with exit 70, and with 
jbang the run
    used another Camel build on jbang's JDK.
    
    Under the launcher (and without --camel-version) --jvm-debug and --jvm-args 
start a JVM
    of the launcher with those JVM options (--jvm-debug waits for the debugger, 
as jbang
    --debug does). --open-telemetry-agent, whose agent jbang downloads, exits 2 
with a clear
    message under the launcher, as --camel-version does.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../modules/ROOT/pages/camel-jbang-debugging.adoc  |  4 ++
 .../apache/camel/dsl/jbang/core/commands/Run.java  | 75 ++++++++++++++++++++++
 .../core/commands/RunLauncherJvmCommandTest.java   | 67 +++++++++++++++++++
 3 files changed, 146 insertions(+)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-debugging.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-debugging.adoc
index c80f246ba659..3a228958bec7 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-debugging.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-debugging.adoc
@@ -139,6 +139,10 @@ 
https://code.visualstudio.com/docs/java/java-debugging#_attach[VS Code], or
 
https://www.vogella.com/tutorials/EclipseDebugging/article.html#remote-debugging[Eclipse].
 Port configuration is described in the 
https://www.jbang.dev/documentation/guide/latest/debugging.html[JBang 
Debugging] guide.
 
+The integration runs in a new JVM that waits until a debugger attaches, and 
`--jvm-args` gives that JVM more options.
+With the Camel launcher (the Camel CLI installed without JBang), it is a JVM 
of the launcher, listening on
+`localhost`. With JBang, `jbang --debug` starts it. `--open-telemetry-agent` 
needs the Camel CLI installed via JBang.
+
 === JBang-level debugging
 
 Use JBang's `--debug` flag to debug any CLI command (not just `run`):
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index 67ae5ba0551a..d6a3027b8e06 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -859,6 +859,15 @@ public class Run extends CamelCommand implements 
CommandLifecycle {
         }
 
         // okay we have validated all input and are ready to run
+        if (camelVersion == null && isDebugMode() && 
LauncherHelper.isRunningFromLauncher()) {
+            // the launcher has no jbang: a JVM of the launcher with the JVM 
options (CAMEL-26930)
+            if (debugOptions.openTelemetryAgent) {
+                printer().printErr("The --open-telemetry-agent option is not 
supported when running from camel-launcher.");
+                printer().printDiagnostic("Install Camel CLI via JBang to use 
it: jbang app install camel@apache/camel");
+                return CliExitCode.USAGE;
+            }
+            return runLauncherJvm();
+        }
         if (camelVersion != null || isDebugMode()) {
             // TODO: debug camel specific version
             boolean custom = false;
@@ -1255,6 +1264,72 @@ public class Run extends CamelCommand implements 
CommandLifecycle {
         }
     }
 
+    /**
+     * Runs this integration in a new JVM of the launcher, with the JVM 
options of --jvm-debug and --jvm-args. Before,
+     * they ran it through jbang, which the launcher does not need, and which 
ran another Camel build on its own JDK.
+     */
+    protected int runLauncherJvm() throws Exception {
+        List<String> cmds = 
createLauncherJvmCommand(LauncherHelper.getCamelCommand());
+
+        ProcessBuilder pb = new ProcessBuilder();
+        pb.command(cmds);
+        markSpawned(pb);
+
+        if (verbose) {
+            printer().println(String.join(" ", cmds));
+        }
+
+        if (background) {
+            return runBackgroundProcess(pb, "Camel Main");
+        } else {
+            pb.inheritIO(); // run in foreground (with IO so logs are visible)
+            Process p = pb.start();
+            this.spawnPid = p.pid();
+            // wait for that process to exit as we run in foreground
+            return p.waitFor();
+        }
+    }
+
+    /**
+     * The command that runs this integration in a new JVM of the launcher: 
the java command of the launcher, with the
+     * JVM options of --jvm-debug (suspended until a debugger attaches, as 
jbang --debug does) and --jvm-args, and the
+     * run options without them.
+     *
+     * @param camelCommand the command of the launcher ({@link 
LauncherHelper#getCamelCommand()}): java, its options,
+     *                     -jar and the launcher JAR
+     */
+    List<String> createLauncherJvmCommand(List<String> camelCommand) {
+        List<String> cmds;
+        if (originalArgs() != null) {
+            cmds = new ArrayList<>(originalArgs());
+        } else {
+            cmds = new ArrayList<>();
+            cmds.add("run");
+        }
+        if (background) {
+            cmds = BackgroundWait.withoutBackgroundOptions(cmds);
+        }
+        List<String> jvm = new ArrayList<>();
+        // tooling may signal to run JMX debugger in suspended mode via JVM 
system property
+        String debugSuspend = 
System.getProperty(BacklogDebugger.SUSPEND_MODE_SYSTEM_PROP_NAME);
+        if (debugSuspend != null) {
+            jvm.add("-D" + BacklogDebugger.SUSPEND_MODE_SYSTEM_PROP_NAME + "=" 
+ debugSuspend);
+        }
+        if (jvmDebugPort > 0) {
+            
jvm.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:"
 + jvmDebugPort);
+            cmds.removeIf(arg -> arg.startsWith("--jvm-debug"));
+        }
+        if (jvmArgs != null && !jvmArgs.isBlank()) {
+            jvm.addAll(Arrays.asList(jvmArgs.trim().split("\\s+")));
+            cmds.removeIf(a -> a.startsWith("--jvm-args"));
+        }
+        List<String> answer = new ArrayList<>(camelCommand);
+        int jar = answer.indexOf("-jar");
+        answer.addAll(jar >= 0 ? jar : answer.size(), jvm);
+        answer.addAll(cmds);
+        return answer;
+    }
+
     // The jbang command that runs this integration in a new JVM.
     List<String> createCamelVersionCommand() {
         List<String> cmds;
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunLauncherJvmCommandTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunLauncherJvmCommandTest.java
new file mode 100644
index 000000000000..a3621a252495
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunLauncherJvmCommandTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+package org.apache.camel.dsl.jbang.core.commands;
+
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.core.common.CommandLineTestHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Under the launcher, --jvm-debug and --jvm-args run the integration in a JVM 
of the launcher, with those JVM options.
+ * Before, they went through jbang, which the launcher does not need, and 
which ran another Camel build on its own JDK
+ * (CAMEL-26930).
+ */
+class RunLauncherJvmCommandTest {
+
+    private static final List<String> LAUNCHER = List.of("/jdk/bin/java", 
"-Xmx512m", "-jar", "/opt/camel/lib/launcher.jar");
+
+    @Test
+    void jvmDebugOpensADebugSocketInTheLauncherJvm() {
+        List<String> cmd = command("route.camel.yaml", "--jvm-debug=5005");
+
+        // the arguments of the command line follow, without --jvm-debug (here 
without run, which a test does not give)
+        assertThat(cmd).containsExactly("/jdk/bin/java", "-Xmx512m",
+                
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005",
+                "-jar", "/opt/camel/lib/launcher.jar", "route.camel.yaml");
+        assertThat(cmd).doesNotContain("jbang");
+    }
+
+    @Test
+    void jvmArgsGoToTheLauncherJvm() {
+        List<String> cmd = command("route.camel.yaml", "--jvm-args=-Xmx1g 
-Dfoo=bar");
+
+        assertThat(cmd).containsSequence("-Xmx1g", "-Dfoo=bar", "-jar");
+        assertThat(cmd).noneMatch(arg -> arg.startsWith("--jvm-args"));
+        assertThat(cmd).endsWith("/opt/camel/lib/launcher.jar", 
"route.camel.yaml");
+    }
+
+    @Test
+    void inTheBackgroundTheJvmDoesNotGoToTheBackgroundAgain() {
+        List<String> cmd = command("route.camel.yaml", "--jvm-debug=5005", 
"--background");
+
+        assertThat(cmd).doesNotContain("--background");
+    }
+
+    private static List<String> command(String... args) {
+        Run run = new Run(new CamelJBangMain());
+        CommandLineTestHelper.parse(run, args);
+        return run.createLauncherJvmCommand(LAUNCHER);
+    }
+}

Reply via email to