This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-23441-export-camel-wrapper in repository https://gitbox.apache.org/repos/asf/camel.git
commit 2db9ae06b38eb474508a6880f869954c106ff2b4 Author: Claus Ibsen <[email protected]> AuthorDate: Wed Aug 5 14:19:39 2026 +0200 CAMEL-23441: camel-jbang - Export to support install camel wrapper Add --camel-wrapper option to camel export so the Camel Wrapper scripts are included in the exported project for version pinning, similar to how --maven-wrapper includes the Maven Wrapper. Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../ROOT/pages/camel-jbang-configuration.adoc | 3 +- .../modules/ROOT/pages/camel-jbang-projects.adoc | 29 ++++++++++++++++ .../camel-jbang-dependency-copy.adoc | 1 + .../camel-jbang-dependency-list.adoc | 1 + .../camel-jbang-dependency-update.adoc | 1 + .../pages/jbang-commands/camel-jbang-export.adoc | 1 + .../pages/jbang-commands/camel-jbang-sbom.adoc | 1 + .../META-INF/camel-jbang-commands-metadata.json | 6 ++-- .../camel-jbang-configuration-metadata.json | 1 + .../camel/dsl/jbang/core/commands/Export.java | 4 +++ .../dsl/jbang/core/commands/ExportBaseCommand.java | 34 +++++++++++++++++++ .../dsl/jbang/core/commands/ExportCamelMain.java | 3 ++ .../dsl/jbang/core/commands/ExportQuarkus.java | 3 ++ .../dsl/jbang/core/commands/ExportSpringBoot.java | 3 ++ .../dsl/jbang/core/common/CamelJBangConstants.java | 4 +++ .../camel/dsl/jbang/core/commands/ExportTest.java | 39 ++++++++++++++++++++++ .../core/commands/kubernetes/KubernetesExport.java | 2 ++ .../core/commands/kubernetes/KubernetesRun.java | 1 + 18 files changed, 133 insertions(+), 4 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc index 16d59ff73148..58d8bc24c988 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc @@ -4,13 +4,14 @@ This page covers configuring the Camel CLI — available options, configuration // jbang options: START == Camel CLI configurations -The camel.jbang supports 51 options, which are listed below. +The camel.jbang supports 52 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== | Name | Description | Default | Type | *camel.jbang.camel-version* | The version of Apache Camel to use | | String | *camel.jbang.camelSpringBootVersion* | To use a custom Camel version when running or export to Spring Boot | | String +| *camel.jbang.camelWrapper* | Include Camel Wrapper scripts in the exported project for version pinning | false | boolean | *camel.jbang.classpathFiles* | Additional files to add to classpath (Use commas to separate multiple files). | | String | *camel.jbang.compileWorkDir* | Work directory for compiler. Can be used to write compiled classes or other resources. | .camel-jbang/compile | String | *camel.jbang.console* | Developer console at /q/dev on local HTTP server (port 8080 by default) | false | boolean diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc index 05e53e7039e5..b924553da6c9 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc @@ -93,6 +93,35 @@ camel export bar.xml cheese.yaml --runtime=spring-boot --gav=com.foo:cheese:1.0- NOTE: `application.properties` is included in all exports automatically. +=== Exporting with Camel Wrapper + +Use `--camel-wrapper` to include Camel Wrapper scripts in the exported project. +This works like the Maven Wrapper — it pins a specific Camel CLI version so that anyone +working on the project uses the same version without a separate install: + +[source,bash] +---- +camel export --runtime=spring-boot --gav=com.foo:acme:1.0-SNAPSHOT --camel-wrapper +---- + +This adds the following files to the exported project: + +- `camel` and `camel.cmd` — launcher scripts that download and run the pinned Camel CLI version +- `.camel/camel-wrapper.properties` — contains the pinned `camel.version` and download URL + +The pinned version matches the Camel version used in the export. After exporting, use `./camel` +instead of a globally installed `camel` to ensure the project always uses the correct version. + +You can also set this in `application.properties`: + +[source,properties] +---- +camel.jbang.camelWrapper=true +---- + +TIP: The Camel Wrapper can also be installed standalone with `camel wrapper`. +See xref:camel-jbang-installation.adoc[Installation Options] for details. + === Including JMX management or CLI connector JMX management and CLI connector are not included by default. Add them with `--dep`: diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc index 2149196f292e..73e75c571797 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc @@ -22,6 +22,7 @@ camel dependency copy [options] | `--build-property` | Maven build properties, ex. --build-property=prop1=foo | | List | `--camel-spring-boot-version` | Camel version to use with Spring Boot | | String | `--camel-version` | To export using a different Camel version than the default version. | | String +| `--camel-wrapper` | Include Camel Wrapper scripts in exported project for version pinning | false | boolean | `--clean-dir` | If exporting to current directory (default) then all existing files are preserved. Enabling this option will force cleaning current directory including all sub dirs (use this with care) | false | boolean | `--dep,--dependency` | Add additional dependencies | | List | `--dir,--directory` | Directory where the project will be exported | . | String diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc index a87b96fed253..7c779c5ace2d 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc @@ -22,6 +22,7 @@ camel dependency list [options] | `--build-property` | Maven build properties, ex. --build-property=prop1=foo | | List | `--camel-spring-boot-version` | Camel version to use with Spring Boot | | String | `--camel-version` | To export using a different Camel version than the default version. | | String +| `--camel-wrapper` | Include Camel Wrapper scripts in exported project for version pinning | false | boolean | `--clean-dir` | If exporting to current directory (default) then all existing files are preserved. Enabling this option will force cleaning current directory including all sub dirs (use this with care) | false | boolean | `--dep,--dependency` | Add additional dependencies | | List | `--dir,--directory` | Directory where the project will be exported | . | String 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 bc3ff5357e69..6efe4940e982 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 @@ -22,6 +22,7 @@ camel dependency update [options] | `--build-property` | Maven build properties, ex. --build-property=prop1=foo | | List | `--camel-spring-boot-version` | Camel version to use with Spring Boot | | String | `--camel-version` | To export using a different Camel version than the default version. | | String +| `--camel-wrapper` | Include Camel Wrapper scripts in exported project for version pinning | false | boolean | `--clean` | Regenerate list of dependencies (do not keep existing dependencies). Not supported for pom.xml | | boolean | `--clean-dir` | If exporting to current directory (default) then all existing files are preserved. Enabling this option will force cleaning current directory including all sub dirs (use this with care) | false | boolean | `--dep,--dependency` | Add additional dependencies | | List diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc index 12278c201622..b3ad3dc2c39c 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc @@ -22,6 +22,7 @@ camel export [options] | `--build-property` | Maven build properties, ex. --build-property=prop1=foo | | List | `--camel-spring-boot-version` | Camel version to use with Spring Boot | | String | `--camel-version` | To export using a different Camel version than the default version. | | String +| `--camel-wrapper` | Include Camel Wrapper scripts in exported project for version pinning | false | boolean | `--clean-dir` | If exporting to current directory (default) then all existing files are preserved. Enabling this option will force cleaning current directory including all sub dirs (use this with care) | false | boolean | `--dep,--dependency` | Add additional dependencies | | List | `--dir,--directory` | Directory where the project will be exported | . | String diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc index d0540d8eabbd..2e28d215b7e4 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc @@ -22,6 +22,7 @@ camel sbom [options] | `--build-property` | Maven build properties, ex. --build-property=prop1=foo | | List | `--camel-spring-boot-version` | Camel version to use with Spring Boot | | String | `--camel-version` | To export using a different Camel version than the default version. | | String +| `--camel-wrapper` | Include Camel Wrapper scripts in exported project for version pinning | false | boolean | `--clean-dir` | If exporting to current directory (default) then all existing files are preserved. Enabling this option will force cleaning current directory including all sub dirs (use this with care) | false | boolean | `--cyclonedx-plugin-version` | The CycloneDX Maven Plugin version | 2.9.1 | String | `--dep,--dependency` | Add additional dependencies | | List 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 cda747041dbc..aa34ac5e55bf 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 @@ -7,14 +7,14 @@ { "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": "dev", "fullName": "dev", "description": "Run in dev mode with live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", "options": [ { "names": "--background", "description": "Run in the background", "defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": "--background-wait", "description": "To wait for run in background to startup successfully, before returning", "defaultValue": "true", "javaType": "boolean", "type": "boolean" }, [...] { "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": "doctor", "fullName": "doctor", "description": "Checks the environment and reports potential issues", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Doctor", "options": [ { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ] }, { "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 [...] { "name": "explain", "fullName": "explain", "description": "Explain what a Camel route does using AI\/LLM", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Explain", "options": [ { "names": "--api-key", "description": "API key for authentication. Also reads ANTHROPIC_API_KEY, OPENAI_API_KEY, WATSONX_APIKEY, or LLM_API_KEY env vars", "javaType": "java.lang.String", "type": "string" }, { "names": "--api-type", "description": "API type: 'ollama', 'openai' (OpenAI-compatible), ' [...] - { "name": "export", "fullName": "export", "description": "Export to other runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": "--build-property", "description": "Maven build properties, ex. --build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { "names": "--camel-spring-boot-version", "description": "Camel version to use with Spring Boot", "javaType": "java.lang.String", "ty [...] + { "name": "export", "fullName": "export", "description": "Export to other runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": "--build-property", "description": "Maven build properties, ex. --build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { "names": "--camel-spring-boot-version", "description": "Camel version to use with Spring Boot", "javaType": "java.lang.String", "ty [...] { "name": "get", "fullName": "get", "description": "Get status of Camel integrations", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { "names": "--watch", "description": "Execute periodically and showing output fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "activity", "fullName": " [...] { "name": "harden", "fullName": "harden", "description": "Suggest security hardening for Camel routes using AI\/LLM", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Harden", "options": [ { "names": "--api-key", "description": "API key for authentication. Also reads OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", "type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", [...] { "name": "hawtio", "fullName": "hawtio", "description": "Launch Hawtio web console", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Hawtio", "options": [ { "names": "--host", "description": "Hostname to bind the Hawtio web console to", "defaultValue": "127.0.0.1", "javaType": "java.lang.String", "type": "string" }, { "names": "--openUrl", "description": "To automatic open Hawtio web console in the web browser", "defaultValue": "true", "javaType": "boolean", "type": [...] @@ -27,7 +27,7 @@ { "name": "ps", "fullName": "ps", "description": "List running Camel integrations", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { "names": "--json", "description": "Output in JSON Format", "javaType": "boolean", "type": "boolean" }, { "names": "--pid", "description": "List only pid in the output", "javaType": "boolean", "type": "boolean" }, { "names": "--remote", "description": "Break down counters into remote\/total pairs", "javaType": [...] { "name": "restart", "fullName": "restart", "description": "Restarts running Camel integrations (stop + re-launch)", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.RestartProcess", "options": [ { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ] }, { "name": "run", "fullName": "run", "description": "Run as local Camel integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", "options": [ { "names": "--background", "description": "Run in the background", "defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": "--background-wait", "description": "To wait for run in background to startup successfully, before returning", "defaultValue": "true", "javaType": "boolean", "type": "boolean" }, { [...] - { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX or SPDX SBOM for a specific project", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { "names": "--build-property", "description": "Maven build properties, ex. --build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { "names": "--camel-spring-boot-version", "description": "Camel version to use with Spring Boot", "javaType": "java.lang.String", "type" [...] + { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX or SPDX SBOM for a specific project", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { "names": "--build-property", "description": "Maven build properties, ex. --build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { "names": "--camel-spring-boot-version", "description": "Camel version to use with Spring Boot", "javaType": "java.lang.String", "type" [...] { "name": "script", "fullName": "script", "description": "Run Camel integration as shell script for terminal scripting", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Script", "options": [ { "names": "--logging", "description": "Can be used to turn on logging (logs to file in <user home>\/.camel directory)", "defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": "--logging-level", "description": "Logging level (ERROR, WARN, INFO, DEBUG, TRACE)", "d [...] { "name": "shell", "fullName": "shell", "description": "Interactive Camel CLI shell.", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Shell", "options": [ { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ] }, { "name": "stop", "fullName": "stop", "description": "Shuts down running Camel integrations", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.StopProcess", "options": [ { "names": "--kill", "description": "To force killing the process (SIGKILL)", "javaType": "boolean", "type": "boolean" }, { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ] }, diff --git a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json index 2009c64f7a0c..f4b422e1b40c 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json +++ b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json @@ -5,6 +5,7 @@ "properties": [ { "name": "camel.jbang.camel-version", "required": false, "description": "The version of Apache Camel to use", "type": "string", "javaType": "String", "secret": false }, { "name": "camel.jbang.camelSpringBootVersion", "required": false, "description": "To use a custom Camel version when running or export to Spring Boot", "label": "spring-boot", "type": "string", "javaType": "String", "secret": false }, + { "name": "camel.jbang.camelWrapper", "required": false, "description": "Include Camel Wrapper scripts in the exported project for version pinning", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.jbang.classpathFiles", "required": false, "description": "Additional files to add to classpath (Use commas to separate multiple files).", "type": "string", "javaType": "String", "secret": false }, { "name": "camel.jbang.compileWorkDir", "required": false, "description": "Work directory for compiler. Can be used to write compiled classes or other resources.", "label": "advanced", "type": "string", "javaType": "String", "defaultValue": ".camel-jbang\/compile", "secret": false }, { "name": "camel.jbang.console", "required": false, "description": "Developer console at \/q\/dev on local HTTP server (port 8080 by default)", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java index f7538ec227ff..32ed859614af 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java @@ -39,6 +39,7 @@ import picocli.CommandLine.Command; import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.CAMEL_SPRING_BOOT_VERSION; import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.CAMEL_VERSION; +import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.CAMEL_WRAPPER; import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.EXCLUDES; import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.EXPORT_DIR; import static org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.GAV; @@ -202,6 +203,8 @@ public class Export extends ExportBaseCommand { this.springBootVersion = props.getProperty(SPRING_BOOT_VERSION, this.springBootVersion); this.mavenWrapper = "true".equals(props.getProperty(MAVEN_WRAPPER, this.mavenWrapper ? "true" : "false")); + this.camelWrapper + = "true".equals(props.getProperty(CAMEL_WRAPPER, this.camelWrapper ? "true" : "false")); this.exportDir = props.getProperty(EXPORT_DIR, this.exportDir); this.openapi = props.getProperty(OPEN_API, this.openapi); this.mavenResolver = MavenResolverMixin.of(props, this.mavenResolver); @@ -259,6 +262,7 @@ public class Export extends ExportBaseCommand { cmd.quarkusPackageType = this.quarkusPackageType; cmd.springBootVersion = this.springBootVersion; cmd.mavenWrapper = this.mavenWrapper; + cmd.camelWrapper = this.camelWrapper; cmd.docker = this.docker; cmd.quiet = this.quiet; cmd.buildProperties = this.buildProperties; diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java index 6fe3c6fa9f59..272df1fbe6b2 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java @@ -207,6 +207,10 @@ public abstract class ExportBaseCommand extends CamelCommand { description = "Include Maven Wrapper files in exported project") protected boolean mavenWrapper = true; + @CommandLine.Option(names = { "--camel-wrapper" }, defaultValue = "false", + description = "Include Camel Wrapper scripts in exported project for version pinning") + protected boolean camelWrapper; + @CommandLine.Option(names = { "--docker" }, defaultValue = "true", description = "Include Docker files in exported project") protected boolean docker = true; @@ -1189,6 +1193,36 @@ public abstract class ExportBaseCommand extends CamelCommand { FileUtil.setPosixFilePermissions(mvnwCmdPath, "rwxr-xr-x"); } + protected void copyCamelWrapper() throws Exception { + Path camelDir = Paths.get(BUILD_DIR, ".camel"); + Files.createDirectories(camelDir); + + // write camel-wrapper.properties with the export's camel version + String distributionUrl = "https://repo1.maven.org/maven2" + + "/org/apache/camel/camel-launcher/" + + camelVersion + + "/camel-launcher-" + + camelVersion + + ".jar"; + String content = "camel.version=" + camelVersion + "\n" + + "distributionUrl=" + distributionUrl + "\n"; + Files.writeString(camelDir.resolve("camel-wrapper.properties"), content); + + // copy wrapper scripts + Path camelPath = Paths.get(BUILD_DIR, "camel"); + Path camelCmdPath = Paths.get(BUILD_DIR, "camel.cmd"); + try (InputStream is = ExportBaseCommand.class.getClassLoader().getResourceAsStream("camel-wrapper/camelw")) { + Files.copy(is, camelPath, StandardCopyOption.REPLACE_EXISTING); + } + try (InputStream is = ExportBaseCommand.class.getClassLoader().getResourceAsStream("camel-wrapper/camelw.cmd")) { + Files.copy(is, camelCmdPath, StandardCopyOption.REPLACE_EXISTING); + } + + // set execute file permission on camel/camel.cmd files + FileUtil.setPosixFilePermissions(camelPath, "rwxr-xr-x"); + FileUtil.setPosixFilePermissions(camelCmdPath, "rwxr-xr-x"); + } + protected String applicationPropertyLine(String key, String value) { return key + "=" + value; } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java index 2f84107492c3..339f0985a139 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java @@ -172,6 +172,9 @@ class ExportCamelMain extends Export { if (mavenWrapper) { copyMavenWrapper(); } + if (camelWrapper) { + copyCamelWrapper(); + } if (docker) { copyDockerFiles(BUILD_DIR); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java index 652843f5ae02..7da2264a211e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java @@ -173,6 +173,9 @@ class ExportQuarkus extends Export { if (mavenWrapper) { copyMavenWrapper(); } + if (camelWrapper) { + copyCamelWrapper(); + } if (cleanExportDir || !exportDir.equals(".")) { // cleaning current dir can be a bit dangerous so only clean if explicit enabled diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java index 5da20b8589e5..ecb772df57e9 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java @@ -166,6 +166,9 @@ class ExportSpringBoot extends Export { if (mavenWrapper) { copyMavenWrapper(); } + if (camelWrapper) { + copyCamelWrapper(); + } if (docker) { copyDockerFiles(BUILD_DIR); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java index 334cd054afb5..b95d4668448c 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java @@ -110,6 +110,10 @@ public final class CamelJBangConstants { javaType = "boolean", defaultValue = "true") public static final String MAVEN_WRAPPER = "camel.jbang.mavenWrapper"; + @Metadata(description = "Include Camel Wrapper scripts in the exported project for version pinning", + javaType = "boolean", defaultValue = "false") + public static final String CAMEL_WRAPPER = "camel.jbang.camelWrapper"; + @Metadata(description = "Directory where the project will be exported", javaType = "String", defaultValue = ".") public static final String EXPORT_DIR = "camel.jbang.exportDir"; diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java index e4b45890ae7b..9685fdba7ffc 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java @@ -505,6 +505,45 @@ class ExportTest { Assertions.assertTrue(new File(workingDir, "AGENTS.md").exists(), "Missing AGENTS.md"); } + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldExportCamelWrapper(RuntimeType rt) throws Exception { + LOG.info("shouldExportCamelWrapper {}", rt); + Export command = createCommand(rt, new String[] { "src/test/resources/route.yaml" }, + "--gav=examples:route:1.0.0", "--dir=" + workingDir, "--quiet", "--camel-wrapper"); + int exit = command.doCall(); + + Assertions.assertEquals(0, exit); + Assertions.assertTrue(new File(workingDir, "camel").exists(), "Missing camel wrapper script"); + Assertions.assertTrue(new File(workingDir, "camel.cmd").exists(), "Missing camel.cmd wrapper script"); + Assertions.assertTrue(new File(workingDir, ".camel/camel-wrapper.properties").exists(), + "Missing .camel/camel-wrapper.properties"); + + String properties = Files.readString(workingDir.toPath().resolve(".camel/camel-wrapper.properties")); + assertThat(properties).contains("camel.version="); + assertThat(properties).contains("distributionUrl="); + assertThat(properties).contains("camel-launcher-"); + + String camelScript = Files.readString(workingDir.toPath().resolve("camel")); + assertThat(camelScript).startsWith("#!/bin/sh"); + assertThat(camelScript).contains("camel-wrapper.properties"); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldNotExportCamelWrapperByDefault(RuntimeType rt) throws Exception { + LOG.info("shouldNotExportCamelWrapperByDefault {}", rt); + Export command = createCommand(rt, new String[] { "src/test/resources/route.yaml" }, + "--gav=examples:route:1.0.0", "--dir=" + workingDir, "--quiet"); + int exit = command.doCall(); + + Assertions.assertEquals(0, exit); + Assertions.assertFalse(new File(workingDir, "camel").exists(), + "Camel wrapper script should not exist by default"); + Assertions.assertFalse(new File(workingDir, ".camel/camel-wrapper.properties").exists(), + "Camel wrapper properties should not exist by default"); + } + @ParameterizedTest @MethodSource("runtimeProvider") public void shouldSkipDockerFiles(RuntimeType rt) throws Exception { diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java index 57243c453ba6..89f027806e8c 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java @@ -179,6 +179,7 @@ public class KubernetesExport extends Export { javaLiveReload = configurer.javaLiveReload; ignoreLoadingError = configurer.ignoreLoadingError; mavenWrapper = configurer.mavenWrapper; + camelWrapper = configurer.camelWrapper; skipPlugins = configurer.skipPlugins; packageScanJars = configurer.packageScanJars; quiet = configurer.quiet; @@ -655,6 +656,7 @@ public class KubernetesExport extends Export { boolean javaLiveReload, boolean ignoreLoadingError, boolean mavenWrapper, + boolean camelWrapper, boolean fresh, boolean download, boolean packageScanJars, diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java index d4aad60ce30c..f2355b240ac7 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java @@ -480,6 +480,7 @@ public class KubernetesRun extends KubernetesBaseCommand { true, true, false, + false, mavenResolver.download(), packageScanJars, (quiet || output != null),
