1 package jalview.bin.argparser;
4 import java.util.AbstractMap;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.EnumSet;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Locale;
14 import java.util.stream.Collectors;
16 import jalview.bin.argparser.Arg.Opt;
17 import jalview.bin.argparser.Arg.Type;
18 import jalview.util.FileUtils;
20 public class BootstrapArgs
23 private Map<Arg, List<Map.Entry<Type, String>>> bootstrapArgMap = new HashMap<>();
25 private Set<File> argFiles = new HashSet<>();
27 private Set<Opt> argsOptions = new HashSet<>();
29 private Set<Type> argsTypes = new HashSet<>();
31 private boolean outputToStdout = false;
33 public static BootstrapArgs getBootstrapArgs(String[] args)
35 List<String> argList = new ArrayList<>(Arrays.asList(args));
36 return new BootstrapArgs(argList);
39 public static BootstrapArgs getBootstrapArgs(List<String> args)
41 return new BootstrapArgs(args);
44 private BootstrapArgs(List<String> args)
49 private void parse(List<String> args, File inArgFile)
53 // avoid looping argFiles
54 if (inArgFile != null)
56 if (argFiles.contains(inArgFile))
58 jalview.bin.Console.errPrintln(
59 "Looped argfiles detected: '" + inArgFile.getPath() + "'");
62 argFiles.add(inArgFile);
65 for (int i = 0; i < args.size(); i++)
67 String arg = args.get(i);
68 // look for double-dash, e.g. --arg
69 if (arg.startsWith(ArgParser.DOUBLEDASH))
71 String argName = null;
75 argName = arg.substring(ArgParser.DOUBLEDASH.length());
77 // look for equals e.g. --arg=value
78 int equalPos = argName.indexOf(ArgParser.EQUALS);
81 val = argName.substring(equalPos + 1);
82 argName = argName.substring(0, equalPos);
85 // check for boolean prepended by "no"
86 if (argName.startsWith(ArgParser.NEGATESTRING)
87 && ArgParser.argMap.containsKey(
88 argName.substring(ArgParser.NEGATESTRING.length())))
91 argName = argName.substring(ArgParser.NEGATESTRING.length());
94 // look for type modification e.g. --help-opening
95 int dashPos = argName.indexOf(ArgParser.SINGLEDASH);
98 String potentialArgName = argName.substring(0, dashPos);
99 Arg potentialArg = ArgParser.argMap.get(potentialArgName);
100 if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE))
102 String typeName = argName.substring(dashPos + 1);
105 type = Type.valueOf(typeName.toUpperCase(Locale.ROOT));
106 } catch (IllegalArgumentException e)
110 argName = argName.substring(0, dashPos);
114 // after all other args, look for Opt.PREFIX args if still not found
115 if (!ArgParser.argMap.containsKey(argName))
117 for (Arg potentialArg : EnumSet.allOf(Arg.class))
119 if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
120 && argName.startsWith(potentialArg.getName())
123 val = argName.substring(potentialArg.getName().length())
124 + ArgParser.EQUALS + val;
125 argName = argName.substring(0,
126 potentialArg.getName().length());
132 Arg a = ArgParser.argMap.get(argName);
136 for (Opt opt : a.getOptions())
138 if (!argsOptions.contains(opt))
140 argsOptions.add(opt);
143 Type t = a.getType();
144 if (!argsTypes.contains(t))
150 if (a == null || !a.hasOption(Opt.BOOTSTRAP))
152 // not a bootstrap arg
154 // make a check for an output going to stdout
155 if (a != null && a.hasOption(Opt.OUTPUTFILE)
156 && a.hasOption(Opt.STDOUT))
158 if (val == null && i + 1 < args.size())
160 val = args.get(i + 1);
162 if (val.startsWith("[") && val.indexOf(']') > 0)
164 val = val.substring(val.indexOf(']') + 1);
167 if (ArgParser.STDOUTFILENAME.equals(val))
169 this.outputToStdout = true;
176 if (a.hasOption(Opt.STRING))
178 List<String> vals = null;
181 vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
185 if (a.hasOption(Opt.GLOB))
187 vals = FileUtils.getFilenamesFromGlob(val);
191 vals = new ArrayList<>();
195 addAll(a, type, vals);
197 if (a == Arg.ARGFILE)
199 for (String filename : vals)
201 File argFile = new File(filename);
202 parse(ArgParser.readArgFile(argFile), argFile);
219 public boolean contains(Arg a)
221 return bootstrapArgMap.containsKey(a);
224 public boolean containsType(Type t)
226 for (List<Map.Entry<Type, String>> l : bootstrapArgMap.values())
228 for (Map.Entry<Type, String> e : l)
237 public List<Arg> getArgsOfType(Type t)
239 return getArgsOfType(t, new Opt[] {});
242 public List<Arg> getArgsOfType(Type t, Opt... opts)
244 List<Arg> args = new ArrayList<>();
245 for (Arg a : bootstrapArgMap.keySet())
247 if (!a.hasAllOptions(opts))
250 List<Map.Entry<Type, String>> l = bootstrapArgMap.get(a);
251 if (l.stream().anyMatch(e -> e.getKey() == t))
259 public List<Map.Entry<Type, String>> getList(Arg a)
261 return bootstrapArgMap.get(a);
264 public List<String> getValueList(Arg a)
266 return bootstrapArgMap.get(a).stream().map(e -> e.getValue())
267 .collect(Collectors.toList());
270 private List<Map.Entry<Type, String>> getOrCreateList(Arg a)
272 List<Map.Entry<Type, String>> l = getList(a);
275 l = new ArrayList<>();
281 private void putList(Arg a, List<Map.Entry<Type, String>> l)
283 bootstrapArgMap.put(a, l);
287 * Creates a new list if not used before,
288 * adds the value unless the existing list is non-empty
289 * and the arg is not MULTI (so first expressed value is
292 private void add(Arg a, Type t, String s)
294 List<Map.Entry<Type, String>> l = getOrCreateList(a);
295 if (a.hasOption(Opt.MULTIVALUE) || l.size() == 0)
301 private void addAll(Arg a, Type t, List<String> al)
303 List<Map.Entry<Type, String>> l = getOrCreateList(a);
304 if (a.hasOption(Opt.MULTIVALUE))
311 else if (l.size() == 0 && al.size() > 0)
313 l.add(entry(t, al.get(0)));
317 private static Map.Entry<Type, String> entry(Type t, String s)
319 return new AbstractMap.SimpleEntry<Type, String>(t, s);
323 * Retrieves the first value even if MULTI.
324 * A convenience for non-MULTI args.
326 public String getValue(Arg a)
328 if (!bootstrapArgMap.containsKey(a))
330 List<Map.Entry<Type, String>> aL = bootstrapArgMap.get(a);
331 return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue();
334 public boolean getBoolean(Arg a, boolean d)
336 if (!bootstrapArgMap.containsKey(a))
338 return Boolean.parseBoolean(getValue(a));
341 public boolean getBoolean(Arg a)
343 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
347 if (bootstrapArgMap.containsKey(a))
349 return Boolean.parseBoolean(getValue(a));
353 return a.getDefaultBoolValue();
357 public boolean argsHaveOption(Opt opt)
359 return argsOptions.contains(opt);
362 public boolean argsHaveType(Type type)
364 return argsTypes.contains(type);
367 public boolean isHeadless()
369 boolean isHeadless = false;
370 if (this.argsHaveType(Type.HELP))
372 // --help, --help-all, ... specified => headless
375 else if (this.contains(Arg.VERSION))
377 // --version specified => headless
380 else if (this.contains(Arg.GUI))
382 // --gui specified => forced NOT headless
383 isHeadless = !this.getBoolean(Arg.GUI);
385 else if (this.contains(Arg.HEADLESS))
387 // --headless has been specified on the command line => headless
388 isHeadless = this.getBoolean(Arg.HEADLESS);
390 else if (this.argsHaveOption(Opt.OUTPUTFILE))
392 // --output file.fa, --image pic.png, --structureimage struct.png =>
393 // assume headless unless above has been already specified
399 public boolean outputToStdout()
401 return this.outputToStdout;