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

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

commit 66f66d9f701e025b99d8ac8297f2a65c68d14cac
Author: Croway <[email protected]>
AuthorDate: Mon Jan 19 11:39:33 2026 +0100

    CAMEL-22876: camel-launcher - handle jbang dependency in camel-jbang-core
---
 .../camel/dsl/jbang/core/commands/Debug.java       |   2 +-
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  12 +-
 .../camel/dsl/jbang/core/commands/RunHelper.java   |  10 +-
 .../dsl/jbang/core/commands/infra/InfraRun.java    |   4 +-
 .../dsl/jbang/core/common/LauncherHelper.java      | 132 +++++++++++++++++++++
 .../camel/dsl/jbang/launcher/CamelLauncher.java    |  40 +++++++
 6 files changed, 189 insertions(+), 11 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
index 87b5d71c2fee..22e40f95070d 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
@@ -584,7 +584,7 @@ public class Debug extends Run {
         cmds.add("--prop=camel.debug.loggingLevel=DEBUG");
         cmds.add("--prop=camel.debug.singleStepIncludeStartEnd=true");
 
-        RunHelper.addCamelJBangCommand(cmds);
+        RunHelper.addCamelCLICommand(cmds);
 
         ProcessBuilder pb = new ProcessBuilder();
         pb.command(cmds);
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 c128e3ee4802..8e67e5be802e 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
@@ -43,6 +43,7 @@ import java.util.stream.Stream;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.core.common.LauncherHelper;
 import org.apache.camel.dsl.jbang.core.common.LoggingLevelCompletionCandidates;
 import org.apache.camel.dsl.jbang.core.common.Printer;
 import org.apache.camel.dsl.jbang.core.common.PropertyResolver;
@@ -995,6 +996,15 @@ public class Run extends CamelCommand {
             writeSettings(DEPENDENCIES, joined);
         }
 
+        // Block --camel-version when running from camel-launcher
+        if (camelVersion != null && LauncherHelper.isRunningFromLauncher()) {
+            printer().printErr("The --camel-version option is not supported 
when running from camel-launcher.");
+            printer().printErr("To use a different Camel version, either:");
+            printer().printErr("  1. Use a different camel-launcher JAR 
version");
+            printer().printErr("  2. Install Camel CLI via JBang: jbang app 
install camel@apache/camel");
+            return 1;
+        }
+
         // if we have a specific camel version then make sure we really need 
to switch
         if (camelVersion != null) {
             CamelCatalog catalog = new DefaultCamelCatalog();
@@ -1529,7 +1539,7 @@ public class Run extends CamelCommand {
         cmds.remove("--background-wait=true");
         cmds.remove("--background-wait");
 
-        RunHelper.addCamelJBangCommand(cmds);
+        RunHelper.addCamelCLICommand(cmds);
 
         ProcessBuilder pb = new ProcessBuilder();
         pb.command(cmds);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
index 4cdf6dcd3c85..b7aa8830316d 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
@@ -30,6 +30,7 @@ import java.util.stream.Stream;
 
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.common.LauncherHelper;
 import org.apache.camel.main.download.MavenDependencyDownloader;
 import org.apache.camel.tooling.maven.MavenArtifact;
 import org.apache.camel.util.FileUtil;
@@ -305,12 +306,7 @@ public final class RunHelper {
      * Adds camel to the start of the list of commands to make it possible to 
run camel-jbang using a spawned process
      * (to run in background).
      */
-    public static void addCamelJBangCommand(List<String> cmds) {
-        if (FileUtil.isWindows()) {
-            String jbangDir = System.getenv().getOrDefault("JBANG_DIR", 
System.getProperty("user.home") + "\\.jbang");
-            cmds.add(0, jbangDir + "\\bin\\camel.cmd");
-        } else {
-            cmds.add(0, "camel");
-        }
+    public static void addCamelCLICommand(List<String> cmds) {
+        cmds.addAll(0, LauncherHelper.getCamelCommand());
     }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
index 41fab4f40af5..b61559d71456 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
@@ -39,7 +39,7 @@ import 
org.apache.camel.main.download.MavenDependencyDownloader;
 import org.apache.camel.tooling.maven.MavenArtifact;
 import picocli.CommandLine;
 
-import static 
org.apache.camel.dsl.jbang.core.commands.RunHelper.addCamelJBangCommand;
+import static 
org.apache.camel.dsl.jbang.core.commands.RunHelper.addCamelCLICommand;
 
 @CommandLine.Command(name = "run", description = "Run an external service", 
sortOptions = false, showDefaultValues = true)
 public class InfraRun extends InfraBaseCommand {
@@ -122,7 +122,7 @@ public class InfraRun extends InfraBaseCommand {
         cmds.remove("--background=true");
         cmds.remove("--background");
 
-        addCamelJBangCommand(cmds);
+        addCamelCLICommand(cmds);
 
         ProcessBuilder pb = new ProcessBuilder();
         pb.command(cmds);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/LauncherHelper.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/LauncherHelper.java
new file mode 100644
index 000000000000..8c7f5fc4bd44
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/LauncherHelper.java
@@ -0,0 +1,132 @@
+/*
+ * 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.common;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.util.FileUtil;
+
+/**
+ * Helper class for detecting and working with the camel-launcher runtime.
+ */
+public final class LauncherHelper {
+
+    public static final String CAMEL_LAUNCHER_PROPERTY = "camel.launcher";
+    public static final String CAMEL_LAUNCHER_JAR_PROPERTY = 
"camel.launcher.jar";
+
+    private LauncherHelper() {
+    }
+
+    /**
+     * Detects if running from camel-launcher (fat JAR) vs JBang.
+     */
+    public static boolean isRunningFromLauncher() {
+        // Check system property (set by CamelLauncher)
+        if 
("true".equalsIgnoreCase(System.getProperty(CAMEL_LAUNCHER_PROPERTY))) {
+            return true;
+        }
+
+        // Check JAR path as fallback
+        String jarPath = getLauncherJarPath();
+        return jarPath != null && jarPath.contains("camel-launcher");
+    }
+
+    /**
+     * Gets the path to the launcher JAR file.
+     */
+    public static String getLauncherJarPath() {
+        // 1. Check system property first
+        String jarPath = System.getProperty(CAMEL_LAUNCHER_JAR_PROPERTY);
+        if (jarPath != null && !jarPath.isEmpty()) {
+            return jarPath;
+        }
+
+        // 2. Try to detect from code source location
+        try {
+            URL location = LauncherHelper.class.getProtectionDomain()
+                    .getCodeSource().getLocation();
+            if (location != null) {
+                String urlStr = location.toString();
+                // Handle nested JAR (Spring Boot loader)
+                if (urlStr.startsWith("jar:file:")) {
+                    int idx = urlStr.indexOf("!/");
+                    if (idx > 0) {
+                        String path = urlStr.substring(9, idx);
+                        // Decode URL-encoded characters (spaces, special 
chars)
+                        return URLDecoder.decode(path, StandardCharsets.UTF_8);
+                    }
+                }
+                // Handle direct file URL
+                if (urlStr.startsWith("file:")) {
+                    String path = urlStr.substring(5);
+                    return URLDecoder.decode(path, StandardCharsets.UTF_8);
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("WARN: Failed to detect launcher JAR path: " + 
e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Gets the command to spawn a new camel process.
+     */
+    public static List<String> getCamelCommand() {
+        List<String> cmds = new ArrayList<>();
+
+        if (isRunningFromLauncher()) {
+            String jarPath = getLauncherJarPath();
+            if (jarPath != null) {
+                cmds.add(getJavaCommand());
+                cmds.add("-jar");
+                cmds.add(jarPath);
+                return cmds;
+            }
+        }
+
+        // Fall back to JBang-style command
+        if (FileUtil.isWindows()) {
+            String jbangDir = System.getenv().getOrDefault("JBANG_DIR",
+                    System.getProperty("user.home") + "\\.jbang");
+            cmds.add(jbangDir + "\\bin\\camel.cmd");
+        } else {
+            cmds.add("camel");
+        }
+        return cmds;
+    }
+
+    private static String getJavaCommand() {
+        String javaHome = System.getProperty("java.home");
+        if (javaHome != null) {
+            StringBuilder javaBin = new StringBuilder(javaHome);
+            
javaBin.append(File.separator).append("bin").append(File.separator).append("java");
+            if (FileUtil.isWindows()) {
+                javaBin.append(".exe");
+            }
+            File javaBinFile = new File(javaBin.toString());
+            if (javaBinFile.exists()) {
+                return javaBin.toString();
+            }
+        }
+        return "java";
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-launcher/src/main/java/org/apache/camel/dsl/jbang/launcher/CamelLauncher.java
 
b/dsl/camel-jbang/camel-launcher/src/main/java/org/apache/camel/dsl/jbang/launcher/CamelLauncher.java
index 3dc4c9b92b15..b86976b1a464 100644
--- 
a/dsl/camel-jbang/camel-launcher/src/main/java/org/apache/camel/dsl/jbang/launcher/CamelLauncher.java
+++ 
b/dsl/camel-jbang/camel-launcher/src/main/java/org/apache/camel/dsl/jbang/launcher/CamelLauncher.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.dsl.jbang.launcher;
 
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 
 /**
@@ -32,6 +36,42 @@ public class CamelLauncher {
      * @param args command line arguments to pass to Camel JBang
      */
     public static void main(String... args) {
+        // Set system property to indicate we're running from the launcher
+        System.setProperty("camel.launcher", "true");
+
+        // Try to determine and set the JAR path
+        String jarPath = detectJarPath();
+        if (jarPath != null) {
+            System.setProperty("camel.launcher.jar", jarPath);
+        }
+
         CamelJBangMain.run(args);
     }
+
+    private static String detectJarPath() {
+        try {
+            URL location = CamelLauncher.class.getProtectionDomain()
+                    .getCodeSource().getLocation();
+            if (location != null) {
+                String urlStr = location.toString();
+                // Handle nested JAR (Spring Boot loader)
+                if (urlStr.startsWith("jar:file:")) {
+                    int idx = urlStr.indexOf("!/");
+                    if (idx > 0) {
+                        String path = urlStr.substring(9, idx);
+                        // Decode URL-encoded characters (spaces, special 
chars)
+                        return URLDecoder.decode(path, StandardCharsets.UTF_8);
+                    }
+                }
+                // Handle direct file URL
+                if (urlStr.startsWith("file:")) {
+                    String path = urlStr.substring(5);
+                    return URLDecoder.decode(path, StandardCharsets.UTF_8);
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("WARN: Failed to detect launcher JAR path: " + 
e.getMessage());
+        }
+        return null;
+    }
 }

Reply via email to