This is an automated email from the ASF dual-hosted git repository.
clebertsuconic pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/artemis.git
The following commit(s) were added to refs/heads/main by this push:
new d8137b7417 ARTEMIS-6051 Change artemis shell history defaults to
~/.artemis_history
d8137b7417 is described below
commit d8137b74176fecb93493ab0dfcb990ad0911fde3
Author: Clebert Suconic <[email protected]>
AuthorDate: Fri May 8 10:30:38 2026 -0400
ARTEMIS-6051 Change artemis shell history defaults to ~/.artemis_history
It is possible to change the artemis-utility.profile as well
---
.../org/apache/activemq/artemis/cli/Shell.java | 63 +++++++++--
.../activemq/artemis/cli/commands/bin/artemis | 6 ++
.../cli/commands/etc/artemis-utility.profile | 4 +
.../activemq/artemis/cli/commands/ShellTest.java | 118 +++++++++++++++++++++
4 files changed, 184 insertions(+), 7 deletions(-)
diff --git
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Shell.java
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Shell.java
index b98fce02fb..bf22076ed6 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Shell.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Shell.java
@@ -22,6 +22,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.file.Files;
@@ -68,7 +69,7 @@ public class Shell implements Runnable {
@CommandLine.Option(names = "--history", description = "File where shell
history is being stored.")
protected File historyFile;
- private static final String DEFAULT_HISTORY_FILE = "history-file";
+ public static final String DEFAULT_HISTORY_FILE = "history-file";
public Shell(CommandLine commandLine) {
}
@@ -82,7 +83,7 @@ public class Shell implements Runnable {
connect.setUser(user).setPassword(password).setBrokerURL(brokerURL);
connect.run();
}
- runShell(false, historyFile);
+ runShell(false, historyFile, null);
}
private static ThreadLocal<AtomicBoolean> IN_SHELL =
ThreadLocal.withInitial(() -> new AtomicBoolean(false));
@@ -106,10 +107,10 @@ public class Shell implements Runnable {
}
public static void runShell(boolean printBanner) {
- runShell(printBanner, null);
+ runShell(printBanner, null, null);
}
- public static void runShell(boolean printBanner, File historyFile) {
+ public static void runShell(boolean printBanner, File historyFile,
InputStream pipedInput) {
try {
setInShell();
@@ -117,8 +118,21 @@ public class Shell implements Runnable {
boolean isInstance = artemisInstance != null;
- if (isInstance && historyFile == null) {
- historyFile = inquiryDefaultHistory(historyFile, artemisInstance);
+ if (historyFile == null) {
+ String historyFilePath =
System.getProperty("artemis.shell.history");
+ if (historyFilePath == null) {
+ historyFilePath = System.getenv("ARTEMIS_SHELL_HISTORY");
+ }
+ if (historyFilePath != null) {
+ historyFile = new File(historyFilePath);
+ } else {
+ historyFile = inquiryDefaultHistory(historyFile,
artemisInstance);
+ }
+ }
+
+ if (pipedInput != null) {
+ runPipedMode(isInstance, pipedInput);
+ return;
}
Supplier<Path> workDir = () ->
Paths.get(System.getProperty("user.dir"));
@@ -168,7 +182,11 @@ public class Shell implements Runnable {
printBanner();
}
- if (historyFile != null) {
+ if (historyFile == null) {
+ File preferenceFile = new File(artemisInstance + "/etc/" +
DEFAULT_HISTORY_FILE);
+
System.out.println(org.apache.activemq.artemis.cli.Terminal.WARNING_COLOR_UNICODE
+ "Shell history disabled as recorded in " + preferenceFile.getAbsolutePath()
+ org.apache.activemq.artemis.cli.Terminal.CLEAR_UNICODE);
+ System.out.println();
+ } else {
System.out.println(org.apache.activemq.artemis.cli.Terminal.WARNING_COLOR_UNICODE
+ "Shell history being saved at " + historyFile.getAbsolutePath() +
org.apache.activemq.artemis.cli.Terminal.CLEAR_UNICODE);
System.out.println();
}
@@ -254,6 +272,7 @@ public class Shell implements Runnable {
} else {
defaultHistoryFile.createNewFile();
}
+ setHistoryFilePermissions(defaultHistoryFile);
}
if (historyFile == null) {
@@ -324,4 +343,34 @@ public class Shell implements Runnable {
}
}
+ private static void runPipedMode(boolean isInstance, InputStream is) throws
Exception {
+
+ try (BufferedReader reader = new BufferedReader(new
InputStreamReader(is))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+
+ // Skip empty lines and comments
+ if (line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+
+ // Exit command
+ if (line.equals("exit") || line.equals("quit")) {
+ break;
+ }
+
+ try {
+ // Rebuild command for each execution to avoid state issues
+ CommandLine commandLine = Artemis.buildCommand(isInstance,
!isInstance, false);
+ String[] args = line.split("\\s+");
+ commandLine.execute(args);
+ } catch (Exception e) {
+ System.err.println("Error executing command: " + line);
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
}
diff --git
a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis
b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis
index b792eb8869..693b175697 100755
---
a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis
+++
b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis
@@ -119,6 +119,11 @@ if [ -f "$ARTEMIS_OOME_DUMP" ] ; then
mv $ARTEMIS_OOME_DUMP $ARTEMIS_OOME_DUMP.bkp
fi
+# Set shell history argument if ARTEMIS_SHELL_HISTORY is defined
+if [ -n "$ARTEMIS_SHELL_HISTORY" ]; then
+ SHELL_HISTORY_ARG="-Dartemis.shell.history=${ARTEMIS_SHELL_HISTORY}"
+fi
+
exec "$JAVACMD" \
$LOGGING_ARGS \
$JAVA_ARGS \
@@ -132,6 +137,7 @@ exec "$JAVACMD" \
-Djava.io.tmpdir="$ARTEMIS_INSTANCE/tmp" \
-Ddata.dir="$ARTEMIS_DATA_DIR" \
-Dartemis.instance.etc="$ARTEMIS_INSTANCE_ETC" \
+ $SHELL_HISTORY_ARG \
$DEBUG_ARGS \
$JAVA_ARGS_APPEND \
org.apache.activemq.artemis.boot.Artemis "$@"
diff --git
a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis-utility.profile
b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis-utility.profile
index a724cd6c49..e23f776e7d 100644
---
a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis-utility.profile
+++
b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis-utility.profile
@@ -19,6 +19,10 @@ ARTEMIS_HOME='${artemis.home}'
ARTEMIS_INSTANCE='@artemis.instance@'
ARTEMIS_DATA_DIR='${artemis.instance.data}'
+if [ -z "$ARTEMIS_SHELL_HISTORY" ]; then
+ ARTEMIS_SHELL_HISTORY=~/.artemis_history
+fi
+
if [ -z "$LOGGING_ARGS" ]; then
LOGGING_ARGS="-Dlog4j2.configurationFile=log4j2-utility.properties"
fi
diff --git
a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java
new file mode 100644
index 0000000000..6060c4d914
--- /dev/null
+++
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.activemq.artemis.cli.commands;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.cli.Shell;
+import org.apache.activemq.artemis.tests.util.ArtemisTestCase;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class ShellTest extends ArtemisTestCase {
+
+ @TempDir
+ File temporaryFolder;
+
+ @Test
+ public void testDefaultAllowHistory() throws Exception {
+ testDefaultHistory(true);
+ }
+
+ @Test
+ public void testDefaultDontAllowHistory() throws Exception {
+ testDefaultHistory(false);
+ }
+
+ public void testDefaultHistory(boolean allowHistory) throws Exception {
+ System.setProperty("artemis.instance",
temporaryFolder.getAbsolutePath());
+ File etcFolder = new File(temporaryFolder, "etc");
+ assertTrue(etcFolder.mkdirs());
+
+ String input;
+ if (allowHistory) {
+ input = "Y\n";
+ } else {
+ input = "N\n";
+ }
+
+ File shellHistory = new File(etcFolder, Shell.DEFAULT_HISTORY_FILE);
+ executeShell(input, shellHistory);
+
+ if (!allowHistory) {
+ String historyContent = new
String(Files.readAllBytes(shellHistory.toPath()), StandardCharsets.UTF_8);
+ assertTrue(historyContent.contains("NO_HISTORY"), "History file
should contain NO_HISTORY marker");
+ }
+ }
+
+ private static void executeShell(String input, File outputHistory) throws
InterruptedException, IOException {
+ ByteArrayInputStream inputStream = new
ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));
+
+ try {
+ CountDownLatch shellFinished = new CountDownLatch(1);
+
+ Thread shellThread = new Thread(() -> {
+ InputStream originlInput = System.in;
+ try {
+ // Run the shell with custom streams for testing
+ System.setIn(inputStream);
+ Shell.runShell(false, null, inputStream);
+ } finally {
+ shellFinished.countDown();
+ System.setIn(originlInput);
+ }
+ });
+
+ shellThread.start();
+
+ // Wait for shell to finish
+ assertTrue(shellFinished.await(30, TimeUnit.SECONDS), "Shell did not
finish in time");
+ shellThread.join(5000);
+
+ assertTrue(outputHistory.exists());
+
+ // Validate file permissions are 600 (owner read/write only)
+ Set<PosixFilePermission> permissions =
Files.getPosixFilePermissions(outputHistory.toPath());
+ assertTrue(permissions.contains(PosixFilePermission.OWNER_READ),
"File should be readable by owner");
+ assertTrue(permissions.contains(PosixFilePermission.OWNER_WRITE),
"File should be writable by owner");
+ // Explicitly verify group and others cannot read
+ assertFalse(permissions.contains(PosixFilePermission.GROUP_READ),
"File should not be readable by group");
+ assertFalse(permissions.contains(PosixFilePermission.GROUP_WRITE),
"File should not be writable by group");
+ assertFalse(permissions.contains(PosixFilePermission.GROUP_EXECUTE),
"File should not be executable by group");
+ assertFalse(permissions.contains(PosixFilePermission.OTHERS_READ),
"File should not be readable by others");
+ assertFalse(permissions.contains(PosixFilePermission.OTHERS_WRITE),
"File should not be writable by others");
+ assertFalse(permissions.contains(PosixFilePermission.OTHERS_EXECUTE),
"File should not be executable by others");
+
+ } finally {
+ System.clearProperty("artemis.instance");
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]