Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.bin.argparser

File BootstrapArgs.java

 

Coverage histogram

../../../img/srcFileCovDistChart9.png
13% of files have more coverage

Code metrics

84
136
22
1
432
339
79
0.58
6.18
22
3.59

Classes

Class Line # Actions
BootstrapArgs 40 136 79
0.814049681.4%
 

Contributing tests

This file is covered by 170 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.bin.argparser;
22   
23    import java.io.File;
24    import java.util.AbstractMap;
25    import java.util.ArrayList;
26    import java.util.Arrays;
27    import java.util.EnumSet;
28    import java.util.HashMap;
29    import java.util.HashSet;
30    import java.util.List;
31    import java.util.Locale;
32    import java.util.Map;
33    import java.util.Set;
34    import java.util.stream.Collectors;
35   
36    import jalview.bin.argparser.Arg.Opt;
37    import jalview.bin.argparser.Arg.Type;
38    import jalview.util.FileUtils;
39   
 
40    public class BootstrapArgs
41    {
42    // only need one
43    private Map<Arg, List<Map.Entry<Type, String>>> bootstrapArgMap = new HashMap<>();
44   
45    private Set<File> argFiles = new HashSet<>();
46   
47    private Set<Opt> argsOptions = new HashSet<>();
48   
49    private Set<Type> argsTypes = new HashSet<>();
50   
51    private boolean outputToStdout = false;
52   
 
53  156 toggle public static BootstrapArgs getBootstrapArgs(String[] args)
54    {
55  156 List<String> argList = new ArrayList<>(Arrays.asList(args));
56  156 return new BootstrapArgs(argList);
57    }
58   
 
59  46 toggle public static BootstrapArgs getBootstrapArgs(List<String> args)
60    {
61  46 return new BootstrapArgs(args);
62    }
63   
 
64  202 toggle private BootstrapArgs(List<String> args)
65    {
66  202 parse(args, null);
67    }
68   
 
69  255 toggle private void parse(List<String> args, File inArgFile)
70    {
71  255 if (args == null)
72  0 return;
73    // avoid looping argFiles
74  255 if (inArgFile != null)
75    {
76  53 if (argFiles.contains(inArgFile))
77    {
78  0 jalview.bin.Console.errPrintln(
79    "Looped argfiles detected: '" + inArgFile.getPath() + "'");
80  0 return;
81    }
82  53 argFiles.add(inArgFile);
83    }
84   
85  1488 for (int i = 0; i < args.size(); i++)
86    {
87  1233 String arg = args.get(i);
88    // look for double-dash, e.g. --arg
89  1233 if (arg.startsWith(ArgParser.DOUBLEDASH))
90    {
91  996 String argName = null;
92  996 String val = null;
93  996 Type type = null;
94    // remove "--"
95  996 argName = arg.substring(ArgParser.DOUBLEDASH.length());
96   
97    // look for equals e.g. --arg=value
98  996 int equalPos = argName.indexOf(ArgParser.EQUALS);
99  996 if (equalPos > -1)
100    {
101  471 val = argName.substring(equalPos + 1);
102  471 argName = argName.substring(0, equalPos);
103    }
104   
105    // check for boolean prepended by "no"
106  996 if (argName.startsWith(ArgParser.NEGATESTRING)
107    && ArgParser.argMap.containsKey(
108    argName.substring(ArgParser.NEGATESTRING.length())))
109    {
110  124 val = "false";
111  124 argName = argName.substring(ArgParser.NEGATESTRING.length());
112    }
113   
114    // look for type modification e.g. --help-opening
115  996 int dashPos = argName.indexOf(ArgParser.SINGLEDASH);
116  996 if (dashPos > -1)
117    {
118  43 String potentialArgName = argName.substring(0, dashPos);
119  43 Arg potentialArg = ArgParser.argMap.get(potentialArgName);
120  43 if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE))
121    {
122  3 String typeName = argName.substring(dashPos + 1);
123  3 try
124    {
125  3 type = Type.valueOf(typeName.toUpperCase(Locale.ROOT));
126    } catch (IllegalArgumentException e)
127    {
128  0 type = Type.INVALID;
129    }
130  3 argName = argName.substring(0, dashPos);
131    }
132    }
133   
134    // after all other args, look for Opt.PREFIX args if still not found
135  996 if (!ArgParser.argMap.containsKey(argName))
136    {
137  116 for (Arg potentialArg : EnumSet.allOf(Arg.class))
138    {
139  7888 if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
140    && argName.startsWith(potentialArg.getName())
141    && val != null)
142    {
143  0 val = argName.substring(potentialArg.getName().length())
144    + ArgParser.EQUALS + val;
145  0 argName = argName.substring(0,
146    potentialArg.getName().length());
147  0 break;
148    }
149    }
150    }
151   
152  996 Arg a = ArgParser.argMap.get(argName);
153   
154  996 if (a != null)
155    {
156  880 for (Opt opt : a.getOptions())
157    {
158  4133 if (!argsOptions.contains(opt))
159    {
160  1744 argsOptions.add(opt);
161    }
162    }
163  880 for (Type t : a.getTypes())
164    {
165  903 if (!argsTypes.contains(t))
166    {
167  428 argsTypes.add(t);
168    }
169    }
170    }
171   
172  996 if (a == null || !a.hasOption(Opt.BOOTSTRAP))
173    {
174    // not a bootstrap arg
175   
176    // make a check for an output going to stdout
177  695 if (a != null && a.hasOption(Opt.OUTPUTFILE)
178    && a.hasOption(Opt.STDOUT))
179    {
180  39 if (val == null && i + 1 < args.size())
181    {
182  25 val = args.get(i + 1);
183    }
184  39 if (val.startsWith("[") && val.indexOf(']') > 0)
185    {
186  1 val = val.substring(val.indexOf(']') + 1);
187    }
188   
189  39 if (ArgParser.STDOUTFILENAME.equals(val))
190    {
191  8 this.outputToStdout = true;
192    }
193    }
194   
195  695 continue;
196    }
197   
198  301 if (a.hasOption(Opt.STRING))
199    {
200  61 List<String> vals = null;
201  61 if (equalPos == -1)
202    {
203  29 vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
204    }
205    else
206    {
207  32 if (a.hasOption(Opt.GLOB))
208    {
209  15 vals = FileUtils.getFilenamesFromGlob(val);
210    }
211    else
212    {
213  17 vals = new ArrayList<>();
214  17 vals.add(val);
215    }
216    }
217  61 addAll(a, type, vals);
218   
219  61 if (a == Arg.ARGFILE)
220    {
221  23 for (String filename : vals)
222    {
223  53 File argFile = new File(filename);
224  53 parse(ArgParser.readArgFile(argFile), argFile);
225    }
226    }
227    }
228    else
229    {
230  240 if (val == null)
231    {
232  144 val = "true";
233    }
234   
235  240 add(a, type, val);
236    }
237    }
238    }
239   
240    // if in an argfile, remove it from the hashset so it can be re-used in
241    // another argfile
242  255 if (inArgFile != null)
243    {
244  53 argFiles.remove(inArgFile);
245    }
246    }
247   
 
