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))
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 System.err.println("###### Found an output");
158 System.err.println("###### val='" + val + "'");
160 .println("###### next arg='" + args.get(i + 1) + "'");
161 if ((val == null && i + 1 < args.size()
162 && ArgParser.STDOUTFILENAME.equals(args.get(i + 1)))
163 || ArgParser.STDOUTFILENAME.equals(val))
165 this.outputToStdout = true;
166 System.err.println("###### Expecting output to stdout");
173 if (a.hasOption(Opt.STRING))
175 List<String> vals = null;
178 vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
182 if (a.hasOption(Opt.GLOB))
184 vals = FileUtils.getFilenamesFromGlob(val);
188 vals = new ArrayList<>();
192 addAll(a, type, vals);
194 if (a == Arg.ARGFILE)
196 for (String filename : vals)
198 File argFile = new File(filename);
199 parse(ArgParser.readArgFile(argFile), argFile);
216 public boolean contains(Arg a)
218 return bootstrapArgMap.containsKey(a);
221 public boolean containsType(Type t)
223 for (List<Map.Entry<Type, String>> l : bootstrapArgMap.values())
225 for (Map.Entry<Type, String> e : l)
234 public List<Arg> getArgsOfType(Type t)
236 return getArgsOfType(t, new Opt[] {});
239 public List<Arg> getArgsOfType(Type t, Opt... opts)
241 List<Arg> args = new ArrayList<>();
242 for (Arg a : bootstrapArgMap.keySet())
244 if (!a.hasAllOptions(opts))
247 List<Map.Entry<Type, String>> l = bootstrapArgMap.get(a);
248 if (l.stream().anyMatch(e -> e.getKey() == t))
256 public List<Map.Entry<Type, String>> getList(Arg a)
258 return bootstrapArgMap.get(a);
261 public List<String> getValueList(Arg a)
263 return bootstrapArgMap.get(a).stream().map(e -> e.getValue())
264 .collect(Collectors.toList());
267 private List<Map.Entry<Type, String>> getOrCreateList(Arg a)
269 List<Map.Entry<Type, String>> l = getList(a);
272 l = new ArrayList<>();
278 private void putList(Arg a, List<Map.Entry<Type, String>> l)
280 bootstrapArgMap.put(a, l);
284 * Creates a new list if not used before,
285 * adds the value unless the existing list is non-empty
286 * and the arg is not MULTI (so first expressed value is
289 private void add(Arg a, Type t, String s)
291 List<Map.Entry<Type, String>> l = getOrCreateList(a);
292 if (a.hasOption(Opt.MULTI) || l.size() == 0)
298 private void addAll(Arg a, Type t, List<String> al)
300 List<Map.Entry<Type, String>> l = getOrCreateList(a);
301 if (a.hasOption(Opt.MULTI))
308 else if (l.size() == 0 && al.size() > 0)
310 l.add(entry(t, al.get(0)));
314 private static Map.Entry<Type, String> entry(Type t, String s)
316 return new AbstractMap.SimpleEntry<Type, String>(t, s);
320 * Retrieves the first value even if MULTI.
321 * A convenience for non-MULTI args.
323 public String getValue(Arg a)
325 if (!bootstrapArgMap.containsKey(a))
327 List<Map.Entry<Type, String>> aL = bootstrapArgMap.get(a);
328 return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue();
331 public boolean getBoolean(Arg a, boolean d)
333 if (!bootstrapArgMap.containsKey(a))
335 return Boolean.parseBoolean(getValue(a));
338 public boolean getBoolean(Arg a)
340 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
344 if (bootstrapArgMap.containsKey(a))
346 return Boolean.parseBoolean(getValue(a));
350 return a.getDefaultBoolValue();
354 public boolean argsHaveOption(Opt opt)
356 return argsOptions.contains(opt);
359 public boolean argsHaveType(Type type)
361 return argsTypes.contains(type);
364 public boolean isHeadless()
366 boolean isHeadless = false;
367 if (this.argsHaveType(Type.HELP))
369 // --help, --help-all, ... specified => headless
372 else if (this.contains(Arg.VERSION))
374 // --version specified => headless
377 else if (this.contains(Arg.GUI))
379 // --gui specified => forced NOT headless
380 isHeadless = !this.getBoolean(Arg.GUI);
382 else if (this.contains(Arg.HEADLESS))
384 // --headless, --noheadless specified => use value
385 isHeadless = this.getBoolean(Arg.HEADLESS);
387 else if (this.argsHaveOption(Opt.OUTPUTFILE))
389 // --output file.fa, --image pic.png, --structureimage struct.png =>
390 // assume headless unless above has been already specified
396 public boolean outputToStdout()
398 return this.outputToStdout;