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]

Reply via email to