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 40eef1cf61b CAMEL-21637: camel-jbang - Commands in watch mode should
wait for user input to exit which makes them also work in shell mode. (#16871)
40eef1cf61b is described below
commit 40eef1cf61b48fdd5944e076c6a3d029cb952dde
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jan 21 12:01:07 2025 +0100
CAMEL-21637: camel-jbang - Commands in watch mode should wait for user
input to exit which makes them also work in shell mode. (#16871)
---
.../dsl/jbang/core/commands/CamelCommand.java | 2 +-
.../dsl/jbang/core/commands/CommandHelper.java | 25 +++++++++++++++++++---
.../camel/dsl/jbang/core/commands/Shell.java | 15 ++++++++-----
.../core/commands/action/ActionWatchCommand.java | 23 ++++++++++++++++++--
.../jbang/core/commands/action/CamelLogAction.java | 14 ++++++++++--
.../core/commands/action/CamelReceiveAction.java | 16 +++++++++++---
.../core/commands/action/CamelTraceAction.java | 14 ++++++++++--
.../core/commands/process/ProcessWatchCommand.java | 23 ++++++++++++++++++--
8 files changed, 112 insertions(+), 20 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
index 7667dbefc4b..188c9abd295 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
@@ -123,7 +123,7 @@ public abstract class CamelCommand implements
Callable<Integer> {
protected Printer printer() {
var out = getMain().getOut();
- CommandHelper.SetPrinter(out);
+ CommandHelper.setPrinter(out);
return out;
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
index 464e2e9019a..c14cf3bfc24 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CommandHelper.java
@@ -23,16 +23,16 @@ import org.apache.camel.util.FileUtil;
public final class CommandHelper {
- private static ThreadLocal<Printer> printerAssociation = new
ThreadLocal<>();
+ private static final ThreadLocal<Printer> printerAssociation = new
ThreadLocal<>();
private CommandHelper() {
}
- public static Printer GetPrinter() {
+ public static Printer getPrinter() {
return printerAssociation.get();
}
- public static void SetPrinter(Printer out) {
+ public static void setPrinter(Printer out) {
printerAssociation.set(out);
}
@@ -53,4 +53,23 @@ public final class CommandHelper {
}
}
}
+
+ /**
+ * A background task that reads from console, and can be used to signal
when user has entered or pressed ctrl + c /
+ * ctrl + d
+ */
+ public static class ReadConsoleTask implements Runnable {
+
+ private final Runnable listener;
+
+ public ReadConsoleTask(Runnable listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void run() {
+ System.console().readLine();
+ listener.run();
+ }
+ }
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java
index 9add8063153..f3c95a1563b 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java
@@ -42,7 +42,7 @@ import picocli.shell.jline3.PicocliCommands;
@CommandLine.Command(name = "shell",
description = "Interactive Camel JBang shell. Hit
@|magenta <TAB>|@ to see available commands.",
- footer = "Press Ctrl-D to exit.")
+ footer = "Press Ctrl-C to exit.")
public class Shell extends CamelCommand {
public Shell(CamelJBangMain main) {
@@ -86,17 +86,22 @@ public class Shell extends CamelCommand {
String prompt = "camel> ";
String rightPrompt = null;
- // start the shell and process input until the user quits with
Ctrl-D
+ // start the shell and process input until the user quits with
Ctrl-C or Ctrl-D
String line;
- while (true) {
+ boolean run = true;
+ while (run) {
try {
systemRegistry.cleanUp();
line = reader.readLine(prompt, rightPrompt,
(MaskingCallback) null, null);
systemRegistry.execute(line);
+ } catch (SystemRegistryImpl.UnknownCommandException e) {
+ // ignore
} catch (UserInterruptException e) {
- // Ignore
+ // ctrl + c is pressed so exit
+ run = false;
} catch (EndOfFileException e) {
- break;
+ // ctrl + d is pressed so exit
+ run = false;
} catch (Exception e) {
systemRegistry.trace(e);
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
index 0e979c4df96..ae1baebd033 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
@@ -16,7 +16,11 @@
*/
package org.apache.camel.dsl.jbang.core.commands.action;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
+import org.apache.camel.util.StopWatch;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;
import picocli.CommandLine;
@@ -27,6 +31,8 @@ abstract class ActionWatchCommand extends ActionBaseCommand {
description = "Execute periodically and showing output
fullscreen")
boolean watch;
+ private CommandHelper.ReadConsoleTask waitUserTask;
+
public ActionWatchCommand(CamelJBangMain main) {
super(main);
}
@@ -34,14 +40,27 @@ abstract class ActionWatchCommand extends ActionBaseCommand
{
@Override
public Integer doCall() throws Exception {
int exit;
+ final AtomicBoolean running = new AtomicBoolean(true);
if (watch) {
+ Thread t = new Thread(() -> {
+ waitUserTask = new CommandHelper.ReadConsoleTask(() ->
running.set(false));
+ waitUserTask.run();
+ }, "WaitForUser");
+ t.start();
do {
exit = doWatchCall();
if (exit == 0) {
// use 2-sec delay in watch mode
- Thread.sleep(2000);
+ try {
+ StopWatch watch = new StopWatch();
+ while (running.get() && watch.taken() < 2000) {
+ Thread.sleep(100);
+ }
+ } catch (Exception e) {
+ running.set(false);
+ }
}
- } while (exit == 0);
+ } while (exit == 0 && running.get());
} else {
exit = doWatchCall();
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
index 31b282c6eef..e390af4cf48 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
@@ -34,10 +34,12 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import org.apache.camel.catalog.impl.TimePatternConverter;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
import org.apache.camel.util.StopWatch;
@@ -56,6 +58,8 @@ public class CamelLogAction extends ActionBaseCommand {
private static final String TIMESTAMP_MAIN = "yyyy-MM-dd HH:mm:ss.SSS";
+ private CommandHelper.ReadConsoleTask waitUserTask;
+
public static class PrefixCompletionCandidates implements Iterable<String>
{
public PrefixCompletionCandidates() {
@@ -78,7 +82,7 @@ public class CamelLogAction extends ActionBaseCommand {
boolean timestamp = true;
@CommandLine.Option(names = { "--follow" }, defaultValue = "true",
- description = "Keep following and outputting new log
lines (use ctrl + c to exit).")
+ description = "Keep following and outputting new log
lines (press enter to exit).")
boolean follow = true;
@CommandLine.Option(names = { "--startup" }, defaultValue = "false",
@@ -165,6 +169,12 @@ public class CamelLogAction extends ActionBaseCommand {
if (follow) {
boolean waitMessage = true;
+ final AtomicBoolean running = new AtomicBoolean(true);
+ Thread t = new Thread(() -> {
+ waitUserTask = new CommandHelper.ReadConsoleTask(() ->
running.set(false));
+ waitUserTask.run();
+ }, "WaitForUser");
+ t.start();
StopWatch watch = new StopWatch();
do {
if (rows.isEmpty()) {
@@ -188,7 +198,7 @@ public class CamelLogAction extends ActionBaseCommand {
Thread.sleep(100);
}
}
- } while (true);
+ } while (running.get());
}
return 0;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
index 237555fc1e2..3e1cb212840 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
@@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import com.github.freva.asciitable.AsciiTable;
@@ -41,6 +42,7 @@ import com.github.freva.asciitable.HorizontalAlign;
import com.github.freva.asciitable.OverflowBehaviour;
import org.apache.camel.catalog.impl.TimePatternConverter;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
import org.apache.camel.dsl.jbang.core.common.PidNameAgeCompletionCandidates;
import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
import org.apache.camel.util.FileUtil;
@@ -63,6 +65,8 @@ public class CamelReceiveAction extends ActionBaseCommand {
private static final int NAME_MAX_WIDTH = 25;
private static final int NAME_MIN_WIDTH = 10;
+ private CommandHelper.ReadConsoleTask waitUserTask;
+
public static class PrefixCompletionCandidates implements Iterable<String>
{
public PrefixCompletionCandidates() {
@@ -102,7 +106,7 @@ public class CamelReceiveAction extends ActionBaseCommand {
String sort;
@CommandLine.Option(names = { "--follow" }, defaultValue = "true",
- description = "Keep following and outputting new
messages (use ctrl + c to exit).")
+ description = "Keep following and outputting new
messages (press enter to exit).")
boolean follow = true;
@CommandLine.Option(names = { "--prefix" }, defaultValue = "auto",
@@ -393,9 +397,15 @@ public class CamelReceiveAction extends ActionBaseCommand {
if (follow) {
boolean waitMessage = true;
- StopWatch watch = new StopWatch();
+ final AtomicBoolean running = new AtomicBoolean(true);
+ Thread t = new Thread(() -> {
+ waitUserTask = new CommandHelper.ReadConsoleTask(() ->
running.set(false));
+ waitUserTask.run();
+ }, "WaitForUser");
+ t.start();
boolean more = true;
boolean init = true;
+ StopWatch watch = new StopWatch();
do {
if (pids.isEmpty()) {
if (waitMessage) {
@@ -425,7 +435,7 @@ public class CamelReceiveAction extends ActionBaseCommand {
break;
}
}
- } while (more);
+ } while (more && running.get());
}
return 0;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
index 61a08e4ef78..859efc1ce49 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
@@ -34,6 +34,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import com.github.freva.asciitable.AsciiTable;
@@ -42,6 +43,7 @@ import com.github.freva.asciitable.HorizontalAlign;
import com.github.freva.asciitable.OverflowBehaviour;
import org.apache.camel.catalog.impl.TimePatternConverter;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
import org.apache.camel.dsl.jbang.core.common.PidNameAgeCompletionCandidates;
import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
import org.apache.camel.util.IOHelper;
@@ -64,6 +66,8 @@ public class CamelTraceAction extends ActionBaseCommand {
private static final int NAME_MAX_WIDTH = 25;
private static final int NAME_MIN_WIDTH = 10;
+ private CommandHelper.ReadConsoleTask waitUserTask;
+
public static class PrefixCompletionCandidates implements Iterable<String>
{
public PrefixCompletionCandidates() {
@@ -107,7 +111,7 @@ public class CamelTraceAction extends ActionBaseCommand {
boolean ago;
@CommandLine.Option(names = { "--follow" }, defaultValue = "true",
- description = "Keep following and outputting new
traces (use ctrl + c to exit).")
+ description = "Keep following and outputting new
traces (press enter to exit).")
boolean follow = true;
@CommandLine.Option(names = { "--prefix" }, defaultValue = "auto",
completionCandidates = PrefixCompletionCandidates.class,
@@ -376,7 +380,13 @@ public class CamelTraceAction extends ActionBaseCommand {
if (follow) {
boolean waitMessage = true;
+ final AtomicBoolean running = new AtomicBoolean(true);
StopWatch watch = new StopWatch();
+ Thread t = new Thread(() -> {
+ waitUserTask = new CommandHelper.ReadConsoleTask(() ->
running.set(false));
+ waitUserTask.run();
+ }, "WaitForUser");
+ t.start();
boolean more = true;
do {
if (pids.isEmpty()) {
@@ -402,7 +412,7 @@ public class CamelTraceAction extends ActionBaseCommand {
break;
}
}
- } while (more);
+ } while (more && running.get());
}
return 0;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
index 5ac45dabdfd..d9559a9f5a1 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
@@ -16,7 +16,11 @@
*/
package org.apache.camel.dsl.jbang.core.commands.process;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.CommandHelper;
+import org.apache.camel.util.StopWatch;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;
import picocli.CommandLine;
@@ -30,6 +34,8 @@ abstract class ProcessWatchCommand extends ProcessBaseCommand
{
description = "Execute periodically and showing output
fullscreen")
boolean watch;
+ private CommandHelper.ReadConsoleTask waitUserTask;
+
public ProcessWatchCommand(CamelJBangMain main) {
super(main);
}
@@ -37,15 +43,28 @@ abstract class ProcessWatchCommand extends
ProcessBaseCommand {
@Override
public Integer doCall() throws Exception {
int exit;
+ final AtomicBoolean running = new AtomicBoolean(true);
if (watch) {
+ Thread t = new Thread(() -> {
+ waitUserTask = new CommandHelper.ReadConsoleTask(() ->
running.set(false));
+ waitUserTask.run();
+ }, "WaitForUser");
+ t.start();
do {
autoClearScreen();
exit = doProcessWatchCall();
if (exit == 0) {
// use 2-sec delay in watch mode
- Thread.sleep(2000);
+ try {
+ StopWatch watch = new StopWatch();
+ while (running.get() && watch.taken() < 2000) {
+ Thread.sleep(100);
+ }
+ } catch (Exception e) {
+ running.set(false);
+ }
}
- } while (exit == 0);
+ } while (exit == 0 && running.get());
} else {
exit = doProcessWatchCall();
}