1 package jalview.bin.argparser;
4 import java.util.AbstractMap;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.HashSet;
10 import java.util.Locale;
13 import java.util.stream.Collectors;
15 import jalview.bin.argparser.Arg.Opt;
16 import jalview.bin.argparser.Arg.Type;
17 import jalview.util.FileUtils;
19 public class BootstrapArgs
22 private Map<Arg, List<Map.Entry<Type, String>>> bootstrapArgMap = new HashMap<>();
24 private Set<File> argFiles = new HashSet<>();
26 public static BootstrapArgs getBootstrapArgs(String[] args)
28 List<String> argList = new ArrayList<>(Arrays.asList(args));
29 return new BootstrapArgs(argList);
32 public static BootstrapArgs getBootstrapArgs(List<String> args)
34 return new BootstrapArgs(args);
37 private BootstrapArgs(List<String> args)
42 private void parse(List<String> args, File inArgFile)
46 // avoid looping argFiles
47 if (inArgFile != null)
49 if (argFiles.contains(inArgFile))
52 "Looped argfiles detected: '" + inArgFile.getPath() + "'");
55 argFiles.add(inArgFile);
58 for (int i = 0; i < args.size(); i++)
60 String arg = args.get(i);
61 // look for double-dash, e.g. --arg
62 if (arg.startsWith(ArgParser.DOUBLEDASH))
64 String argName = null;
68 argName = arg.substring(ArgParser.DOUBLEDASH.length());
70 // look for equals e.g. --arg=value
71 int equalPos = argName.indexOf(ArgParser.EQUALS);
74 val = argName.substring(equalPos + 1);
75 argName = argName.substring(0, equalPos);
78 // check for boolean prepended by "no"
79 if (argName.startsWith(ArgParser.NEGATESTRING)
80 && ArgParser.argMap.containsKey(
81 argName.substring(ArgParser.NEGATESTRING.length())))
84 argName = argName.substring(ArgParser.NEGATESTRING.length());
87 // look for type modification e.g. --help-opening
88 int dashPos = argName.indexOf(ArgParser.SINGLEDASH);
91 String potentialArgName = argName.substring(0, dashPos);
92 Arg potentialArg = ArgParser.argMap.get(potentialArgName);
93 if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE))
95 String typeName = argName.substring(dashPos + 1);
98 type = Type.valueOf(typeName.toUpperCase(Locale.ROOT));
99 } catch (IllegalArgumentException e)
103 argName = argName.substring(0, dashPos);
107 if (ArgParser.argMap.containsKey(argName) && val == null)
112 Arg a = ArgParser.argMap.get(argName);
114 if (a == null || !a.hasOption(Opt.BOOTSTRAP))
116 // not a valid bootstrap arg
120 if (a.hasOption(Opt.STRING))
122 List<String> vals = null;
125 vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
129 if (a.hasOption(Opt.GLOB))
131 vals = FileUtils.getFilenamesFromGlob(val);
135 vals = new ArrayList<>();
139 addAll(a, type, vals);
141 if (a == Arg.ARGFILE)
143 for (String filename : vals)
145 File argFile = new File(filename);
146 parse(ArgParser.readArgFile(argFile), argFile);
158 public boolean contains(Arg a)
160 return bootstrapArgMap.containsKey(a);
163 public boolean containsType(Type t)
165 for (List<Map.Entry<Type, String>> l : bootstrapArgMap.values())
167 for (Map.Entry<Type, String> e : l)
176 public List<Arg> getArgsOfType(Type t)
178 return getArgsOfType(t, new Opt[] {});
181 public List<Arg> getArgsOfType(Type t, Opt... opts)
183 List<Arg> args = new ArrayList<>();
184 for (Arg a : bootstrapArgMap.keySet())
186 if (!a.hasAllOptions(opts))
189 List<Map.Entry<Type, String>> l = bootstrapArgMap.get(a);
190 if (l.stream().anyMatch(e -> e.getKey() == t))
198 public List<Map.Entry<Type, String>> getList(Arg a)
200 return bootstrapArgMap.get(a);
203 public List<String> getValueList(Arg a)
205 return bootstrapArgMap.get(a).stream().map(e -> e.getValue())
206 .collect(Collectors.toList());
209 private List<Map.Entry<Type, String>> getOrCreateList(Arg a)
211 List<Map.Entry<Type, String>> l = getList(a);
214 l = new ArrayList<>();
220 private void putList(Arg a, List<Map.Entry<Type, String>> l)
222 bootstrapArgMap.put(a, l);
226 * Creates a new list if not used before,
227 * adds the value unless the existing list is non-empty
228 * and the arg is not MULTI (so first expressed value is
231 private void add(Arg a, Type t, String s)
233 List<Map.Entry<Type, String>> l = getOrCreateList(a);
234 if (a.hasOption(Opt.MULTI) || l.size() == 0)
240 private void addAll(Arg a, Type t, List<String> al)
242 List<Map.Entry<Type, String>> l = getOrCreateList(a);
243 if (a.hasOption(Opt.MULTI))
250 else if (l.size() == 0 && al.size() > 0)
252 l.add(entry(t, al.get(0)));
256 private static Map.Entry<Type, String> entry(Type t, String s)
258 return new AbstractMap.SimpleEntry<Type, String>(t, s);
262 * Retrieves the first value even if MULTI.
263 * A convenience for non-MULTI args.
265 public String get(Arg a)
267 if (!bootstrapArgMap.containsKey(a))
269 List<Map.Entry<Type, String>> aL = bootstrapArgMap.get(a);
270 return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue();
273 public boolean getBoolean(Arg a, boolean d)
275 if (!bootstrapArgMap.containsKey(a))
277 return Boolean.parseBoolean(get(a));
280 public boolean getBoolean(Arg a)
282 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
286 if (bootstrapArgMap.containsKey(a))
287 return Boolean.parseBoolean(get(a));
289 return a.getDefaultBoolValue();