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 c6e819023cd8 CAMEL-25236: camel-jbang - camel run --example runs the
example in its own folder, wherever camel run is started (#27266)
c6e819023cd8 is described below
commit c6e819023cd896e45d1bd073b790866c56e04a25
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Oct 2 11:17:47 2026 +0200
CAMEL-25236: camel-jbang - camel run --example runs the example in its own
folder, wherever camel run is started (#27266)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../ROOT/pages/camel-jbang-getting-started.adoc | 3 +
.../apache/camel/dsl/jbang/core/commands/Run.java | 73 +++++++++++++---------
.../camel/dsl/jbang/core/common/ExampleHelper.java | 24 +++++++
.../dsl/jbang/core/common/ExampleHelperTest.java | 25 ++++++++
.../dsl/jbang/core/commands/tui/LaunchManager.java | 14 +----
5 files changed, 96 insertions(+), 43 deletions(-)
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-jbang-getting-started.adoc
b/docs/user-manual/modules/ROOT/pages/camel-jbang-getting-started.adoc
index 8b943bf42372..d97406348b16 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-getting-started.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-getting-started.adoc
@@ -119,6 +119,9 @@ camel run --example=rest-api --dev
TIP: Combine with `--dev` for live reload while exploring the example.
+An example runs in a folder of its own, with its files, wherever you start
`camel run`. A route that reads `orders`
+or writes to `out/` uses the folder of the example, which `camel run` prints
when it starts.
+
=== Running multiple files
You can run several files together, even mixing DSLs:
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 06cc2dade192..39f92ce7a567 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
@@ -536,31 +536,12 @@ public class Run extends CamelCommand {
}
private int runBundledExample(JsonObject entry) throws Exception {
- String eName = entry.getString("name");
Path tempDir = ExampleHelper.extractBundledExample(entry);
- List<String> exampleFiles = ExampleHelper.getFiles(entry);
-
- printer().println("Running example: " + eName);
- for (String f : exampleFiles) {
- files.add(tempDir.resolve(f).toString());
- }
- if ("CamelJBang".equals(name)) {
- name = eName;
- }
-
- // use the temp dir as base so run() loads the example's
application.properties
- exportBaseDir = tempDir;
-
- if (!exportRun) {
- printConfigurationValues("Running integration with the following
configuration:");
- }
- return run();
+ return runExampleIn(entry, tempDir);
}
private int runGithubExample(JsonObject entry) throws Exception {
String eName = entry.getString("name");
- List<String> exampleFiles = ExampleHelper.getFiles(entry);
-
printer().println("Fetching example from GitHub: " + eName);
if (ExampleHelper.requiresDocker(entry)) {
printer().println("Note: this example requires Docker/Podman");
@@ -574,20 +555,52 @@ public class Run extends CamelCommand {
printer().printErr("This example requires an internet
connection.");
return 1;
}
+ return runExampleIn(entry, tempDir);
+ }
- for (String f : exampleFiles) {
- files.add(tempDir.resolve(f).toString());
- }
- if ("CamelJBang".equals(name)) {
- name = eName;
+ /**
+ * Runs the example in its folder. A JVM cannot change its working
directory, so the example runs in a JVM of its
+ * own started in that folder: its routes read and write files relative to
it (file:orders, out/), wherever camel
+ * run is started (CAMEL-25236). Exporting and transforming do not run the
routes, and stay in this JVM.
+ */
+ private int runExampleIn(JsonObject entry, Path dir) throws Exception {
+ String eName = entry.getString("name");
+ printer().println("Running example: " + eName);
+ if (exportRun || transformRun || spec == null) {
+ for (String f : ExampleHelper.getFiles(entry)) {
+ files.add(dir.resolve(f).toString());
+ }
+ if ("CamelJBang".equals(name)) {
+ name = ExampleHelper.getShortName(entry);
+ }
+ // use the folder as base so run() loads the example's
application.properties
+ exportBaseDir = dir;
+ return run();
}
- exportBaseDir = tempDir;
-
- if (!exportRun) {
- printConfigurationValues("Running integration with the following
configuration:");
+ printer().println("Example folder: " + dir + " (the files it reads and
writes are there)");
+ List<String> cmds =
ExampleHelper.runArgs(spec.commandLine().getParseResult().originalArgs(),
entry);
+ RunHelper.addCamelCLICommand(cmds);
+ if (verbose) {
+ printer().println(String.join(" ", cmds));
+ }
+ ProcessBuilder pb = new ProcessBuilder(cmds);
+ pb.directory(dir.toFile());
+ pb.inheritIO(); // run in foreground (with IO so logs are visible)
+ Process p = pb.start();
+ this.spawnPid = p.pid();
+ // the example stops with this JVM (Ctrl+C reaches both, a kill of
this one only this one)
+ Thread hook = new Thread(p::destroy, "CamelExampleStop");
+ Runtime.getRuntime().addShutdownHook(hook);
+ try {
+ return p.waitFor();
+ } finally {
+ try {
+ Runtime.getRuntime().removeShutdownHook(hook);
+ } catch (IllegalStateException e) {
+ // shutting down already
+ }
}
- return run();
}
// the logback configuration of an existing Spring Boot project run, in a
temp file
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
index febdca5fd094..bd2449a2fce5 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
@@ -377,6 +377,30 @@ public final class ExampleHelper {
return slash > 0 ? name.substring(slash + 1) : name != null ? name :
"";
}
+ /**
+ * The arguments of a camel run of an example, for a process started in
the folder of the example: --example=name
+ * (or --example name) replaced by the files of the example, and its name
unless one is given (CAMEL-25236).
+ */
+ public static List<String> runArgs(List<String> args, JsonObject example) {
+ List<String> answer = new ArrayList<>();
+ boolean named = args.stream().anyMatch(a -> a.equals("--name") ||
a.startsWith("--name="));
+ for (int i = 0; i < args.size(); i++) {
+ String a = args.get(i);
+ if (a.equals("--example") || a.startsWith("--example=")) {
+ if (a.equals("--example") && i + 1 < args.size()) {
+ i++; // its value
+ }
+ answer.addAll(getFiles(example));
+ if (!named) {
+ answer.add("--name=" + getShortName(example));
+ }
+ } else {
+ answer.add(a);
+ }
+ }
+ return answer;
+ }
+
public static boolean isBundled(JsonObject entry) {
Boolean bundled = entry.getBoolean("bundled");
return bundled != null && bundled;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ExampleHelperTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ExampleHelperTest.java
index bd6c3b626c8e..40a4e0fcfa60 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ExampleHelperTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ExampleHelperTest.java
@@ -249,4 +249,29 @@ class ExampleHelperTest {
assertTrue(names.contains("mqtt"));
assertTrue(names.contains("aws-sqs"));
}
+
+ @Test
+ void runArgsOfAnExample() {
+ JsonObject example =
ExampleHelper.findExample(ExampleHelper.loadCatalog(),
"route/content-based-router");
+ List<String> files = ExampleHelper.getFiles(example);
+
+ // --example=name: its files and its short name, the other options kept
+ List<String> args = ExampleHelper.runArgs(List.of("run",
"--example=route/content-based-router", "--dev"), example);
+ assertEquals("run", args.get(0));
+ assertTrue(args.containsAll(files));
+ assertTrue(args.contains("--name=content-based-router"));
+ assertTrue(args.contains("--dev"));
+ assertFalse(args.stream().anyMatch(a -> a.startsWith("--example")));
+
+ // --example name: the value goes too
+ args = ExampleHelper.runArgs(List.of("run", "--example",
"route/content-based-router", "--dev"), example);
+ assertFalse(args.contains("route/content-based-router"));
+ assertTrue(args.containsAll(files));
+ assertTrue(args.contains("--dev"));
+
+ // a name given is kept as the only one
+ args = ExampleHelper.runArgs(List.of("run",
"--example=content-based-router", "--name", "cbr"), example);
+ assertTrue(args.contains("cbr"));
+ assertFalse(args.contains("--name=content-based-router"));
+ }
}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
index 482b294ec597..d9a53829aa90 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
@@ -148,19 +148,7 @@ class LaunchManager {
/** The arguments with --example=name replaced by the files of the
example, and its name unless one is given. */
static List<String> exampleArgs(List<String> args, JsonObject example) {
- List<String> answer = new ArrayList<>();
- boolean named = args.stream().anyMatch(a -> a.startsWith("--name"));
- for (String a : args) {
- if (a.startsWith("--example=")) {
- answer.addAll(ExampleHelper.getFiles(example));
- if (!named) {
- answer.add("--name=" +
TuiHelper.stripCategory(example.getString("name")));
- }
- } else {
- answer.add(a);
- }
- }
- return answer;
+ return ExampleHelper.runArgs(args, example);
}
void addPendingLaunch(String name, Process process, Path outputFile) {