import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
}
}
- String defs = aparser.getValue("setprop");
- while (defs != null)
+ List<String> setprops = new ArrayList<>();
+ if (bootstrapArgs.contains(Arg.SETPROP))
{
- int p = defs.indexOf('=');
+ setprops = bootstrapArgs.getList(Arg.SETPROP);
+ }
+ else
+ {
+ String sp = aparser.getValue("setprop");
+ while (sp != null)
+ {
+ setprops.add(sp);
+ sp = aparser.getValue("setprop");
+ }
+ }
+ for (String setprop : setprops)
+ {
+ int p = setprop.indexOf('=');
if (p == -1)
{
- System.err.println("Ignoring invalid setprop argument : " + defs);
+ System.err
+ .println("Ignoring invalid setprop argument : " + setprop);
}
else
{
- System.out.println("Executing setprop argument: " + defs);
+ System.out.println("Executing setprop argument: " + setprop);
if (Platform.isJS())
{
- Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
+ Cache.setProperty(setprop.substring(0, p),
+ setprop.substring(p + 1));
}
// DISABLED FOR SECURITY REASONS
// TODO: add a property to allow properties to be overriden by cli args
// Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
}
- defs = aparser.getValue("setprop");
}
if (System.getProperty("java.awt.headless") != null
&& System.getProperty("java.awt.headless").equals("true"))
{
HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
- ANNOTATION2, DISPLAY, GUI, NEWS, NOQUESTIONNAIRE, SORTBYTREE, USAGESTATS,
- OPEN, OPENNEW, PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC, VSESS, OUTPUT,
- OUTPUTTYPE, SSANNOTATION, NOTEMPFAC, TEMPFAC, TEMPFAC_LABEL, TEMPFAC_DESC,
+ ANNOTATION2, DISPLAY, GUI, NEWS, SORTBYTREE, USAGESTATS, OPEN, OPENNEW,
+ PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC, VSESS, OUTPUT, OUTPUTTYPE,
+ SSANNOTATION, NOTEMPFAC, TEMPFAC, TEMPFAC_LABEL, TEMPFAC_DESC,
TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP, NOSTRUCTURE, STRUCTURE, IMAGE,
QUIT, CLOSE, DEBUG("d"), QUIET("q"), ARGFILE, INCREMENT, NPP("n++"),
- SUBSTITUTIONS, NIL, SPLASH;
+ SUBSTITUTIONS, NIL, SPLASH, SETARGFILE, UNSETARGFILE;
protected static enum Opt
{
BOOLEAN, STRING, UNARY, MULTI, LINKED, NODUPLICATEVALUES, BOOTSTRAP,
- GLOB, NOACTION, ALLOWSUBSTITUTIONS
+ GLOB, NOACTION, ALLOWSUBSTITUTIONS, PRIVATE
}
static
GUI.setOptions(true, Opt.BOOLEAN);
NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
SPLASH.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
- NOQUESTIONNAIRE.setOptions(Opt.UNARY, Opt.BOOTSTRAP); // unary as
- // --questionnaire=val
// expects a string value
SORTBYTREE.setOptions(true, Opt.BOOLEAN);
USAGESTATS.setOptions(true, Opt.BOOLEAN);
OPENNEW.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
Opt.ALLOWSUBSTITUTIONS);
PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
- QUESTIONNAIRE.setOptions(Opt.STRING);
- SETPROP.setOptions(Opt.STRING);
+ QUESTIONNAIRE.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
+ SETPROP.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP);
TREE.setOptions(Opt.STRING);
VDOC.setOptions(Opt.UNARY);
NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
+ SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
+ UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
// Opt.BOOTSTRAP args are parsed (not linked with no SubVals so using a
// simplified parser, see jalview.bin.argparser.BootstrapArgs)
// before a full parse of arguments and so can be accessible at an earlier
{
protected static final String DOUBLEDASH = "--";
+ protected static final char EQUALS = '=';
+
protected static final String NEGATESTRING = "no";
// the default linked id prefix used for no id (not even square braces)
// the counter added to the default linked id prefix
private int opennewLinkedIdCounter = 0;
- // the linked id used to increment the idCounter (and use the incremented
- // value)
+ // the linked id substitution string used to increment the idCounter (and use
+ // the incremented value)
private static final String INCREMENTAUTOCOUNTERLINKEDID = "{++n}";
- // the linked id used to use the idCounter
+ // the linked id substitution string used to use the idCounter
private static final String AUTOCOUNTERLINKEDID = "{n}";
+ // the linked id substitution string used to use the base filename of --open
+ // or --opennew
+ private static final String LINKEDIDBASENAME = "{basename}";
+
+ // the linked id substitution string used to use the dir path of --open
+ // or --opennew
+ private static final String LINKEDIDDIRNAME = "{dirname}";
+
+ // the current argfile
+ private String argFile = null;
+
+ // the linked id substitution string used to use the dir path of the latest
+ // --argfile name
+ private static final String ARGFILEBASENAME = "{argfilebasename}";
+
+ // the linked id substitution string used to use the dir path of the latest
+ // --argfile name
+ private static final String ARGFILEDIRNAME = "{argfiledirname}";
+
private int linkedIdAutoCounter = 0;
// flag to say whether {n} subtitutions in output filenames should be made.
public ArgParser(List<String> args)
{
+ this(args, false);
+ }
+
+ public ArgParser(List<String> args, boolean allowPrivate)
+ {
// do nothing if there are no "--" args and some "-" args
boolean d = false;
boolean dd = false;
if (d && !dd)
{
// leave it to the old style -- parse an empty list
- parse(new ArrayList<String>());
+ parse(new ArrayList<String>(), allowPrivate);
return;
}
- parse(args);
+ parse(args, allowPrivate);
}
- private void parse(List<String> args)
+ private void parse(List<String> args, boolean allowPrivate)
{
int argIndex = 0;
boolean openEachInitialFilenames = true;
String linkedId = null;
if (arg.startsWith(DOUBLEDASH))
{
- int equalPos = arg.indexOf('=');
+ int equalPos = arg.indexOf(EQUALS);
if (equalPos > -1)
{
argName = arg.substring(DOUBLEDASH.length(), equalPos);
Console.error("Argument '" + arg + "' not recognised. Ignoring.");
continue;
}
+ if (a.hasOption(Opt.PRIVATE) && !allowPrivate)
+ {
+ Console.error("Argument '" + DOUBLEDASH + argName
+ + "' is private. Ignoring.");
+ continue;
+ }
if (!a.hasOption(Opt.BOOLEAN) && negated)
{
// used "no" with a non-boolean option
- Console.error("Argument '--" + NEGATESTRING + argName
+ Console.error("Argument '" + DOUBLEDASH + NEGATESTRING + argName
+ "' not a boolean option. Ignoring.");
continue;
}
if (!a.hasOption(Opt.STRING) && equalPos > -1)
{
// set --argname=value when arg does not accept values
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + DOUBLEDASH + argName
+ "' does not expect a value (given as '" + arg
+ "'). Ignoring.");
continue;
if (!a.hasOption(Opt.LINKED) && linkedId != null)
{
// set --argname[linkedId] when arg does not use linkedIds
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + DOUBLEDASH + argName
+ "' does not expect a linked id (given as '" + arg
+ "'). Ignoring.");
continue;
{
// strip off and save the SubVals to be added individually later
globSubVals = ArgParser.getSubVals(val);
- globVals = FileUtils
- .getFilenamesFromGlob(globSubVals.getContent());
+ // make substitutions before looking for files
+ String fileGlob = makeSubstitutions(globSubVals.getContent(),
+ linkedId);
+ globVals = FileUtils.getFilenamesFromGlob(fileGlob);
}
else
{
{
substitutions = !negated;
}
+ else if (a == Arg.SETARGFILE)
+ {
+ argFile = val;
+ }
+ else if (a == Arg.UNSETARGFILE)
+ {
+ argFile = null;
+ }
String autoCounterString = null;
boolean usingAutoCounterLinkedId = false;
// not dealing with both NODUPLICATEVALUES and GLOB
if (a.hasOption(Opt.NODUPLICATEVALUES) && avm.hasValue(a, val))
{
- Console.error("Argument '--" + argName
+ Console.error("Argument '" + DOUBLEDASH + argName
+ "' cannot contain a duplicate value ('" + val
+ "'). Ignoring this and subsequent occurrences.");
continue;
String id = idsv.get(ArgValues.ID);
if (id != null && avm.hasId(a, id))
{
- Console.error("Argument '--" + argName + "' has a duplicate id ('"
- + id + "'). Ignoring.");
+ Console.error("Argument '" + DOUBLEDASH + argName
+ + "' has a duplicate id ('" + id + "'). Ignoring.");
continue;
}
{
for (String v : globVals)
{
- v = makeSubstitutions(v);
+ v = makeSubstitutions(v, linkedId);
SubVals vsv = new SubVals(globSubVals, v);
avs.addValue(vsv, v, argIndex++);
argIndexIncremented = true;
}
else
{
- avs.addValue(makeSubstitutions(val), argIndex);
+ avs.addValue(makeSubstitutions(val, linkedId), argIndex);
}
}
else if (a.hasOption(Opt.BOOLEAN))
}
}
- private String makeSubstitutions(String val)
+ private String makeSubstitutions(String val, String linkedId)
{
if (!this.substitutions)
return val;
subvals = "";
rest = val;
}
- if ((rest.contains(AUTOCOUNTERLINKEDID)))
+ if (rest.contains(AUTOCOUNTERLINKEDID))
rest = rest.replace(AUTOCOUNTERLINKEDID,
String.valueOf(linkedIdAutoCounter));
- if ((rest.contains(INCREMENTAUTOCOUNTERLINKEDID)))
+ if (rest.contains(INCREMENTAUTOCOUNTERLINKEDID))
rest = rest.replace(INCREMENTAUTOCOUNTERLINKEDID,
String.valueOf(++linkedIdAutoCounter));
- if ((rest.contains("{}")))
+ if (rest.contains("{}"))
rest = rest.replace("{}", String.valueOf(defaultLinkedIdCounter));
+ ArgValuesMap avm = linkedArgs.get(linkedId);
+ if (avm != null)
+ {
+ if (rest.contains(LINKEDIDBASENAME))
+ {
+ rest = rest.replace(LINKEDIDBASENAME, avm.getBasename());
+ }
+ if (rest.contains(LINKEDIDDIRNAME))
+ {
+ rest = rest.replace(LINKEDIDDIRNAME, avm.getDirname());
+ }
+ }
+ if (argFile != null)
+ {
+ if (rest.contains(ARGFILEBASENAME))
+ {
+ rest = rest.replace(ARGFILEBASENAME,
+ FileUtils.getBasename(new File(argFile)));
+ }
+ if (rest.contains(ARGFILEDIRNAME))
+ {
+ rest = rest.replace(ARGFILEDIRNAME,
+ FileUtils.getDirname(new File(argFile)));
+ }
+ }
return new StringBuilder(subvals).append(rest).toString();
}
if (!argFile.exists())
{
String message = DOUBLEDASH
- + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + "=\""
- + argFile.getPath() + "\": File does not exist.";
+ + Arg.ARGFILE.name().toLowerCase(Locale.ROOT) + EQUALS
+ + "\"" + argFile.getPath() + "\": File does not exist.";
Jalview.exit(message, 2);
}
try
{
+ String setargfile = new StringBuilder(ArgParser.DOUBLEDASH)
+ .append(Arg.SETARGFILE.getName()).append(EQUALS)
+ .append(argFile.getCanonicalPath()).toString();
+ argsList.add(setargfile);
argsList.addAll(Files.readAllLines(Paths.get(argFile.getPath())));
+ argsList.add(new StringBuilder(ArgParser.DOUBLEDASH)
+ .append(Arg.UNSETARGFILE.getName()).toString());
} catch (IOException e)
{
String message = DOUBLEDASH
Jalview.exit(message, 3);
}
}
- return new ArgParser(argsList);
+ // Second param "true" uses Opt.PRIVATE args --setargile=argfile and
+ // --unsetargfile
+ return new ArgParser(argsList, true);
}
}
\ No newline at end of file
package jalview.bin.argparser;
+import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import jalview.bin.argparser.Arg.Opt;
+import jalview.util.FileUtils;
/**
* Helper class to allow easy extraction of information about specific argument
ArgValues avs = this.getArgValues(a);
return avs == null ? null : avs.getId(id);
}
+
+ /*
+ * This method returns the basename of the first --open or --opennew value.
+ * Used primarily for substitutions in output filenames.
+ */
+ public String getBasename()
+ {
+ return getDirOrBasename(false);
+ }
+
+ /*
+ * This method returns the dirname of the first --open or --opennew value.
+ * Used primarily for substitutions in output filenames.
+ */
+ public String getDirname()
+ {
+ return getDirOrBasename(true);
+ }
+
+ public String getDirOrBasename(boolean dirname)
+ {
+ String filename = null;
+ String openVal = getValue(Arg.OPEN);
+ String opennewVal = getValue(Arg.OPENNEW);
+ if (openVal != null)
+ filename = openVal;
+ if (filename == null && opennewVal != null)
+ filename = opennewVal;
+ if (filename == null)
+ return null;
+
+ File file = new File(filename);
+ return dirname ? FileUtils.getDirname(file)
+ : FileUtils.getBasename(file);
+ }
}
{
// remove "--"
arg = arg.substring(ArgParser.DOUBLEDASH.length());
- int equalPos = arg.indexOf('=');
+ int equalPos = arg.indexOf(ArgParser.EQUALS);
if (equalPos > -1
&& ArgParser.argMap.containsKey(arg.substring(0, equalPos)))
{
return (aL == null || aL.size() == 0) ? null : aL.get(0);
}
+ public boolean getBoolean(Arg a, boolean d)
+ {
+ if (!bootstrapArgMap.containsKey(a))
+ return d;
+ return Boolean.parseBoolean(get(a));
+ }
+
public boolean getBoolean(Arg a)
{
- if (!bootstrapArgMap.containsKey(a)
- || !(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
+ if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
+ {
return false;
- return Boolean.parseBoolean(get(a));
+ }
+ if (bootstrapArgMap.containsKey(a))
+ return Boolean.parseBoolean(get(a));
+ else
+ return a.getDefaultBoolValue();
}
}
import java.util.List;
import java.util.stream.Collectors;
+import jalview.bin.Console;
+
public class FileUtils
{
/*
? System.getProperty("user.home") + path.substring(1)
: path;
}
+
+ /*
+ * This method returns the basename of the first --open or --opennew value.
+ * Used primarily for substitutions in output filenames.
+ */
+ public static String getBasename(File file)
+ {
+ if (file == null)
+ return null;
+
+ String basename = null;
+ String filename = file.getName();
+ int lastDot = filename.lastIndexOf('.');
+ if (lastDot > 0) // don't truncate if starts with '.'
+ {
+ basename = filename.substring(0, lastDot);
+ }
+ else
+ {
+ basename = filename;
+ }
+ return basename;
+ }
+
+ /*
+ * This method returns the dirname of the first --open or --opennew value.
+ * Used primarily for substitutions in output filenames.
+ */
+ public static String getDirname(File file)
+ {
+ if (file == null)
+ return null;
+
+ String dirname = null;
+ try
+ {
+ dirname = file.getParentFile().getCanonicalPath();
+ } catch (IOException e)
+ {
+ Console.debug(
+ "Exception when getting dirname of '" + file.getPath() + "'",
+ e);
+ dirname = "";
+ }
+ return dirname;
+ }
}
package jalview.bin;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@Test(singleThreaded = true)
public class CommandsTest
{
+ private static final String testfiles = "test/jalview/bin/argparser/testfiles";
+
+ private static final String png1 = testfiles + "/dir1/test2.png";
+
+ private static final String png2 = testfiles + "/dir2/test2.png";
+
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
Desktop.instance.closeAll_actionPerformed(null);
}
+ /* --setprop currently disabled
+ @Test(groups = "Functional")
+ public void setpropsTest()
+ {
+ String MOSTLY_HARMLESS = "MOSTLY_HARMLESS";
+ String cmdLine = "--setprop=" + MOSTLY_HARMLESS + "=Earth";
+ String[] args = cmdLine.split("\\s+");
+ Jalview.main(args);
+ Assert.assertEquals(Cache.getDefault(MOSTLY_HARMLESS, "Magrathea"),
+ "Earth");
+ }
+ */
+
@Test(groups = "Functional", dataProvider = "cmdLines")
public void commandsOpenTest(String cmdLine, boolean cmdArgs,
int numFrames, String[] sequences)
lookForSequenceName("THIS_SEQUENCE_ID_DOESN'T_EXIST"));
}
+ @Test(groups = "Functional")
+ public void argFilesGlobAndSubstitutionsTest() throws IOException
+ {
+ cleanupArgfilesImages();
+ String cmdLine = "--headless --argfile=" + testfiles
+ + "/dir*/argfile.txt";
+ String[] args = cmdLine.split("\\s+");
+ Jalview.main(args);
+ Commands cmds = Jalview.getInstance().getCommands();
+ File file1 = new File(png1);
+ File file2 = new File(png2);
+ Assert.assertTrue(file1.exists(),
+ "Did not make file " + png1 + " from argfile");
+ Assert.assertTrue(file2.exists(),
+ "Did not make file " + png2 + " from argfile");
+ long size1 = Files.size(file1.toPath());
+ long size2 = Files.size(file2.toPath());
+ Assert.assertTrue(file1.isFile() && size1 > 0);
+ Assert.assertTrue(file2.isFile() && size2 > 0);
+ Assert.assertTrue(size2 > size1); // png2 has three sequences, png1 has 2
+ cleanupArgfilesImages();
+ }
+
@DataProvider(name = "cmdLines")
public Object[][] cmdLines()
{
{ "--open=[new]examples/uniref50*.fa", true, 2, someUniref50Seqs },
{ "--opennew=examples/uniref50*.fa", true, 2, someUniref50Seqs },
{ "examples/uniref50.fa", true, 1, someUniref50Seqs },
- { "examples/uniref50.fa test/jalview/bin/argparser/testfiles/test1.fa",
- true, 2, ArrayUtils.concatArrays(someUniref50Seqs, t1) },
- { "examples/uniref50.fa test/jalview/bin/argparser/testfiles/test1.fa",
- true, 2, t1 },
- { "--argfile=test/jalview/bin/argparser/testfiles/argfile0.txt",
- true, 1, ArrayUtils.concatArrays(t1, t3) },
- { "--argfile=test/jalview/bin/argparser/testfiles/argfile*.txt",
- true, 4, ArrayUtils.concatArrays(t1, t2, t3) },
- { "--argfile=test/jalview/bin/argparser/testfiles/argfile.autocounter",
- true, 3, ArrayUtils.concatArrays(t1, t2) } };
+ { "examples/uniref50.fa " + testfiles + "/test1.fa", true, 2,
+ ArrayUtils.concatArrays(someUniref50Seqs, t1) },
+ { "examples/uniref50.fa " + testfiles + "/test1.fa", true, 2, t1 },
+ { "--argfile=" + testfiles + "/argfile0.txt", true, 1,
+ ArrayUtils.concatArrays(t1, t3) },
+ { "--argfile=" + testfiles + "/argfile*.txt", true, 4,
+ ArrayUtils.concatArrays(t1, t2, t3) },
+ { "--argfile=" + testfiles + "/argfile.autocounter", true, 3,
+ ArrayUtils.concatArrays(t1, t2) } };
}
public static boolean lookForSequenceName(String sequenceName)
return false;
}
+ public static void cleanupArgfilesImages()
+ {
+ File png1File = new File(png1);
+ File png2File = new File(png2);
+ if (png1File.exists())
+ {
+ png1File.delete();
+ }
+ if (png2File.exists())
+ {
+ png2File.delete();
+ }
+ }
+
}
--- /dev/null
+--substitutions
+--increment
+--open={argfiledirname}/*.fa
+--colour=gecos:flower
+--image={argfiledirname}/{basename}.png
--- /dev/null
+>TEST1
+AAAA
--- /dev/null
+>TEST2
+LLLL
--- /dev/null
+--substitutions
+--increment
+--open={argfiledirname}/*.fa
+--colour=gecos:flower
+--image={argfiledirname}/{basename}.png
--- /dev/null
+>TEST1
+AAAA
--- /dev/null
+>TEST2
+LLLL
--- /dev/null
+>TEST3
+AAARG