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

gnodet pushed a commit to branch camel-23150-camel-wrapper
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 58235a2f5d20a899340f9518a00a204dd4e82ba8
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri Mar 13 09:37:46 2026 +0100

    CAMEL-23150: Add camel wrapper command for version pinning
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   1 +
 .../dsl/jbang/core/commands/WrapperCommand.java    | 155 ++++++++++++++++++
 .../src/main/resources/camel-wrapper/camelw        | 160 ++++++++++++++++++
 .../src/main/resources/camel-wrapper/camelw.cmd    | 101 ++++++++++++
 .../jbang/core/commands/WrapperCommandTest.java    | 181 +++++++++++++++++++++
 pom.xml                                            |   1 +
 6 files changed, 599 insertions(+)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 93861612e5f4..3627447d602c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -206,6 +206,7 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("get", new CommandLine(new 
VersionGet(this)))
                         .addSubcommand("list", new CommandLine(new 
VersionList(this)))
                         .addSubcommand("set", new CommandLine(new 
VersionSet(this))))
+                .addSubcommand("wrapper", new CommandLine(new 
WrapperCommand(this)))
                 .setParameterExceptionHandler(new 
MissingPluginParameterExceptionHandler());
 
         postAddCommands(commandLine, args);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommand.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommand.java
