Improve JShell client CLI v2.3.20
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 18 Oct 2023 13:05:48 +0000 (15:05 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 18 Oct 2023 13:05:48 +0000 (15:05 +0200)
org.argeo.cms.jshell/src/org/argeo/cms/jshell/JShellClient.java
org.argeo.cms/src/org/argeo/cms/util/OS.java

index 87e88b77fe2d994014b488b84f5927e143ac4f1a..f090ed0684a85b3be957b9da3af309f46f0ec67b 100644 (file)
@@ -11,6 +11,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.PrintStream;
 import java.lang.System.Logger;
 import java.lang.management.ManagementFactory;
 import java.net.StandardSocketOptions;
@@ -155,34 +156,101 @@ public class JShellClient {
 
        }
 
-       public static void main(String[] args) throws IOException, InterruptedException {
-               if (benchmark)
-                       System.err.println(ManagementFactory.getRuntimeMXBean().getUptime());
-               List<String> plainArgs = new ArrayList<>();
-               Map<String, List<String>> options = new HashMap<>();
-               String currentOption = null;
-               for (int i = 0; i < args.length; i++) {
-                       if (args[i].startsWith("-")) {
-                               currentOption = args[i];
-                               if (!options.containsKey(currentOption))
-                                       options.put(currentOption, new ArrayList<>());
-                               i++;
-                               options.get(currentOption).add(args[i]);
-                       } else {
-                               plainArgs.add(args[i]);
+       public static void main(String[] args) {
+               try {
+                       if (benchmark)
+                               System.err.println(ManagementFactory.getRuntimeMXBean().getUptime());
+                       List<String> plainArgs = new ArrayList<>();
+                       Map<String, List<String>> options = new HashMap<>();
+                       String currentOption = null;
+                       for (int i = 0; i < args.length; i++) {
+                               if (args[i].startsWith("-")) {
+                                       currentOption = args[i];
+                                       if ("-h".equals(currentOption) || "--help".equals(currentOption)) {
+                                               printHelp(System.out);
+                                               return;
+                                       }
+                                       if (!options.containsKey(currentOption))
+                                               options.put(currentOption, new ArrayList<>());
+                                       i++;
+                                       options.get(currentOption).add(args[i]);
+                               } else {
+                                       plainArgs.add(args[i]);
+                               }
                        }
+
+                       List<String> dir = opt(options, "-d", "--sockets-dir");
+                       if (dir.size() > 1)
+                               throw new IllegalArgumentException("Only one run directory can be specified");
+                       Path targetStateDirectory;
+                       if (dir.isEmpty())
+                               targetStateDirectory = Paths.get(System.getProperty("user.dir"));
+                       else {
+                               targetStateDirectory = Paths.get(dir.get(0));
+                               if (!Files.exists(targetStateDirectory)) {
+                                       // we assume argument is the application id
+                                       targetStateDirectory = getRunDir().resolve(dir.get(0));
+                               }
+                       }
+
+                       List<String> bundle = opt(options, "-b", "--bundle");
+                       if (bundle.size() > 1)
+                               throw new IllegalArgumentException("Only one bundle can be specified");
+                       String symbolicName = bundle.isEmpty() ? "org.argeo.cms.cli" : bundle.get(0);
+
+                       Path script = plainArgs.isEmpty() ? null : Paths.get(plainArgs.get(0));
+                       List<String> scriptArgs = new ArrayList<>();
+                       for (int i = 1; i < plainArgs.size(); i++)
+                               scriptArgs.add(plainArgs.get(i));
+
+                       JShellClient client = new JShellClient(targetStateDirectory, symbolicName, script, scriptArgs);
+                       client.run();
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       printHelp(System.err);
                }
+       }
 
-               Path targetStateDirectory = Paths.get(options.get("-d").get(0));
-               String symbolicName = options.get("-b").get(0);
+       /** Guaranteed to return a non-null list (which may be empty). */
+       private static List<String> opt(Map<String, List<String>> options, String shortOpt, String longOpt) {
+               List<String> res = new ArrayList<>();
+               if (options.get(shortOpt) != null)
+                       res.addAll(options.get(shortOpt));
+               if (options.get(longOpt) != null)
+                       res.addAll(options.get(longOpt));
+               return res;
+       }
 
-               Path script = plainArgs.isEmpty() ? null : Paths.get(plainArgs.get(0));
-               List<String> scriptArgs = new ArrayList<>();
-               for (int i = 1; i < plainArgs.size(); i++)
-                       scriptArgs.add(plainArgs.get(i));
+       public static void printHelp(PrintStream out) {
+               out.println("Start a JShell terminal or execute a JShell script in a local Argeo CMS instance");
+               out.println("Usage: jshc -d <sockets directory> -b <bundle> [JShell script] [script arguments...]");
+               out.println("  -d, --sockets-dir  app directory with UNIX sockets (default to current dir)");
+               out.println("  -b, --bundle       bundle to activate and use as context (default to org.argeo.cms.cli)");
+               out.println("  -h, --help         this help message");
+       }
 
-               JShellClient client = new JShellClient(targetStateDirectory, symbolicName, script, scriptArgs);
-               client.run();
+       // Copied from org.argeo.cms.util.OS
+       private static Path getRunDir() {
+               Path runDir;
+               String xdgRunDir = System.getenv("XDG_RUNTIME_DIR");
+               if (xdgRunDir != null) {
+                       // TODO support multiple names
+                       runDir = Paths.get(xdgRunDir);
+               } else {
+                       String username = System.getProperty("user.name");
+                       if (username.equals("root")) {
+                               runDir = Paths.get("/run");
+                       } else {
+                               Path homeDir = Paths.get(System.getProperty("user.home"));
+                               if (!Files.isWritable(homeDir)) {
+                                       // typically, dameon's home (/usr/sbin) is not writable
+                                       runDir = Paths.get("/tmp/" + username + "/run");
+                               } else {
+                                       runDir = homeDir.resolve(".cache/argeo");
+                               }
+                       }
+               }
+               return runDir;
        }
 
        /*
index e72ad252a48d1de1b836e65560e74c3de782e578..8d7e693e9f85841d7dcb4bc9045c179cf0fb886f 100644 (file)
@@ -67,10 +67,12 @@ public class OS {
                        if (username.equals("root")) {
                                runDir = Paths.get("/run");
                        } else {
-                               runDir = Paths.get(System.getProperty("user.home"), ".cache/argeo");
-                               if (!Files.isWritable(runDir)) {
+                               Path homeDir = Paths.get(System.getProperty("user.home"));
+                               if (!Files.isWritable(homeDir)) {
                                        // typically, dameon's home (/usr/sbin) is not writable
                                        runDir = Paths.get("/tmp/" + username + "/run");
+                               } else {
+                                       runDir = homeDir.resolve(".cache/argeo");
                                }
                        }
                }