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 8d0206b4b5a3 CAMEL-25417: camel-jbang - An opened folder run with F10
is linked to its app by the launched process (#27499)
8d0206b4b5a3 is described below
commit 8d0206b4b5a3a93938011d0f3252d787595700c8
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Oct 7 14:45:29 2026 +0200
CAMEL-25417: camel-jbang - An opened folder run with F10 is linked to its
app by the launched process (#27499)
An opened project was linked to its running app by directory only. A
folder of route files runs from the working directory of the monitor, or
from a copy in .camel-jbang-run when a runtime is chosen, so its app does
not report the project folder, and the project stayed listed as Starting
next to it. The monitor now keeps the process F10 launched, and the app
whose pid is that process or a descendant of it stands in for the project.
Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
.../dsl/jbang/core/commands/tui/ActionsPopup.java | 9 ++++----
.../core/commands/tui/DataRefreshService.java | 24 ++++++++++++++++++++
.../jbang/core/commands/tui/IntegrationInfo.java | 2 ++
.../dsl/jbang/core/commands/tui/LaunchManager.java | 15 +++++++++++--
.../commands/tui/OpenedProjectLifecycleTest.java | 26 ++++++++++++++++++++++
5 files changed, 69 insertions(+), 7 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
index 000c2c44fa3c..da1cd007a013 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
@@ -1326,11 +1326,10 @@ class ActionsPopup {
// the project stays listed (Starting) until its app shows up and
stands in for it
phantom.startingSince = System.currentTimeMillis();
- if (phantom.projectType != null) {
- launchManager.launchMavenProject(phantom.sourceDir,
phantom.projectType, displayName, extraArgs);
- } else {
- launchManager.launchCamelRun(phantom.sourceDir, displayName,
extraArgs);
- }
+ // the app is found by the process it runs in: a folder runs from
elsewhere, and reports another directory
+ phantom.launchedProcess = phantom.projectType != null
+ ? launchManager.launchMavenProject(phantom.sourceDir,
phantom.projectType, displayName, extraArgs)
+ : launchManager.launchCamelRun(phantom.sourceDir, displayName,
extraArgs);
}
// ---- Name Input ----
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
index 789b2f7ad14b..426a9acbc3d1 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
@@ -409,6 +409,9 @@ class DataRefreshService {
.collect(Collectors.toMap(i -> i.directory, i -> i, (a, b) ->
a.vanishing ? b : a));
for (IntegrationInfo phantom : phantoms) {
IntegrationInfo live = phantom.sourceDir != null ?
liveDirs.get(phantom.sourceDir) : null;
+ if (live == null) {
+ live = launchedApp(phantom, infos);
+ }
if (live != null) {
if (phantom.pid.equals(ctx.selectedPid) && !live.vanishing) {
ctx.selectedPid = live.pid;
@@ -428,6 +431,27 @@ class DataRefreshService {
}
}
+ /**
+ * The app F10 launched for the project: the launched process or a
descendant of it. A folder of route files runs
+ * from the working directory of the monitor, or from a copy in
.camel-jbang-run when a runtime is chosen, so its
+ * app does not report the project folder as its directory (CAMEL-25417).
+ */
+ static IntegrationInfo launchedApp(IntegrationInfo phantom,
List<IntegrationInfo> infos) {
+ ProcessHandle launched = phantom.launchedProcess;
+ if (launched == null) {
+ return null;
+ }
+ java.util.Set<String> pids = new java.util.HashSet<>();
+ pids.add(Long.toString(launched.pid()));
+ launched.descendants().forEach(p -> pids.add(Long.toString(p.pid())));
+ for (IntegrationInfo info : infos) {
+ if (!info.phantom && info.pid != null && pids.contains(info.pid)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
private void mergePhantoms(List<IntegrationInfo> infos) {
mergePhantoms(infos, ctx.phantomIntegrations, ctx);
}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/IntegrationInfo.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/IntegrationInfo.java
index e2bdef4aec27..6d8b42ff28ee 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/IntegrationInfo.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/IntegrationInfo.java
@@ -39,6 +39,8 @@ class IntegrationInfo {
String openedAs;
// an opened project: when it was asked to run, until its app shows up (or
the launch fails)
long startingSince;
+ // the process F10 launched for an opened project: its app is that process
or a descendant of it (CAMEL-25417)
+ ProcessHandle launchedProcess;
String projectType;
String sourceDir;
String ready;
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 d9a53829aa90..574c0c4c0e4f 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
@@ -284,8 +284,10 @@ class LaunchManager {
/**
* Runs an existing Maven project via {@code camel run pom.xml}, which
detects the runtime, injects the CLI
* connector, and logs to a file in {@code ~/.camel} that the Log tab
reads (the same for all runtimes).
+ *
+ * @return the launched process, or null when it did not start
*/
- void launchMavenProject(String dir, String projectType, String
displayName, List<String> extraArgs) {
+ ProcessHandle launchMavenProject(String dir, String projectType, String
displayName, List<String> extraArgs) {
try {
List<String> cmd = new
ArrayList<>(LauncherHelper.getCamelCommand());
cmd.add("run");
@@ -300,12 +302,19 @@ class LaunchManager {
Process process = pb.start();
addPendingLaunch(displayName, process, outputFile);
notify("Starting: " + displayName + " (" + projectType + ")",
false);
+ return process.toHandle();
} catch (Exception e) {
notify("Failed to start Maven project: " + e.getMessage(), true);
+ return null;
}
}
- void launchCamelRun(String sourceDir, String displayName, List<String>
extraArgs) {
+ /**
+ * Runs a folder of route files with camel run --source-dir.
+ *
+ * @return the launched process, or null when it did not start
+ */
+ ProcessHandle launchCamelRun(String sourceDir, String displayName,
List<String> extraArgs) {
try {
List<String> cmd = new
ArrayList<>(LauncherHelper.getCamelCommand());
cmd.add("run");
@@ -320,8 +329,10 @@ class LaunchManager {
Process process = pb.start();
addPendingLaunch(displayName, process, outputFile);
notify("Starting: " + displayName, false);
+ return process.toHandle();
} catch (Exception e) {
notify("Failed to start: " + sourceDir + " - " + e.getMessage(),
true);
+ return null;
}
}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/OpenedProjectLifecycleTest.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/OpenedProjectLifecycleTest.java
index 763abd87f5c8..90c51c49ff98 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/OpenedProjectLifecycleTest.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/OpenedProjectLifecycleTest.java
@@ -66,6 +66,32 @@ class OpenedProjectLifecycleTest {
assertEquals(project.pid, ctx.selectedPid);
}
+ @Test
+ void aFolderRunWithF10IsFoundByItsProcess() {
+ // CAMEL-25417: a folder of route files runs from the working
directory of the monitor (or from a copy in
+ // .camel-jbang-run), so its app does not report the project folder:
it is found by the launched process
+ IntegrationInfo project = new IntegrationInfo();
+ project.name = "custom-kamelet";
+ project.sourceDir = "/work/custom-kamelet";
+ project.startingSince = System.currentTimeMillis();
+ project.launchedProcess = ProcessHandle.current();
+ ctx.addPhantom(project);
+ ctx.selectedPid = project.pid;
+
+ IntegrationInfo app =
running(Long.toString(ProcessHandle.current().pid()), "custom-kamelet",
+ "/home/me/.camel-jbang-run/1791375674390");
+ List<IntegrationInfo> infos = merge(app);
+ assertFalse(infos.contains(project));
+ assertEquals(app.pid, ctx.selectedPid);
+ assertEquals("custom-kamelet", app.openedAs);
+ assertEquals(0, project.startingSince);
+
+ // another app with the same name, not launched for the project, does
not stand in for it
+ IntegrationInfo other = running("4242", "custom-kamelet",
"/elsewhere");
+ project.launchedProcess = null;
+ assertTrue(merge(other).contains(project));
+ }
+
@Test
void aProjectIsStartingUntilItsAppShowsUp() {
IntegrationInfo project = new IntegrationInfo();