new file mode 100644
index 000000000000..7f8966270ee1
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommand.java
@@ -0,0 +1,155 @@
+/*
+ * 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.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.attribute.PosixFilePermission;
+import java.util.Set;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.util.IOHelper;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "wrapper", description = "Install Camel wrapper scripts for 
version pinning", sortOptions = false,
+         showDefaultValues = true)
+public class WrapperCommand extends CamelCommand {
+
+    private static final String DEFAULT_REPO_URL = 
"https://repo1.maven.org/maven2";;
+    private static final String WRAPPER_PROPERTIES_FILE = 
"camel-wrapper.properties";
+    private static final String CAMEL_DIR = ".camel";
+
+    @CommandLine.Option(names = { "--camel-version" },
+                        description = "Camel version to pin (defaults to 
current version)")
+    String camelVersion;
+
+    @CommandLine.Option(names = { "--repo-url" },
+                        description = "Maven repository URL for downloading 
the launcher",
+                        defaultValue = DEFAULT_REPO_URL)
+    String repoUrl = DEFAULT_REPO_URL;
+
+    @CommandLine.Option(names = { "--dir", "--directory" },
+                        description = "Directory where wrapper files will be 
created",
+                        defaultValue = ".")
+    String directory = ".";
+
+    public WrapperCommand(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doCall() throws Exception {
+        if (camelVersion == null || camelVersion.isEmpty()) {
+            CamelCatalog catalog = new DefaultCamelCatalog();
+            camelVersion = catalog.getCatalogVersion();
+        }
+
+        Path baseDir = Paths.get(directory).toAbsolutePath().normalize();
+        Path camelDir = baseDir.resolve(CAMEL_DIR);
+
+        // Create .camel directory
+        Files.createDirectories(camelDir);
+
+        // Write camel-wrapper.properties
+        writeProperties(camelDir);
+
+        // Write camelw script
+        writeScript(baseDir, "camelw");
+
+        // Write camelw.cmd script
+        writeScript(baseDir, "camelw.cmd");
+
+        printer().println("Apache Camel wrapper installed successfully.");
+        printer().println("  Camel version: " + camelVersion);
+        printer().println("  Properties: " + 
camelDir.resolve(WRAPPER_PROPERTIES_FILE));
+        printer().println("  Unix script: " + baseDir.resolve("camelw"));
+        printer().println("  Windows script: " + 
baseDir.resolve("camelw.cmd"));
+        printer().println();
+        printer().println("You can now use ./camelw instead of camel to run 
with the pinned version.");
+
+        return 0;
+    }
+
+    void writeProperties(Path camelDir) throws IOException {
+        String distributionUrl = buildDistributionUrl();
+        String content = String.join(System.lineSeparator(),
+                "# 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.",
+                "camel.version=" + camelVersion,
+                "distributionUrl=" + distributionUrl,
+                "");
+
+        Files.writeString(camelDir.resolve(WRAPPER_PROPERTIES_FILE), content);
+    }
+
+    String buildDistributionUrl() {
+        return repoUrl
+               + "/org/apache/camel/camel-launcher/"
+               + camelVersion
+               + "/camel-launcher-"
+               + camelVersion
+               + ".jar";
+    }
+
+    void writeScript(Path baseDir, String scriptName) throws IOException {
+        String resourcePath = "camel-wrapper/" + scriptName;
+        try (InputStream is = 
WrapperCommand.class.getClassLoader().getResourceAsStream(resourcePath)) {
+            if (is == null) {
+                throw new IOException("Resource not found: " + resourcePath);
+            }
+            String content = IOHelper.loadText(is);
+            Path scriptPath = baseDir.resolve(scriptName);
+            Files.writeString(scriptPath, content);
+
+            // Make Unix script executable
+            if (!scriptName.endsWith(".cmd")) {
+                makeExecutable(scriptPath);
+            }
+        }
+    }
+
+    private void makeExecutable(Path path) {
+        try {
+            Set<PosixFilePermission> perms = 
Files.getPosixFilePermissions(path);
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+            Files.setPosixFilePermissions(path, perms);
+        } catch (UnsupportedOperationException | IOException e) {
+            // Windows or other OS that doesn't support POSIX permissions
+        }
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw
new file mode 100644
index 000000000000..ff6d57f829e2
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw
@@ -0,0 +1,160 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Camel Wrapper startup script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   CAMEL_OPTS - parameters passed to the Java VM when running Camel
+# ----------------------------------------------------------------------------
+
+# OS specific support
+cygwin=false
+darwin=false
+mingw=false
+case "$(uname)" in
+CYGWIN*) cygwin=true ;;
+MINGW*) mingw=true ;;
+Darwin*)
+  darwin=true
+  if [ -z "$JAVA_HOME" ]; then
+    if [ -x "/usr/libexec/java_home" ]; then
+      JAVA_HOME="$(/usr/libexec/java_home)"
+      export JAVA_HOME
+    else
+      JAVA_HOME="/Library/Java/Home"
+      export JAVA_HOME
+    fi
+  fi
+  ;;
+esac
+
+if [ -z "$JAVA_HOME" ]; then
+  if [ -r /etc/gentoo-release ]; then
+    JAVA_HOME=$(java-config --jre-home)
+  fi
+fi
+
+# Resolve the script directory
+if [ -z "$CAMEL_WRAPPER_DIR" ]; then
+  # resolve links - $0 may be a softlink
+  PRG="$0"
+  while [ -h "$PRG" ]; do
+    ls=$(ls -ld "$PRG")
+    link=$(expr "$ls" : '.*-> \(.*\)$')
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG=$(dirname "$PRG")/"$link"
+    fi
+  done
+  CAMEL_WRAPPER_DIR=$(dirname "$PRG")
+  CAMEL_WRAPPER_DIR=$(cd "$CAMEL_WRAPPER_DIR" && pwd)
+fi
+
+# Read properties file
+CAMEL_PROPERTIES="$CAMEL_WRAPPER_DIR/.camel/camel-wrapper.properties"
+if [ ! -f "$CAMEL_PROPERTIES" ]; then
+  echo "Error: Could not find $CAMEL_PROPERTIES" >&2
+  echo "Please run 'camel wrapper' to set up the Camel wrapper." >&2
+  exit 1
+fi
+
+# Parse properties
+CAMEL_VERSION=$(grep '^camel.version=' "$CAMEL_PROPERTIES" | cut -d'=' -f2-)
+DISTRIBUTION_URL=$(grep '^distributionUrl=' "$CAMEL_PROPERTIES" | cut -d'=' 
-f2-)
+
+if [ -z "$CAMEL_VERSION" ]; then
+  echo "Error: camel.version not found in $CAMEL_PROPERTIES" >&2
+  exit 1
+fi
+
+if [ -z "$DISTRIBUTION_URL" ]; then
+  echo "Error: distributionUrl not found in $CAMEL_PROPERTIES" >&2
+  exit 1
+fi
+
+# Determine the Java command to use
+if [ -n "$JAVA_HOME" ]; then
+  if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+    JAVACMD="$JAVA_HOME/jre/sh/java"
+  else
+    JAVACMD="$JAVA_HOME/bin/java"
+  fi
+  if [ ! -x "$JAVACMD" ]; then
+    echo "Error: JAVA_HOME is set to an invalid directory: $JAVA_HOME" >&2
+    echo "Please set the JAVA_HOME variable in your environment to match the" 
>&2
+    echo "location of your Java installation." >&2
+    exit 1
+  fi
+else
+  JAVACMD="java"
+  command -v java >/dev/null 2>&1 || {
+    echo "Error: JAVA_HOME is not set and 'java' command not found in PATH." 
>&2
+    echo "Please set the JAVA_HOME variable in your environment to match the" 
>&2
+    echo "location of your Java installation." >&2
+    exit 1
+  }
+fi
+
+# Set up the cache directory for the launcher jar
+CAMEL_CACHE_DIR="${HOME}/.camel/wrapper"
+CAMEL_LAUNCHER_JAR="$CAMEL_CACHE_DIR/camel-launcher-${CAMEL_VERSION}.jar"
+
+# Download the launcher jar if it doesn't exist
+if [ ! -f "$CAMEL_LAUNCHER_JAR" ]; then
+  mkdir -p "$CAMEL_CACHE_DIR"
+  echo "Downloading Camel Launcher ${CAMEL_VERSION}..."
+
+  if command -v curl > /dev/null 2>&1; then
+    curl -fsSL -o "$CAMEL_LAUNCHER_JAR" "$DISTRIBUTION_URL" || {
+      echo "Error: Failed to download Camel Launcher from $DISTRIBUTION_URL" 
>&2
+      rm -f "$CAMEL_LAUNCHER_JAR"
+      exit 1
+    }
+  elif command -v wget > /dev/null 2>&1; then
+    wget -q -O "$CAMEL_LAUNCHER_JAR" "$DISTRIBUTION_URL" || {
+      echo "Error: Failed to download Camel Launcher from $DISTRIBUTION_URL" 
>&2
+      rm -f "$CAMEL_LAUNCHER_JAR"
+      exit 1
+    }
+  else
+    echo "Error: Neither curl nor wget found. Please install one of them." >&2
+    exit 1
+  fi
+
+  echo "Camel Launcher ${CAMEL_VERSION} downloaded successfully."
+fi
+
+# For Cygwin/MinGW, switch paths to Windows format
+if $cygwin; then
+  CAMEL_LAUNCHER_JAR=$(cygpath --path --windows "$CAMEL_LAUNCHER_JAR")
+fi
+
+# Run the Camel launcher
+exec "$JAVACMD" \
+  $CAMEL_OPTS \
+  -jar "$CAMEL_LAUNCHER_JAR" \
+  "$@"
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw.cmd 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw.cmd
new file mode 100644
index 000000000000..fdb5822d0b2e
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/camel-wrapper/camelw.cmd
@@ -0,0 +1,101 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one or more
+@REM contributor license agreements.  See the NOTICE file distributed with
+@REM this work for additional information regarding copyright ownership.
+@REM The ASF licenses this file to You under the Apache License, Version 2.0
+@REM (the "License"); you may not use this file except in compliance with
+@REM the License.  You may obtain a copy of the License at
+@REM
+@REM      http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing, software
+@REM distributed under the License is distributed on an "AS IS" BASIS,
+@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@REM See the License for the specific language governing permissions and
+@REM limitations under the License.
+@REM
+
+@REM 
----------------------------------------------------------------------------
+@REM Apache Camel Wrapper startup batch script
+@REM
+@REM Required ENV vars:
+@REM   JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars:
+@REM   CAMEL_OPTS - parameters passed to the Java VM when running Camel
+@REM 
----------------------------------------------------------------------------
+
+@echo off
+setlocal
+
+set "CAMEL_WRAPPER_DIR=%~dp0"
+
+@REM Read properties file
+set "CAMEL_PROPERTIES=%CAMEL_WRAPPER_DIR%.camel\camel-wrapper.properties"
+if not exist "%CAMEL_PROPERTIES%" (
+    echo Error: Could not find %CAMEL_PROPERTIES% >&2
+    echo Please run 'camel wrapper' to set up the Camel wrapper. >&2
+    exit /b 1
+)
+
+@REM Parse properties
+set "CAMEL_VERSION="
+set "DISTRIBUTION_URL="
+for /f "usebackq tokens=1,* delims==" %%a in ("%CAMEL_PROPERTIES%") do (
+    if "%%a"=="camel.version" set "CAMEL_VERSION=%%b"
+    if "%%a"=="distributionUrl" set "DISTRIBUTION_URL=%%b"
+)
+
+if "%CAMEL_VERSION%"=="" (
+    echo Error: camel.version not found in %CAMEL_PROPERTIES% >&2
+    exit /b 1
+)
+
+if "%DISTRIBUTION_URL%"=="" (
+    echo Error: distributionUrl not found in %CAMEL_PROPERTIES% >&2
+    exit /b 1
+)
+
+@REM Find Java
+if not "%JAVA_HOME%"=="" goto javaHomeSet
+set "JAVACMD=java"
+goto javaFound
+
+:javaHomeSet
+set "JAVACMD=%JAVA_HOME%\bin\java.exe"
+if not exist "%JAVACMD%" (
+    echo Error: JAVA_HOME is set to an invalid directory: %JAVA_HOME% >&2
+    echo Please set the JAVA_HOME variable in your environment to match the >&2
+    echo location of your Java installation. >&2
+    exit /b 1
+)
+
+:javaFound
+@REM Set up cache directory
+set "CAMEL_CACHE_DIR=%USERPROFILE%\.camel\wrapper"
+set "CAMEL_LAUNCHER_JAR=%CAMEL_CACHE_DIR%\camel-launcher-%CAMEL_VERSION%.jar"
+
+@REM Download launcher jar if needed
+if exist "%CAMEL_LAUNCHER_JAR%" goto runCamel
+
+if not exist "%CAMEL_CACHE_DIR%" mkdir "%CAMEL_CACHE_DIR%"
+echo Downloading Camel Launcher %CAMEL_VERSION%...
+
+@REM Try PowerShell download
+powershell -Command "& { [Net.ServicePointManager]::SecurityProtocol = 
[Net.SecurityProtocolType]::Tls12; Invoke-WebRequest -Uri '%DISTRIBUTION_URL%' 
-OutFile '%CAMEL_LAUNCHER_JAR%' }" >nul 2>&1
+if %ERRORLEVEL% neq 0 (
+    @REM Try curl as fallback
+    curl -fsSL -o "%CAMEL_LAUNCHER_JAR%" "%DISTRIBUTION_URL%" >nul 2>&1
+    if %ERRORLEVEL% neq 0 (
+        echo Error: Failed to download Camel Launcher from %DISTRIBUTION_URL% 
>&2
+        del /f "%CAMEL_LAUNCHER_JAR%" >nul 2>&1
+        exit /b 1
+    )
+)
+
+echo Camel Launcher %CAMEL_VERSION% downloaded successfully.
+
+:runCamel
+"%JAVACMD%" %CAMEL_OPTS% -jar "%CAMEL_LAUNCHER_JAR%" %*
+
+endlocal
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommandTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommandTest.java
new file mode 100644
index 000000000000..db832341a168
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/WrapperCommandTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.common.PathUtils;
+import org.apache.camel.dsl.jbang.core.common.StringPrinter;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class WrapperCommandTest {
+
+    private Path workingDir;
+
+    @BeforeEach
+    public void beforeEach() throws IOException {
+        Path base = Paths.get("target");
+        workingDir = Files.createTempDirectory(base, "camel-wrapper");
+    }
+
+    @AfterEach
+    public void afterEach() throws IOException {
+        PathUtils.deleteDirectory(workingDir);
+    }
+
+    @Test
+    void testWrapperCreatesFiles() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+        cmd.camelVersion = "4.10.0";
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+        
assertTrue(Files.exists(workingDir.resolve(".camel/camel-wrapper.properties")));
+        assertTrue(Files.exists(workingDir.resolve("camelw")));
+        assertTrue(Files.exists(workingDir.resolve("camelw.cmd")));
+    }
+
+    @Test
+    void testWrapperPropertiesContent() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+        cmd.camelVersion = "4.10.0";
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+
+        String properties = 
Files.readString(workingDir.resolve(".camel/camel-wrapper.properties"));
+        assertTrue(properties.contains("camel.version=4.10.0"));
+        assertTrue(properties.contains("distributionUrl="));
+        assertTrue(properties.contains("camel-launcher-4.10.0.jar"));
+    }
+
+    @Test
+    void testWrapperDefaultsToCurrentVersion() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        String expectedVersion = catalog.getCatalogVersion();
+
+        String properties = 
Files.readString(workingDir.resolve(".camel/camel-wrapper.properties"));
+        assertTrue(properties.contains("camel.version=" + expectedVersion));
+    }
+
+    @Test
+    void testWrapperCustomRepoUrl() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+        cmd.camelVersion = "4.10.0";
+        cmd.repoUrl = "https://custom.repo.example.com/maven2";;
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+
+        String properties = 
Files.readString(workingDir.resolve(".camel/camel-wrapper.properties"));
+        
assertTrue(properties.contains("https://custom.repo.example.com/maven2";));
+    }
+
+    @Test
+    void testWrapperScriptContent() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+        cmd.camelVersion = "4.10.0";
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+
+        String camelw = Files.readString(workingDir.resolve("camelw"));
+        assertTrue(camelw.startsWith("#!/bin/sh"));
+        assertTrue(camelw.contains("camel-wrapper.properties"));
+
+        String camelwCmd = Files.readString(workingDir.resolve("camelw.cmd"));
+        assertTrue(camelwCmd.contains("camel-wrapper.properties"));
+    }
+
+    @Test
+    void testBuildDistributionUrl() {
+        CamelJBangMain main = new CamelJBangMain();
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.camelVersion = "4.10.0";
+        cmd.repoUrl = "https://repo1.maven.org/maven2";;
+
+        String url = cmd.buildDistributionUrl();
+        assertEquals(
+                
"https://repo1.maven.org/maven2/org/apache/camel/camel-launcher/4.10.0/camel-launcher-4.10.0.jar";,
+                url);
+    }
+
+    @Test
+    void testWrapperOutputMessages() throws Exception {
+        CamelJBangMain main = new CamelJBangMain();
+        StringPrinter printer = new StringPrinter();
+        main.setOut(printer);
+
+        WrapperCommand cmd = new WrapperCommand(main);
+        cmd.directory = workingDir.toString();
+        cmd.camelVersion = "4.10.0";
+
+        int exit = cmd.doCall();
+
+        assertEquals(0, exit);
+
+        String output = printer.getOutput();
+        assertTrue(output.contains("Apache Camel wrapper installed 
successfully."));
+        assertTrue(output.contains("Camel version: 4.10.0"));
+        assertTrue(output.contains("camelw"));
+    }
+}
diff --git a/pom.xml b/pom.xml
index 6690a991d31b..b8aa2a05bf5d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -368,6 +368,7 @@
                                     <exclude>camel-sbom/*.xml</exclude>
                                     <exclude>doap.rdf</exclude>
                                     <exclude>mvnw*</exclude>
+                                    <exclude>**/camelw</exclude>
                                     
<exclude>**/FileSplitXPathCharsetTest-input.xml</exclude>
                                     <exclude>**/.camel-jbang-run/**</exclude>
                                     
<exclude>**/camel-jbang-run.properties</exclude>

Reply via email to