diff --git a/src/main/java/joptsimple/BarclayOptionParser.java b/src/main/java/joptsimple/BarclayOptionParser.java new file mode 100644 index 00000000..4056ee08 --- /dev/null +++ b/src/main/java/joptsimple/BarclayOptionParser.java @@ -0,0 +1,31 @@ +package joptsimple; + +import joptsimple.util.KeyValuePair; + +/** + * Custom subclass of the jopt parser for Barclay. Overrides short argument handling + * so that short arg clustering is disabled. + */ +public class BarclayOptionParser extends OptionParser { + public BarclayOptionParser(final boolean allowAbbreviations) { + super(allowAbbreviations); + } + + /** + * Only delegate short arg handling to the base class if we're guaranteed that the option will be + * recognized using the full argument string. Otherwise the base class implementation will fall back + * to clustered short name recognition, which we want to disable to avoid the confusing error message + * generated. + */ + void handleShortOptionToken( String candidate, ArgumentList arguments, OptionSet detected ) { + KeyValuePair optionAndArgument = KeyValuePair.valueOf( candidate.substring( 1 ) ); + + if ( isRecognized( optionAndArgument.key ) ) { + super.handleShortOptionToken(candidate, arguments, detected ); + } + else { + throw new UnrecognizedOptionException(candidate); + } + } + +} diff --git a/src/main/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParser.java b/src/main/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParser.java index fd9433e6..8a0e4aaf 100644 --- a/src/main/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParser.java +++ b/src/main/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParser.java @@ -372,7 +372,7 @@ public boolean parseArguments(final PrintStream messageStream, String[] args) { // the key when the fields's values are set. args = tagParser.preprocessTaggedOptions(args); - final OptionParser parser = new OptionParser(false); + final OptionParser parser = new BarclayOptionParser(false); for (final ArgumentDefinition arg : argumentDefinitions){ OptionSpecBuilder bld = parser.acceptsAll(arg.getNames(), arg.doc); diff --git a/src/test/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParserTest.java b/src/test/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParserTest.java index 7cf74a73..5f29bf2d 100644 --- a/src/test/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParserTest.java +++ b/src/test/java/org/broadinstitute/barclay/argparser/CommandLineArgumentParserTest.java @@ -177,6 +177,19 @@ public void testAbbreviationsAreRejected() { clp.parseArguments(System.err, new String[]{"--" + AbbreviatableArgument.ARGUMENT_NAME.substring(0,5)}); } + @Test + public void testEnsureClusteringDisabled() { + final String clusterOfShortArgs = "-cluster"; + final CommandLineArgumentParser clp = new CommandLineArgumentParser(new Object()); + final CommandLineException e = Assert.expectThrows( + CommandLineException.class, + () -> clp.parseArguments(System.err, new String[]{clusterOfShortArgs})); + // If clustering is enabled, the string "cluster" would be interpreted as a series of short arg names, the + // first one being "c", so the error message will say "-c is not...", but we want to ensure it says + // "-cluster is not..." + Assert.assertTrue(e.getMessage().startsWith(clusterOfShortArgs)); + } + @CommandLineProgramProperties( summary = "[oscillation_frequency]\n\nRecalibrates overthruster oscillation. \n", oneLineSummary = "Recalibrates the overthruster.",