X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2Fargparser%2FArgParser.java;h=38cb2d47b3be3e2842a90a8f92db679d4855024c;hb=79456f40b33e73e2fb5420a3287ae80854281ef6;hp=5f0cad612f2a48b23f1300b49de064d4345bd95d;hpb=71ce94a16981fdb88eaecd2078c6bd3f1cf8d0b8;p=jalview.git diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 5f0cad6..38cb2d4 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -26,15 +26,20 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; +import java.util.Enumeration; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import jalview.bin.Cache; import jalview.bin.Console; import jalview.bin.Jalview; import jalview.bin.argparser.Arg.Opt; import jalview.util.FileUtils; +import jalview.util.HttpUtils; public class ArgParser { @@ -47,17 +52,21 @@ public class ArgParser // the default linked id prefix used for no id (not even square braces) protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:"; + // the linkedId string used to match all linkedIds seen so far + protected static final String MATCHALLLINKEDIDS = "*"; + // the counter added to the default linked id prefix private int defaultLinkedIdCounter = 0; // the substitution string used to use the defaultLinkedIdCounter private static final String DEFAULTLINKEDIDCOUNTER = "{}"; - // the counter added to the default linked id prefix - private int opennewLinkedIdCounter = 0; + // the counter added to the default linked id prefix. NOW using + // linkedIdAutoCounter + // private int openLinkedIdCounter = 0; - // the linked id prefix used for --opennew files - protected static final String OPENNEWLINKEDIDPREFIX = "OPENNEW:"; + // the linked id prefix used for --open files. NOW the same as DEFAULT + protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX; // the counter used for {n} substitutions private int linkedIdAutoCounter = 0; @@ -69,12 +78,12 @@ public class ArgParser // the linked id substitution string used to use the idCounter private static final String LINKEDIDAUTOCOUNTER = "{n}"; - // the linked id substitution string used to use the base filename of --open - // or --opennew + // the linked id substitution string used to use the base filename of --append + // or --open private static final String LINKEDIDBASENAME = "{basename}"; - // the linked id substitution string used to use the dir path of --open - // or --opennew + // the linked id substitution string used to use the dir path of --append + // or --open private static final String LINKEDIDDIRNAME = "{dirname}"; // the current argfile @@ -89,19 +98,28 @@ public class ArgParser private static final String ARGFILEDIRNAME = "{argfiledirname}"; // flag to say whether {n} subtitutions in output filenames should be made. - // Turn on and off with --subs and --nosubs - private boolean substitutions = false; + // Turn on and off with --substitutions and --nosubstitutions + // Start with it on + private boolean substitutions = true; + + // flag to say whether the default linkedId is the current default linked id + // or ALL linkedIds + private boolean allLinkedIds = false; protected static final Map argMap; protected Map linkedArgs = new HashMap<>(); - protected List linkedOrder = null; + protected List linkedOrder = new ArrayList<>(); - protected List argList; + protected List argList = new ArrayList<>(); private static final char ARGFILECOMMENT = '#'; + private int argIndex = 0; + + private BootstrapArgs bootstrapArgs = null; + static { argMap = new HashMap<>(); @@ -131,29 +149,32 @@ public class ArgParser public ArgParser(String[] args) { - this(args, false); + this(args, false, null); } - public ArgParser(String[] args, boolean initsubstitutions) + public ArgParser(String[] args, boolean initsubstitutions, + BootstrapArgs bsa) { // Make a mutable new ArrayList so that shell globbing parser works. // (When shell file globbing is used, there are a sequence of non-Arg // arguments (which are the expanded globbed filenames) that need to be - // consumed by the --open/--argfile/etc Arg which is most easily done by + // consumed by the --append/--argfile/etc Arg which is most easily done by // removing these filenames from the list one at a time. This can't be done // with an ArrayList made with only Arrays.asList(String[] args). ) - this(new ArrayList<>(Arrays.asList(args)), initsubstitutions); + this(new ArrayList<>(Arrays.asList(args)), initsubstitutions, false, + bsa); } public ArgParser(List args, boolean initsubstitutions) { - this(args, initsubstitutions, false); + this(args, initsubstitutions, false, null); } public ArgParser(List args, boolean initsubstitutions, - boolean allowPrivate) + boolean allowPrivate, BootstrapArgs bsa) { - // do nothing if there are no "--" args and some "-" args + // do nothing if there are no "--" args and (some "-" args || >0 arg is + // "open") boolean d = false; boolean dd = false; for (String arg : args) @@ -163,7 +184,7 @@ public class ArgParser dd = true; break; } - else if (arg.startsWith("-")) + else if (arg.startsWith("-") || arg.equals("open")) { d = true; } @@ -174,6 +195,10 @@ public class ArgParser parse(new ArrayList(), false, false); return; } + if (bsa != null) + this.bootstrapArgs = bsa; + else + this.bootstrapArgs = BootstrapArgs.getBootstrapArgs(args); parse(args, initsubstitutions, allowPrivate); } @@ -181,21 +206,22 @@ public class ArgParser boolean allowPrivate) { this.substitutions = initsubstitutions; - int argIndex = 0; boolean openEachInitialFilenames = true; for (int i = 0; i < args.size(); i++) { String arg = args.get(i); - // 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 + // If the first arguments do not start with "--" or "-" or is not "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 // single arg[i] and increment the defaultLinkedIdCounter so that each of // these files is opened separately. if (openEachInitialFilenames && !arg.startsWith(DOUBLEDASH) - && !arg.startsWith("-") && new File(arg).exists()) + && !arg.startsWith("-") && !arg.equals("open") + && (new File(arg).exists() + || HttpUtils.startsWithHttpOrHttps(arg))) { - arg = Arg.OPENNEW.argString(); + arg = Arg.OPEN.argString(); } else { @@ -243,7 +269,9 @@ public class ArgParser if (a == null) { // arg not found - Console.error("Argument '" + arg + "' not recognised. Ignoring."); + Console.error("Argument '" + arg + "' not recognised. Exiting."); + Jalview.exit("Unrecognised command line argument '" + arg + "'", + 13); continue; } if (a.hasOption(Opt.PRIVATE) && !allowPrivate) @@ -327,11 +355,7 @@ public class ArgParser // make NOACTION adjustments // default and auto counter increments - if (a == Arg.INCREMENT) - { - defaultLinkedIdCounter++; - } - else if (a == Arg.NPP) + if (a == Arg.NPP) { linkedIdAutoCounter++; } @@ -347,24 +371,29 @@ public class ArgParser { argFile = null; } + else if (a == Arg.ALL) + { + allLinkedIds = !negated; + } + + // this is probably only Arg.NEW and Arg.OPEN + if (a.hasOption(Opt.INCREMENTDEFAULTCOUNTER)) + { + // use the next default prefixed OPENLINKEDID + defaultLinkedId(true); + } String autoCounterString = null; boolean usingAutoCounterLinkedId = false; - String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX) - .append(Integer.toString(defaultLinkedIdCounter)) - .toString(); + String defaultLinkedId = defaultLinkedId(false); boolean usingDefaultLinkedId = false; if (a.hasOption(Opt.LINKED)) { if (linkedId == null) { - if (a == Arg.OPENNEW) + if (allLinkedIds && a.hasOption(Opt.ALLOWALL)) { - // use the next default prefixed OPENNEWLINKEDID - linkedId = new StringBuilder(OPENNEWLINKEDIDPREFIX) - .append(Integer.toString(opennewLinkedIdCounter)) - .toString(); - opennewLinkedIdCounter++; + linkedId = MATCHALLLINKEDIDS; } else { @@ -397,14 +426,11 @@ public class ArgParser } } - if (!linkedArgs.containsKey(linkedId)) - linkedArgs.put(linkedId, new ArgValuesMap()); - - // do not continue for NOACTION args + // do not continue in this block for NOACTION args if (a.hasOption(Opt.NOACTION)) continue; - ArgValuesMap avm = linkedArgs.get(linkedId); + ArgValuesMap avm = getOrCreateLinkedArgValuesMap(linkedId); // not dealing with both NODUPLICATEVALUES and GLOB if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val)) @@ -425,7 +451,10 @@ public class ArgParser continue; } - boolean argIndexIncremented = false; + /* TODO + * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*" + * DONE, need to check + */ ArgValues avs = avm.getOrCreateArgValues(a); // store appropriate String value(s) @@ -434,55 +463,90 @@ public class ArgParser if (a.hasOption(Opt.GLOB) && globVals != null && globVals.size() > 0) { - for (String v : globVals) + Enumeration gve = Collections.enumeration(globVals); + while (gve.hasMoreElements()) { - v = makeSubstitutions(v, linkedId); + String v = gve.nextElement(); SubVals vsv = new SubVals(globSubVals, v); - avs.addValue(vsv, v, argIndex++); - argIndexIncremented = true; + addValue(linkedId, avs, vsv, v, argIndex++, true); + // if we're using defaultLinkedId and the arg increments the + // counter: + if (gve.hasMoreElements() && usingDefaultLinkedId + && a.hasOption(Opt.INCREMENTDEFAULTCOUNTER)) + { + // increment the default linkedId + linkedId = defaultLinkedId(true); + // get new avm and avs + avm = linkedArgs.get(linkedId); + avs = avm.getOrCreateArgValues(a); + } } } else { - avs.addValue(makeSubstitutions(val, linkedId), argIndex); + addValue(linkedId, avs, val, argIndex, true); } } else if (a.hasOption(Opt.BOOLEAN)) { - avs.setBoolean(!negated, argIndex); - avs.setNegated(negated); + setBoolean(linkedId, avs, !negated, argIndex); + setNegated(linkedId, avs, negated); } else if (a.hasOption(Opt.UNARY)) { - avs.setBoolean(true, argIndex); + setBoolean(linkedId, avs, true, argIndex); } - avs.incrementCount(); - if (!argIndexIncremented) - argIndex++; - // store in appropriate place - if (a.hasOption(Opt.LINKED)) + // remove the '*' linkedId that should be empty if it was created + if (MATCHALLLINKEDIDS.equals(linkedId) + && linkedArgs.containsKey(linkedId)) { - // store the order of linkedIds - if (linkedOrder == null) - linkedOrder = new ArrayList<>(); - if (!linkedOrder.contains(linkedId)) - linkedOrder.add(linkedId); + linkedArgs.remove(linkedId); } + } + } + } + + private void finaliseStoringArgValue(String linkedId, ArgValues avs) + { + Arg a = avs.arg(); + incrementCount(linkedId, avs); + argIndex++; + + // store in appropriate place + if (a.hasOption(Opt.LINKED)) + { + // store the order of linkedIds + if (!linkedOrder.contains(linkedId)) + linkedOrder.add(linkedId); + } - // store arg in the list of args used - if (argList == null) - argList = new ArrayList<>(); - if (!argList.contains(a)) - argList.add(a); + // store arg in the list of args used + if (!argList.contains(a)) + argList.add(a); + } + private String defaultLinkedId(boolean increment) + { + String defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX) + .append(Integer.toString(defaultLinkedIdCounter)).toString(); + if (increment) + { + while (linkedArgs.containsKey(defaultLinkedId)) + { + defaultLinkedIdCounter++; + defaultLinkedId = new StringBuilder(DEFAULTLINKEDIDPREFIX) + .append(Integer.toString(defaultLinkedIdCounter)) + .toString(); } } + getOrCreateLinkedArgValuesMap(defaultLinkedId); + return defaultLinkedId; } - private String makeSubstitutions(String val, String linkedId) + public String makeSubstitutions(String val, String linkedId) { - if (!this.substitutions) + if (!this.substitutions || val == null) return val; String subvals; @@ -560,9 +624,24 @@ public class ArgParser return vals; } + public BootstrapArgs getBootstrapArgs() + { + return bootstrapArgs; + } + public boolean isSet(Arg a) { - return a.hasOption(Opt.LINKED) ? isSet("", a) : isSet(null, a); + return a.hasOption(Opt.LINKED) ? isSetAtAll(a) : isSet(null, a); + } + + public boolean isSetAtAll(Arg a) + { + for (String linkedId : linkedOrder) + { + if (isSet(linkedId, a)) + return true; + } + return false; } public boolean isSet(String linkedId, Arg a) @@ -571,7 +650,7 @@ public class ArgParser return avm == null ? false : avm.containsArg(a); } - public boolean getBool(Arg a) + public boolean getBoolean(Arg a) { if (!a.hasOption(Opt.BOOLEAN) && !a.hasOption(Opt.UNARY)) { @@ -590,12 +669,12 @@ public class ArgParser return avs == null ? a.getDefaultBoolValue() : avs.getBoolean(); } - public List linkedIds() + public List getLinkedIds() { return linkedOrder; } - public ArgValuesMap linkedArgs(String id) + public ArgValuesMap getLinkedArgs(String id) { return linkedArgs.get(id); } @@ -606,16 +685,16 @@ public class ArgParser StringBuilder sb = new StringBuilder(); sb.append("UNLINKED\n"); sb.append(argValuesMapToString(linkedArgs.get(null))); - if (linkedIds() != null) + if (getLinkedIds() != null) { sb.append("LINKED\n"); - for (String id : linkedIds()) + for (String id : getLinkedIds()) { // already listed these as UNLINKED args if (id == null) continue; - ArgValuesMap avm = linkedArgs(id); + ArgValuesMap avm = getLinkedArgs(id); sb.append("ID: '").append(id).append("'\n"); sb.append(argValuesMapToString(avm)); } @@ -638,7 +717,7 @@ public class ArgParser } public static ArgParser parseArgFiles(List argFilenameGlobs, - boolean initsubstitutions) + boolean initsubstitutions, BootstrapArgs bsa) { List argFiles = new ArrayList<>(); @@ -648,11 +727,11 @@ public class ArgParser argFiles.addAll(FileUtils.getFilesFromGlob(pattern)); } - return parseArgFileList(argFiles, initsubstitutions); + return parseArgFileList(argFiles, initsubstitutions, bsa); } public static ArgParser parseArgFileList(List argFiles, - boolean initsubstitutions) + boolean initsubstitutions, BootstrapArgs bsa) { List argsList = new ArrayList<>(); for (File argFile : argFiles) @@ -680,7 +759,7 @@ public class ArgParser } // Third param "true" uses Opt.PRIVATE args --setargile=argfile and // --unsetargfile - return new ArgParser(argsList, initsubstitutions, true); + return new ArgParser(argsList, initsubstitutions, true, bsa); } protected static List readArgFile(File argFile) @@ -707,4 +786,281 @@ public class ArgParser return args; } + public static enum Position + { + FIRST, BEFORE, AFTER + } + + // get from following Arg of type a or subval of same name (lowercase) + public static String getValueFromSubValOrArg(ArgValuesMap avm, + ArgValue av, Arg a, SubVals sv) + { + return getFromSubValArgOrPref(avm, av, a, sv, null, null, null); + } + + // get from following Arg of type a or subval key or preference pref or + // default def + public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av, + Arg a, SubVals sv, String key, String pref, String def) + { + return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref, + def); + } + + // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE) + // Arg of type a or subval key or preference pref or default def + public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a, + Position pos, ArgValue av, SubVals sv, String key, String pref, + String def) + { + return getFromSubValArgOrPrefWithSubstitutions(null, avm, a, pos, av, + sv, key, pref, def); + } + + public static String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, + ArgValuesMap avm, Arg a, Position pos, ArgValue av, SubVals sv, + String key, String pref, String def) + { + if (key == null) + key = a.getName(); + String value = null; + if (sv != null && sv.has(key) && sv.get(key) != null) + { + value = ap == null ? sv.get(key) + : sv.getWithSubstitutions(ap, avm.getLinkedId(), key); + } + else if (avm != null && avm.containsArg(a)) + { + if (pos == Position.FIRST && avm.getValue(a) != null) + value = avm.getValue(a); + else if (pos == Position.BEFORE + && avm.getClosestPreviousArgValueOfArg(av, a) != null) + value = avm.getClosestPreviousArgValueOfArg(av, a).getValue(); + else if (pos == Position.AFTER + && avm.getClosestNextArgValueOfArg(av, a) != null) + value = avm.getClosestNextArgValueOfArg(av, a).getValue(); + } + else + { + value = pref != null ? Cache.getDefault(pref, def) : def; + } + return value; + } + + public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a, + SubVals sv) + { + return getFromSubValArgOrPref(avm, a, sv, null, null, false); + } + + public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a, + SubVals sv, String key, String pref, boolean def) + { + if ((key == null && a == null) || (sv == null && a == null)) + return false; + + boolean usingArgKey = false; + if (key == null) + { + key = a.getName(); + usingArgKey = true; + } + + String nokey = ArgParser.NEGATESTRING + key; + + // look for key or nokey in subvals first (if using Arg check options) + if (sv != null) + { + // check for true boolean + if (sv.has(key) && sv.get(key) != null) + { + if (usingArgKey) + { + if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY))) + { + Console.debug( + "Looking for boolean in subval from non-boolean/non-unary Arg " + + a.getName()); + return false; + } + } + return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); + } + + // check for negative boolean (subval "no..." will be "true") + if (sv.has(nokey) && sv.get(nokey) != null) + { + if (usingArgKey) + { + if (!(a.hasOption(Opt.BOOLEAN))) + { + Console.debug( + "Looking for negative boolean in subval from non-boolean Arg " + + a.getName()); + return false; + } + } + return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true"); + } + } + + // check argvalues + if (avm != null && avm.containsArg(a)) + return avm.getBoolean(a); + + // return preference or default + return pref != null ? Cache.getDefault(pref, def) : def; + } + + // the following methods look for the "*" linkedId and add the argvalue to all + // linkedId ArgValues if it does + private void addValue(String linkedId, ArgValues avs, SubVals sv, + String v, int argIndex, boolean doSubs) + { + Arg a = avs.arg(); + if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + { + for (String id : getLinkedIds()) + { + if (id == null || MATCHALLLINKEDIDS.equals(id)) + continue; + ArgValuesMap avm = linkedArgs.get(id); + if (a.hasOption(Opt.REQUIREINPUT) + && !avm.hasArgWithOption(Opt.INPUT)) + continue; + ArgValues tavs = avm.getOrCreateArgValues(a); + String val = v; + if (doSubs) + { + val = makeSubstitutions(v, id); + sv = new SubVals(sv, val); + } + tavs.addValue(sv, val, argIndex); + finaliseStoringArgValue(id, tavs); + } + } + else + { + String val = v; + if (doSubs) + { + val = makeSubstitutions(v, linkedId); + sv = new SubVals(sv, val); + } + avs.addValue(sv, val, argIndex); + finaliseStoringArgValue(linkedId, avs); + } + } + + private void addValue(String linkedId, ArgValues avs, String v, + int argIndex, boolean doSubs) + { + Arg a = avs.arg(); + if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + { + for (String id : getLinkedIds()) + { + if (id == null || MATCHALLLINKEDIDS.equals(id)) + continue; + ArgValuesMap avm = linkedArgs.get(id); + // don't set an output if there isn't an input + if (a.hasOption(Opt.REQUIREINPUT) + && !avm.hasArgWithOption(Opt.INPUT)) + continue; + ArgValues tavs = avm.getOrCreateArgValues(a); + String val = doSubs ? makeSubstitutions(v, id) : v; + tavs.addValue(val, argIndex); + finaliseStoringArgValue(id, tavs); + } + } + else + { + String val = doSubs ? makeSubstitutions(v, linkedId) : v; + avs.addValue(val, argIndex); + finaliseStoringArgValue(linkedId, avs); + } + } + + private void setBoolean(String linkedId, ArgValues avs, boolean b, + int argIndex) + { + Arg a = avs.arg(); + if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + { + for (String id : getLinkedIds()) + { + if (id == null || MATCHALLLINKEDIDS.equals(id)) + continue; + ArgValuesMap avm = linkedArgs.get(id); + if (a.hasOption(Opt.REQUIREINPUT) + && !avm.hasArgWithOption(Opt.INPUT)) + continue; + ArgValues tavs = avm.getOrCreateArgValues(a); + tavs.setBoolean(b, argIndex); + finaliseStoringArgValue(id, tavs); + } + } + else + { + avs.setBoolean(b, argIndex); + finaliseStoringArgValue(linkedId, avs); + } + } + + private void setNegated(String linkedId, ArgValues avs, boolean b) + { + Arg a = avs.arg(); + if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + { + for (String id : getLinkedIds()) + { + if (id == null || MATCHALLLINKEDIDS.equals(id)) + continue; + ArgValuesMap avm = linkedArgs.get(id); + if (a.hasOption(Opt.REQUIREINPUT) + && !avm.hasArgWithOption(Opt.INPUT)) + continue; + ArgValues tavs = avm.getOrCreateArgValues(a); + tavs.setNegated(b); + } + } + else + { + avs.setNegated(b); + } + } + + private void incrementCount(String linkedId, ArgValues avs) + { + Arg a = avs.arg(); + if (MATCHALLLINKEDIDS.equals(linkedId) && a.hasOption(Opt.ALLOWALL)) + { + for (String id : getLinkedIds()) + { + if (id == null || MATCHALLLINKEDIDS.equals(id)) + continue; + ArgValuesMap avm = linkedArgs.get(id); + if (a.hasOption(Opt.REQUIREINPUT) + && !avm.hasArgWithOption(Opt.INPUT)) + continue; + ArgValues tavs = avm.getOrCreateArgValues(a); + tavs.incrementCount(); + } + } + else + { + avs.incrementCount(); + } + } + + private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId) + { + if (linkedArgs.containsKey(linkedId) + && linkedArgs.get(linkedId) != null) + return linkedArgs.get(linkedId); + + linkedArgs.put(linkedId, new ArgValuesMap(linkedId)); + return linkedArgs.get(linkedId); + } + } \ No newline at end of file