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))
157 if ((val == null && i + 1 < args.size()
158 && ArgParser.STDOUTFILENAME.equals(args.get(i + 1)))
159 || ArgParser.STDOUTFILENAME.equals(val))
161 this.outputToStdout = true;
168 if (a.hasOption(Opt.STRING))
170 List<String> vals = null;
173 vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
177 if (a.hasOption(Opt.GLOB))
179 vals = FileUtils.getFilenamesFromGlob(val);
183 vals = new ArrayList<>();
187 addAll(a, type, vals);
189 if (a == Arg.ARGFILE)
191 for (String filename : vals)
193 File argFile = new File(filename);
194 parse(ArgParser.readArgFile(argFile), argFile);
211 public boolean contains(Arg a)
213 return bootstrapArgMap.containsKey(a);
216 public boolean containsType(Type t)
218 for (List<Map.Entry<Type, String>> l : bootstrapArgMap.values())
220 for (Map.Entry<Type, String> e : l)
229 public List<Arg> getArgsOfType(Type t)
231 return getArgsOfType(t, new Opt[] {});
234 public List<Arg> getArgsOfType(Type t, Opt... opts)
236 List<Arg> args = new ArrayList<>();
237 for (Arg a : bootstrapArgMap.keySet())
239 if (!a.hasAllOptions(opts))
242 List<Map.Entry<Type, String>> l = bootstrapArgMap.get(a);
243 if (l.stream().anyMatch(e -> e.getKey() == t))
251 public List<Map.Entry<Type, String>> getList(Arg a)
253 return bootstrapArgMap.get(a);
256 public List<String> getValueList(Arg a)
258 return bootstrapArgMap.get(a).stream().map(e -> e.getValue())
259 .collect(Collectors.toList());
262 private List<Map.Entry<Type, String>> getOrCreateList(Arg a)
264 List<Map.Entry<Type, String>> l = getList(a);
267 l = new ArrayList<>();
273 private void putList(Arg a, List<Map.Entry<Type, String>> l)
275 bootstrapArgMap.put(a, l);
279 * Creates a new list if not used before,
280 * adds the value unless the existing list is non-empty
281 * and the arg is not MULTI (so first expressed value is
284 private void add(Arg a, Type t, String s)
286 List<Map.Entry<Type, String>> l = getOrCreateList(a);
287 if (a.hasOption(Opt.MULTI) || l.size() == 0)
293 private void addAll(Arg a, Type t, List<String> al)
295 List<Map.Entry<Type, String>> l = getOrCreateList(a);
296 if (a.hasOption(Opt.MULTI))
303 else if (l.size() == 0 && al.size() > 0)
305 l.add(entry(t, al.get(0)));
309 private static Map.Entry<Type, String> entry(Type t, String s)
311 return new AbstractMap.SimpleEntry<Type, String>(t, s);
315 * Retrieves the first value even if MULTI.
316 * A convenience for non-MULTI args.
318 public String getValue(Arg a)
320 if (!bootstrapArgMap.containsKey(a))
322 List<Map.Entry<Type, String>> aL = bootstrapArgMap.get(a);
323 return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue();
326 public boolean getBoolean(Arg a, boolean d)
328 if (!bootstrapArgMap.containsKey(a))
330 return Boolean.parseBoolean(getValue(a));
333 public boolean getBoolean(Arg a)
335 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
339 if (bootstrapArgMap.containsKey(a))
341 return Boolean.parseBoolean(getValue(a));
345 return a.getDefaultBoolValue();
349 public boolean argsHaveOption(Opt opt)
351 return argsOptions.contains(opt);
354 public boolean argsHaveType(Type type)
356 return argsTypes.contains(type);
359 public boolean isHeadless()
361 boolean isHeadless = false;
362 if (this.argsHaveType(Type.HELP))
364 // --help, --help-all, ... specified => headless
367 else if (this.contains(Arg.VERSION))
369 // --version specified => headless
372 else if (this.contains(Arg.GUI))
374 // --gui specified => forced NOT headless
375 isHeadless = !this.getBoolean(Arg.GUI);
377 else if (this.contains(Arg.HEADLESS))
379 // --headless, --noheadless specified => use value
380 isHeadless = this.getBoolean(Arg.HEADLESS);
382 else if (this.argsHaveOption(Opt.OUTPUTFILE))
384 // --output file.fa, --image pic.png, --structureimage struct.png =>
385 // assume headless unless above has been already specified
391 public boolean outputToStdout()
393 return this.outputToStdout;