248  1830 toggle public boolean contains(Arg a)
249    {
250  1830 return bootstrapArgMap.containsKey(a);
251    }
252   
 
253  0 toggle public boolean containsType(Type t)
254    {
255  0 for (List<Map.Entry<Type, String>> l : bootstrapArgMap.values())
256    {
257  0 for (Map.Entry<Type, String> e : l)
258    {
259  0 if (e.getKey() == t)
260  0 return true;
261    }
262    }
263  0 return false;
264    }
265   
 
266  0 toggle public List<Arg> getArgsOfType(Type t)
267    {
268  0 return getArgsOfType(t, new Opt[] {});
269    }
270   
 
271  0 toggle public List<Arg> getArgsOfType(Type t, Opt... opts)
272    {
273  0 List<Arg> args = new ArrayList<>();
274  0 for (Arg a : bootstrapArgMap.keySet())
275    {
276  0 if (!a.hasAllOptions(opts))
277  0 continue;
278   
279  0 List<Map.Entry<Type, String>> l = bootstrapArgMap.get(a);
280  0 if (l.stream().anyMatch(e -> e.getKey() == t))
281    {
282  0 args.add(a);
283    }
284    }
285  0 return args;
286    }
287   
 
288  301 toggle public List<Map.Entry<Type, String>> getList(Arg a)
289    {
290  301 return bootstrapArgMap.get(a);
291    }
292   
 
