JAL-629 Added --opennew --nonews --nosplash. Added java globbing for = e.g. --open...
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 29 Mar 2023 22:31:46 +0000 (23:31 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 29 Mar 2023 22:31:46 +0000 (23:31 +0100)
src/jalview/bin/Commands.java
src/jalview/bin/Jalview.java
src/jalview/bin/argparser/Arg.java
src/jalview/bin/argparser/ArgParser.java
src/jalview/bin/argparser/ArgValue.java
src/jalview/bin/argparser/ArgValues.java
src/jalview/bin/argparser/BootstrapArgs.java
src/jalview/bin/argparser/SubVals.java
src/jalview/util/FileUtils.java
test/jalview/bin/ArgsParserTest.java [moved from test/jalview/bin/argparser/ArgsParserTest.java with 100% similarity]

index 43dc1fd..e92ee61 100644 (file)
@@ -159,7 +159,7 @@ public class Commands
     FileFormatI format = null;
     DataSourceType protocol = null;
     */
-    if (avm.containsArg(Arg.OPEN))
+    if (avm.containsArg(Arg.OPEN) || avm.containsArg(Arg.OPENNEW))
     {
       commandArgsProvided = true;
       long progress = -1;
@@ -167,6 +167,8 @@ public class Commands
       boolean first = true;
       boolean progressBarSet = false;
       AlignFrame af;
+      // Combine the OPEN and OPENNEW files into one list, along with whether it
+      // was OPEN or OPENNEW
       List<Entry<Arg, ArgValue>> openAvList = new ArrayList<>();
       avm.getArgValueList(Arg.OPEN).stream()
               .forEachOrdered(av -> openAvList.add(
index bc8c997..689080e 100755 (executable)
@@ -416,9 +416,11 @@ public class Jalview
     String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
             ? bootstrapArgs.get(Arg.PROPS)
             : aparser.getValue("props");
+    // if usrPropsFile == null, loadProperties will use the Channel
+    // preferences.file
+    Cache.loadProperties(usrPropsFile);
     if (usrPropsFile != null)
     {
-      Cache.loadProperties(usrPropsFile);
       System.out.println(
               "CMD [-props " + usrPropsFile + "] executed successfully!");
     }
@@ -542,7 +544,8 @@ public class Jalview
 
     if (!(headless || headlessArg))
     {
-      Desktop.nosplash = aparser.contains("nosplash");
+      Desktop.nosplash = "false".equals(bootstrapArgs.get(Arg.SPLASH))
+              || aparser.contains("nosplash");
       desktop = new Desktop();
       desktop.setInBatchMode(true); // indicate we are starting up
 
index 4c2465c..c19012b 100644 (file)
@@ -52,7 +52,7 @@ public enum Arg
     USAGESTATS.setOptions(true, Opt.BOOLEAN);
     OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
             Opt.ALLOWSUBSTITUTIONS);
-    OPENNEW.setOptions(Opt.STRING, Opt.MULTI, Opt.GLOB,
+    OPENNEW.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
             Opt.ALLOWSUBSTITUTIONS);
     PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
     QUESTIONNAIRE.setOptions(Opt.STRING);
index f22ca7f..19cf276 100644 (file)
@@ -62,7 +62,7 @@ public class ArgParser
   // the linked id used to use the idCounter
   private static final String AUTOCOUNTERLINKEDID = "{n}";
 
-  private int idCounter = 0;
+  private int linkedIdAutoCounter = 0;
 
   // flag to say whether {n} subtitutions in output filenames should be made.
   // Turn on and off with --subs and --nosubs
@@ -126,8 +126,6 @@ public class ArgParser
     {
       String arg = args.get(i);
 
-      Console.debug("##### Looking at arg '" + arg + "'");
-
       // If the first arguments do not start with "--" or "-" or is "open" and
       // is a filename that exists it is probably a file/list of files to open
       // so we fake an Arg.OPEN argument and when adding files only add the
@@ -145,7 +143,8 @@ public class ArgParser
 
       String argName = null;
       String val = null;
-      List<String> vals = null; // for Opt.GLOB only
+      List<String> globVals = null; // for Opt.GLOB only
+      SubVals globSubVals = null; // also for use by Opt.GLOB only
       String linkedId = null;
       if (arg.startsWith(DOUBLEDASH))
       {
@@ -210,31 +209,50 @@ public class ArgParser
           continue;
         }
 
-        if (a.hasOption(Opt.STRING) && equalPos == -1)
+        // String value(s)
+        if (a.hasOption(Opt.STRING))
         {
-          // take next arg as value if required, and '=' was not found
-          // if (!argE.hasMoreElements())
-          if (i + 1 >= args.size())
-          {
-            // no value to take for arg, which wants a value
-            Console.error("Argument '" + a.getName()
-                    + "' requires a value, none given. Ignoring.");
-            continue;
-          }
-          // deal with bash globs here (--arg val* is expanded before reaching
-          // the JVM). Note that SubVals cannot be used in this case.
-          // If using the --arg=val then the glob is preserved and Java globs
-          // will be used later. SubVals can be used.
-          if (a.hasOption(Opt.GLOB))
+          if (equalPos >= 0)
           {
-            // if this is the first argument with a file list at the start of
-            // the args we add filenames from index i instead of i+1
-            vals = getShellGlobbedFilenameValues(a, args,
-                    openEachInitialFilenames ? i : i + 1);
+            if (a.hasOption(Opt.GLOB))
+            {
+              // strip off and save the SubVals to be added individually later
+              globSubVals = ArgParser.getSubVals(val);
+              globVals = FileUtils
+                      .getFilenamesFromGlob(globSubVals.getContent());
+            }
+            else
+            {
+              // val is already set -- will be saved in the ArgValue later in
+              // the normal way
+            }
           }
           else
           {
-            val = args.get(i + 1);
+            // There is no "=" so value is next arg or args (possibly shell
+            // glob-expanded)
+            if (i + 1 >= args.size())
+            {
+              // no value to take for arg, which wants a value
+              Console.error("Argument '" + a.getName()
+                      + "' requires a value, none given. Ignoring.");
+              continue;
+            }
+            // deal with bash globs here (--arg val* is expanded before reaching
+            // the JVM). Note that SubVals cannot be used in this case.
+            // If using the --arg=val then the glob is preserved and Java globs
+            // will be used later. SubVals can be used.
+            if (a.hasOption(Opt.GLOB))
+            {
+              // if this is the first argument with a file list at the start of
+              // the args we add filenames from index i instead of i+1
+              globVals = getShellGlobbedFilenameValues(a, args,
+                      openEachInitialFilenames ? i : i + 1);
+            }
+            else
+            {
+              val = args.get(i + 1);
+            }
           }
         }
 
@@ -246,7 +264,7 @@ public class ArgParser
         }
         else if (a == Arg.NPP)
         {
-          idCounter++;
+          linkedIdAutoCounter++;
         }
         else if (a == Arg.SUBSTITUTIONS)
         {
@@ -259,37 +277,43 @@ public class ArgParser
                 .append(Integer.toString(defaultLinkedIdCounter))
                 .toString();
         boolean usingDefaultLinkedId = false;
-        if (a == Arg.OPENNEW)
-        {
-          linkedId = new StringBuilder(OPENNEWLINKEDIDPREFIX)
-                  .append(Integer.toString(opennewLinkedIdCounter))
-                  .toString();
-          opennewLinkedIdCounter++;
-        }
-        else if (a.hasOption(Opt.LINKED))
+        if (a.hasOption(Opt.LINKED))
         {
           if (linkedId == null)
           {
-            // use default linkedId for linked arguments
-            linkedId = defaultLinkedId;
-            usingDefaultLinkedId = true;
-            Console.debug(
-                    "Changing linkedId to '" + linkedId + "' from " + arg);
+            if (a == Arg.OPENNEW)
+            {
+              // use the next default prefixed OPENNEWLINKEDID
+              linkedId = new StringBuilder(OPENNEWLINKEDIDPREFIX)
+                      .append(Integer.toString(opennewLinkedIdCounter))
+                      .toString();
+              opennewLinkedIdCounter++;
+            }
+            else
+            {
+              // use default linkedId for linked arguments
+              linkedId = defaultLinkedId;
+              usingDefaultLinkedId = true;
+              Console.debug("Changing linkedId to '" + linkedId + "' from "
+                      + arg);
+            }
           }
-          else if (linkedId.equals(AUTOCOUNTERLINKEDID))
+          else if (linkedId.contains(AUTOCOUNTERLINKEDID))
           {
             // turn {n} to the autoCounter
-            autoCounterString = Integer.toString(idCounter);
-            linkedId = autoCounterString;
+            autoCounterString = Integer.toString(linkedIdAutoCounter);
+            linkedId = linkedId.replace(AUTOCOUNTERLINKEDID,
+                    autoCounterString);
             usingAutoCounterLinkedId = true;
             Console.debug(
                     "Changing linkedId to '" + linkedId + "' from " + arg);
           }
-          else if (linkedId.equals(INCREMENTAUTOCOUNTERLINKEDID))
+          else if (linkedId.contains(INCREMENTAUTOCOUNTERLINKEDID))
           {
             // turn {++n} to the incremented autoCounter
-            autoCounterString = Integer.toString(++idCounter);
-            linkedId = autoCounterString;
+            autoCounterString = Integer.toString(++linkedIdAutoCounter);
+            linkedId = linkedId.replace(INCREMENTAUTOCOUNTERLINKEDID,
+                    autoCounterString);
             usingAutoCounterLinkedId = true;
             Console.debug(
                     "Changing linkedId to '" + linkedId + "' from " + arg);
@@ -315,8 +339,8 @@ public class ArgParser
         }
 
         // check for unique id
-        SubVals sv = ArgParser.getSubVals(val);
-        String id = sv.get(ArgValues.ID);
+        SubVals idsv = ArgParser.getSubVals(val);
+        String id = idsv.get(ArgValues.ID);
         if (id != null && avm.hasId(a, id))
         {
           Console.error("Argument '--" + argName + "' has a duplicate id ('"
@@ -327,14 +351,18 @@ public class ArgParser
         boolean argIndexIncremented = false;
         ArgValues avs = avm.getOrCreateArgValues(a);
 
-        // store appropriate value
+        // store appropriate String value(s)
         if (a.hasOption(Opt.STRING))
         {
-          if (a.hasOption(Opt.GLOB) && vals != null && vals.size() > 0)
+          if (a.hasOption(Opt.GLOB) && globVals != null
+                  && globVals.size() > 0)
           {
-            for (String v : vals)
+            for (String v : globVals)
             {
-              avs.addValue(makeSubstitutions(v), argIndex++);
+              v = makeSubstitutions(v);
+              SubVals vsv = new SubVals(globSubVals == null ? null
+                      : globSubVals.getSubValsMap(), v);
+              avs.addValue(vsv, v, argIndex++);
               argIndexIncremented = true;
             }
           }
@@ -371,6 +399,7 @@ public class ArgParser
           argList = new ArrayList<>();
         if (!argList.contains(a))
           argList.add(a);
+
       }
     }
   }
@@ -395,9 +424,14 @@ public class ArgParser
       subvals = "";
       rest = val;
     }
-    rest.replace(AUTOCOUNTERLINKEDID, String.valueOf(idCounter));
-    rest.replace(INCREMENTAUTOCOUNTERLINKEDID, String.valueOf(++idCounter));
-    rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
+    if ((rest.contains(AUTOCOUNTERLINKEDID)))
+      rest = rest.replace(AUTOCOUNTERLINKEDID,
+              String.valueOf(linkedIdAutoCounter));
+    if ((rest.contains(INCREMENTAUTOCOUNTERLINKEDID)))
+      rest = rest.replace(INCREMENTAUTOCOUNTERLINKEDID,
+              String.valueOf(++linkedIdAutoCounter));
+    if ((rest.contains("{}")))
+      rest = rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
 
     return new StringBuilder(subvals).append(rest).toString();
   }
@@ -418,7 +452,7 @@ public class ArgParser
     List<String> vals = new ArrayList<>();
     while (i < args.size() && !args.get(i).startsWith(DOUBLEDASH))
     {
-      vals.add(args.remove(i));
+      vals.add(FileUtils.substituteHomeDir(args.remove(i)));
       if (!a.hasOption(Opt.GLOB))
         break;
     }
index 2aa32df..28cead9 100644 (file)
@@ -13,11 +13,18 @@ public class ArgValue
 
   private SubVals subVals = null;
 
+  protected ArgValue(SubVals sv, String content, int argIndex)
+  {
+    this.value = content;
+    this.argIndex = argIndex;
+    this.subVals = sv;
+  }
+
   protected ArgValue(String value, int argIndex)
   {
-    this.value = value;
     this.argIndex = argIndex;
-    this.subVals = ArgParser.getSubVals(getValue());
+    this.subVals = ArgParser.getSubVals(value);
+    this.value = getSubVals().getContent();
   }
 
   public String getValue()
index 2c71f63..27d52ba 100644 (file)
@@ -108,6 +108,11 @@ public class ArgValues
     addArgValue(new ArgValue(val, argIndex));
   }
 
+  protected void addValue(SubVals sv, String content, int argIndex)
+  {
+    addArgValue(new ArgValue(sv, content, argIndex));
+  }
+
   protected void addArgValue(ArgValue av)
   {
     if ((!arg.hasOption(Opt.MULTI) && argValueList.size() > 0)
index 49e8686..f6b592b 100644 (file)
@@ -37,7 +37,6 @@ public class BootstrapArgs
       if (arg.startsWith(ArgParser.DOUBLEDASH))
       {
         // remove "--"
-        System.out.println("###### BOOTSTRAP: '" + arg + "'");
         arg = arg.substring(ArgParser.DOUBLEDASH.length());
         int equalPos = arg.indexOf('=');
         if (equalPos > -1
@@ -51,7 +50,6 @@ public class BootstrapArgs
                 && ArgParser.argMap.containsKey(
                         arg.substring(ArgParser.NEGATESTRING.length())))
         {
-          System.out.println("###### BOOTSTRAP IN NEGATESTRING");
           argName = arg.substring(ArgParser.NEGATESTRING.length());
           val = "false";
         }
@@ -86,8 +84,6 @@ public class BootstrapArgs
         }
         else
         {
-          System.err.println(
-                  "###### Adding '" + a.getName() + "' with '" + val + "'");
           add(a, val);
         }
       }
index e6a7cb2..aea6df3 100644 (file)
@@ -1,6 +1,8 @@
 package jalview.bin.argparser;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import jalview.bin.Console;
@@ -21,8 +23,16 @@ public class SubVals
 
   private static char SEPARATOR = ';';
 
+  private static char EQUALS = '=';
+
   private String content = null;
 
+  public SubVals(Map<String, String> sv, String c)
+  {
+    this.subVals = sv;
+    this.content = c;
+  }
+
   public SubVals(String item)
   {
     this.parseVals(item);
@@ -42,11 +52,11 @@ public class SubVals
       for (String subvalString : subvalsString
               .split(Character.toString(SEPARATOR)))
       {
-        int equals = subvalString.indexOf('=');
+        if (subVals == null)
+          subVals = new HashMap<>();
+        int equals = subvalString.indexOf(EQUALS);
         if (equals > -1)
         {
-          if (subVals == null)
-            subVals = new HashMap<>();
           this.put(subvalString.substring(0, equals),
                   subvalString.substring(equals + 1));
         }
@@ -59,7 +69,7 @@ public class SubVals
           } catch (NumberFormatException e)
           {
             // store this non-numeric key as a "true" value
-            subVals.put(subvalsString, "true");
+            subVals.put(subvalString, "true");
           }
         }
       }
@@ -108,15 +118,27 @@ public class SubVals
     return content;
   }
 
+  protected Map<String, String> getSubValsMap()
+  {
+    return subVals;
+  }
+
   public String toString()
   {
-    StringBuilder sb = new StringBuilder();
-    if (subVals == null)
+    if (subVals == null && getIndex() == NOTSET)
       return "";
-    for (Map.Entry<String, String> m : subVals.entrySet())
-    {
-      sb.append(m.getKey()).append('=').append(m.getValue()).append("\n");
-    }
+
+    StringBuilder sb = new StringBuilder();
+    List<String> entries = new ArrayList<>();
+    subVals.entrySet().stream().forEachOrdered(
+            m -> entries.add(m.getValue().equals("true") ? m.getKey()
+                    : new StringBuilder().append(m.getKey()).append(EQUALS)
+                            .append(m.getValue()).toString()));
+    if (getIndex() != NOTSET)
+      entries.add(Integer.toString(getIndex()));
+    sb.append('[');
+    sb.append(String.join(Character.toString(SEPARATOR), entries));
+    sb.append(']');
     return sb.toString();
   }
 }
\ No newline at end of file
index 9aa27f9..63af0bc 100644 (file)
@@ -26,9 +26,16 @@ public class FileUtils
    */
   public static List<File> getFilesFromGlob(String pattern)
   {
+    return getFilesFromGlob(pattern, true);
+  }
+
+  public static List<File> getFilesFromGlob(String pattern,
+          boolean allowSingleFilenameThatDoesNotExist)
+  {
+    pattern = substituteHomeDir(pattern);
     List<File> files = new ArrayList<>();
     /*
-     * For efficiency of the Files.walkFileTree, let's find the longest path that doesn't need globbing.
+     * For efficiency of the Files.walkFileTree(), let's find the longest path that doesn't need globbing.
      * We look for the first glob character * { ? and then look for the last File.separator before that.
      * Then we can reset the path to look at and shorten the globbing pattern.
      * Relative paths can be used in pattern, which work from the pwd (though these are converted into
@@ -94,7 +101,7 @@ public class FileUtils
     {
       // no wildcards
       File f = new File(pattern);
-      if (f.exists())
+      if (allowSingleFilenameThatDoesNotExist || f.exists())
       {
         files.add(f);
       }
@@ -110,4 +117,10 @@ public class FileUtils
             .collect(Collectors.toList());
   }
 
-}
\ No newline at end of file
+  public static String substituteHomeDir(String path)
+  {
+    return path.startsWith("~" + File.separator)
+            ? System.getProperty("user.home") + path.substring(1)
+            : path;
+  }
+}