X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=blobdiff_plain;f=src%2Fjalview%2Fbin%2Fargparser%2FBootstrapArgs.java;fp=src%2Fjalview%2Fbin%2Fargparser%2FBootstrapArgs.java;h=80e08c5a63b1ae4bc5b177dbce8396502333c175;hp=0000000000000000000000000000000000000000;hb=c1e71094304dcd2b975c485416ec5e25cca30815;hpb=bd990168d0b3c7772c961b56144c3dee94a09054 diff --git a/src/jalview/bin/argparser/BootstrapArgs.java b/src/jalview/bin/argparser/BootstrapArgs.java new file mode 100644 index 0000000..80e08c5 --- /dev/null +++ b/src/jalview/bin/argparser/BootstrapArgs.java @@ -0,0 +1,430 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.bin.argparser; + +import java.io.File; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import jalview.bin.argparser.Arg.Opt; +import jalview.bin.argparser.Arg.Type; +import jalview.util.FileUtils; + +public class BootstrapArgs +{ + // only need one + private Map>> bootstrapArgMap = new HashMap<>(); + + private Set argFiles = new HashSet<>(); + + private Set argsOptions = new HashSet<>(); + + private Set argsTypes = new HashSet<>(); + + private boolean outputToStdout = false; + + public static BootstrapArgs getBootstrapArgs(String[] args) + { + List argList = new ArrayList<>(Arrays.asList(args)); + return new BootstrapArgs(argList); + } + + public static BootstrapArgs getBootstrapArgs(List args) + { + return new BootstrapArgs(args); + } + + private BootstrapArgs(List args) + { + parse(args, null); + } + + private void parse(List args, File inArgFile) + { + if (args == null) + return; + // avoid looping argFiles + if (inArgFile != null) + { + if (argFiles.contains(inArgFile)) + { + jalview.bin.Console.errPrintln( + "Looped argfiles detected: '" + inArgFile.getPath() + "'"); + return; + } + argFiles.add(inArgFile); + } + + for (int i = 0; i < args.size(); i++) + { + String arg = args.get(i); + // look for double-dash, e.g. --arg + if (arg.startsWith(ArgParser.DOUBLEDASH)) + { + String argName = null; + String val = null; + Type type = null; + // remove "--" + argName = arg.substring(ArgParser.DOUBLEDASH.length()); + + // look for equals e.g. --arg=value + int equalPos = argName.indexOf(ArgParser.EQUALS); + if (equalPos > -1) + { + val = argName.substring(equalPos + 1); + argName = argName.substring(0, equalPos); + } + + // check for boolean prepended by "no" + if (argName.startsWith(ArgParser.NEGATESTRING) + && ArgParser.argMap.containsKey( + argName.substring(ArgParser.NEGATESTRING.length()))) + { + val = "false"; + argName = argName.substring(ArgParser.NEGATESTRING.length()); + } + + // look for type modification e.g. --help-opening + int dashPos = argName.indexOf(ArgParser.SINGLEDASH); + if (dashPos > -1) + { + String potentialArgName = argName.substring(0, dashPos); + Arg potentialArg = ArgParser.argMap.get(potentialArgName); + if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE)) + { + String typeName = argName.substring(dashPos + 1); + try + { + type = Type.valueOf(typeName.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) + { + type = Type.INVALID; + } + argName = argName.substring(0, dashPos); + } + } + + // after all other args, look for Opt.PREFIX args if still not found + if (!ArgParser.argMap.containsKey(argName)) + { + for (Arg potentialArg : EnumSet.allOf(Arg.class)) + { + if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null + && argName.startsWith(potentialArg.getName()) + && val != null) + { + val = argName.substring(potentialArg.getName().length()) + + ArgParser.EQUALS + val; + argName = argName.substring(0, + potentialArg.getName().length()); + break; + } + } + } + + Arg a = ArgParser.argMap.get(argName); + + if (a != null) + { + for (Opt opt : a.getOptions()) + { + if (!argsOptions.contains(opt)) + { + argsOptions.add(opt); + } + } + Type t = a.getType(); + if (!argsTypes.contains(t)) + { + argsTypes.add(t); + } + } + + if (a == null || !a.hasOption(Opt.BOOTSTRAP)) + { + // not a bootstrap arg + + // make a check for an output going to stdout + if (a != null && a.hasOption(Opt.OUTPUTFILE) + && a.hasOption(Opt.STDOUT)) + { + if (val == null && i + 1 < args.size()) + { + val = args.get(i + 1); + } + if (val.startsWith("[") && val.indexOf(']') > 0) + { + val = val.substring(val.indexOf(']') + 1); + } + + if (ArgParser.STDOUTFILENAME.equals(val)) + { + this.outputToStdout = true; + } + } + + continue; + } + + if (a.hasOption(Opt.STRING)) + { + List vals = null; + if (equalPos == -1) + { + vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1); + } + else + { + if (a.hasOption(Opt.GLOB)) + { + vals = FileUtils.getFilenamesFromGlob(val); + } + else + { + vals = new ArrayList<>(); + vals.add(val); + } + } + addAll(a, type, vals); + + if (a == Arg.ARGFILE) + { + for (String filename : vals) + { + File argFile = new File(filename); + parse(ArgParser.readArgFile(argFile), argFile); + } + } + } + else + { + if (val == null) + { + val = "true"; + } + + add(a, type, val); + } + } + } + + // if in an argfile, remove it from the hashset so it can be re-used in + // another argfile + if (inArgFile != null) + { + argFiles.remove(inArgFile); + } + } + + public boolean contains(Arg a) + { + return bootstrapArgMap.containsKey(a); + } + + public boolean containsType(Type t) + { + for (List> l : bootstrapArgMap.values()) + { + for (Map.Entry e : l) + { + if (e.getKey() == t) + return true; + } + } + return false; + } + + public List getArgsOfType(Type t) + { + return getArgsOfType(t, new Opt[] {}); + } + + public List getArgsOfType(Type t, Opt... opts) + { + List args = new ArrayList<>(); + for (Arg a : bootstrapArgMap.keySet()) + { + if (!a.hasAllOptions(opts)) + continue; + + List> l = bootstrapArgMap.get(a); + if (l.stream().anyMatch(e -> e.getKey() == t)) + { + args.add(a); + } + } + return args; + } + + public List> getList(Arg a) + { + return bootstrapArgMap.get(a); + } + + public List getValueList(Arg a) + { + return bootstrapArgMap.get(a).stream().map(e -> e.getValue()) + .collect(Collectors.toList()); + } + + private List> getOrCreateList(Arg a) + { + List> l = getList(a); + if (l == null) + { + l = new ArrayList<>(); + putList(a, l); + } + return l; + } + + private void putList(Arg a, List> l) + { + bootstrapArgMap.put(a, l); + } + + /* + * Creates a new list if not used before, + * adds the value unless the existing list is non-empty + * and the arg is not MULTI (so first expressed value is + * retained). + */ + private void add(Arg a, Type t, String s) + { + List> l = getOrCreateList(a); + if (a.hasOption(Opt.MULTIVALUE) || l.size() == 0) + { + l.add(entry(t, s)); + } + } + + private void addAll(Arg a, Type t, List al) + { + List> l = getOrCreateList(a); + if (a.hasOption(Opt.MULTIVALUE)) + { + for (String s : al) + { + l.add(entry(t, s)); + } + } + else if (l.size() == 0 && al.size() > 0) + { + l.add(entry(t, al.get(0))); + } + } + + private static Map.Entry entry(Type t, String s) + { + return new AbstractMap.SimpleEntry(t, s); + } + + /* + * Retrieves the first value even if MULTI. + * A convenience for non-MULTI args. + */ + public String getValue(Arg a) + { + if (!bootstrapArgMap.containsKey(a)) + return null; + List> aL = bootstrapArgMap.get(a); + return (aL == null || aL.size() == 0) ? null : aL.get(0).getValue(); + } + + public boolean getBoolean(Arg a, boolean d) + { + if (!bootstrapArgMap.containsKey(a)) + return d; + return Boolean.parseBoolean(getValue(a)); + } + + public boolean getBoolean(Arg a) + { + if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY))) + { + return false; + } + if (bootstrapArgMap.containsKey(a)) + { + return Boolean.parseBoolean(getValue(a)); + } + else + { + return a.getDefaultBoolValue(); + } + } + + public boolean argsHaveOption(Opt opt) + { + return argsOptions.contains(opt); + } + + public boolean argsHaveType(Type type) + { + return argsTypes.contains(type); + } + + public boolean isHeadless() + { + boolean isHeadless = false; + if (this.argsHaveType(Type.HELP)) + { + // --help, --help-all, ... specified => headless + isHeadless = true; + } + else if (this.contains(Arg.VERSION)) + { + // --version specified => headless + isHeadless = true; + } + else if (this.contains(Arg.GUI)) + { + // --gui specified => forced NOT headless + isHeadless = !this.getBoolean(Arg.GUI); + } + else if (this.contains(Arg.HEADLESS)) + { + // --headless has been specified on the command line => headless + isHeadless = this.getBoolean(Arg.HEADLESS); + } + else if (this.argsHaveOption(Opt.OUTPUTFILE)) + { + // --output file.fa, --image pic.png, --structureimage struct.png => + // assume headless unless above has been already specified + isHeadless = true; + } + return isHeadless; + } + + public boolean outputToStdout() + { + return this.outputToStdout; + } +}