293  15 toggle public List<String> getValueList(Arg a)
294    {
295  15 return bootstrapArgMap.get(a).stream().map(e -> e.getValue())
296    .collect(Collectors.toList());
297    }
298   
 
299  301 toggle private List<Map.Entry<Type, String>> getOrCreateList(Arg a)
300    {
301  301 List<Map.Entry<Type, String>> l = getList(a);
302  301 if (l == null)
303    {
304  280 l = new ArrayList<>();
305  280 putList(a, l);
306    }
307  301 return l;
308    }
309   
 
310  280 toggle private void putList(Arg a, List<Map.Entry<Type, String>> l)
311    {
312  280 bootstrapArgMap.put(a, l);
313    }
314   
315    /*
316    * Creates a new list if not used before,
317    * adds the value unless the existing list is non-empty
318    * and the arg is not MULTI (so first expressed value is
319    * retained).
320    */
 
321  240 toggle private void add(Arg a, Type t, String s)
322    {
323  240 List<Map.Entry<Type, String>> l = getOrCreateList(a);
324  240 if (a.hasOption(Opt.MULTIVALUE) || l.size() == 0)
325    {
326  219 l.add(entry(t, s));
327    }
328    }
329   
 
330  61 toggle private void addAll(Arg a, Type t, List<String> al)
331    {
332  61 List<Map.Entry<Type, String>> l = getOrCreateList(a);
333  61 if (a.hasOption(Opt.MULTIVALUE))
334    {
335  23 for (String s : al)
336    {
337  53 l.add(entry(t, s));
338    }
339    }
340  38 else if (l.size() == 0 && al.size() > 0)
341    {
342  38 l.add(entry(t, al.get(0)));
343    }
344    }
345   
 
346  310 toggle private static Map.Entry<Type, String> entry(Type t, String s)
347    {
348  310 return new AbstractMap.SimpleEntry<Type, String>(t, s);
349    }
350   
351    /*
352    * Retrieves the first value even if MULTI.
353    * A convenience for non-MULTI args.
354    */
 
355  618 toggle public String getValue(Arg a)
356    {
357  618 if (!bootstrapArgMap.containsKey(a))
358  332 return null;
359  286 List<Map.Entry<Type, String>> aL = bootstrapArgMap.get(a);
360  286 return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue();
361    }
362   
 
363  0 toggle public boolean getBoolean(Arg a, boolean d)
364    {
365  0 if (!bootstrapArgMap.containsKey(a))
366  0 return d;
367  0 return Boolean.parseBoolean(getValue(a));
368    }
369   
 
370  721 toggle public boolean getBoolean(Arg a)
371    {
372  721 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
373    {
374  0 return false;
375    }
376  721 if (bootstrapArgMap.containsKey(a))
377    {
378  142 return Boolean.parseBoolean(getValue(a));
379    }
380    else
381    {
382  579 return a.getDefaultBoolValue();
383    }
384    }
385   
 
386  66 toggle public boolean argsHaveOption(Opt opt)
387    {
388  66 return argsOptions.contains(opt);
389    }
390   
 
391  145 toggle public boolean argsHaveType(Type type)
392    {
393  145 return argsTypes.contains(type);
394    }
395   
 
396  145 toggle public boolean isHeadless()
397    {
398  145 boolean isHeadless = false;
399  145 if (this.argsHaveType(Type.HELP))
400    {
401    // --help, --help-all, ... specified => headless
402  4 isHeadless = true;
403    }
404  141 else if (this.contains(Arg.VERSION))
405    {
406    // --version specified => headless
407  0 isHeadless = true;
408    }
409  141 else if (this.contains(Arg.GUI))
410    {
411    // --gui specified => forced NOT headless
412  50 isHeadless = !this.getBoolean(Arg.GUI);
413    }
414  91 else if (this.contains(Arg.HEADLESS))
415    {
416    // --headless has been specified on the command line => headless
417  25 isHeadless = this.getBoolean(Arg.HEADLESS);
418    }
419  66 else if (this.argsHaveOption(Opt.OUTPUTFILE))
420    {
421    // --output file.fa, --image pic.png, --structureimage struct.png =>
422    // assume headless unless above has been already specified
423  12 isHeadless = true;
424    }
425  145 return isHeadless;
426    }
427   
 
428  552 toggle public boolean outputToStdout()
429    {
430  552 return this.outputToStdout;
431    }
432    }