Skip to content

Commit

Permalink
[#308] API to disallow POSIX clustered short options; add to CommandL…
Browse files Browse the repository at this point in the history
…ine facade; add documentation; add tests
  • Loading branch information
remkop committed Mar 27, 2018
1 parent 6ab2156 commit a22c68c
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,11 @@ options and positional parameters as soon as it encounters an unmatched argument
When this flag is set, the first unmatched argument and all subsequent command line arguments are added to the
unmatched arguments list returned by `CommandLine.getUnmatchedArguments()`.

=== Disallowing POSIX Clustered Short Options
By default, the picocli parser allows POSIX clustered short options, so short options like `-x -v -f SomeFile` can be clustered together like `-xvfSomeFile`.
From picocli 3.0, applications can call `CommandLine.setPosixClusteredShortOptionsAllowed(false)` to enforce that options must be separated with whitespace on the command line.



== Help

Expand Down
22 changes: 22 additions & 0 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,28 @@ public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
return this;
}

/** Returns whether the parser accepts clustered short options. The default is {@code true}.
* @return {@code true} if short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}, {@code false} otherwise
* @since 3.0 */
public boolean isPosixClusteredShortOptionsAllowed() { return getCommandSpec().parser().posixClusteredShortOptionsAllowed(); }

/** Sets whether short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}.
* <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.</p>
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.0
*/
public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
getCommandSpec().parser().posixClusteredShortOptionsAllowed(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setPosixClusteredShortOptionsAllowed(newValue);
}
return this;
}

/** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining
* arguments are all treated as positional parameters. The default is {@code false}.
* @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
Expand Down
46 changes: 46 additions & 0 deletions src/test/java/picocli/CommandLineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,52 @@ public void testParserPosixClustedShortOptions_false_allowsUnclusteredShortOptio
verifyCompact(unclustered, true, true, "FILE", null);
}

@Test
public void testParserPosixClustedShortOptions_BeforeSubcommandsAdded() {
@Command class TopLevel {}
CommandLine commandLine = new CommandLine(new TopLevel());
assertEquals(true, commandLine.isPosixClusteredShortOptionsAllowed());
commandLine.setPosixClusteredShortOptionsAllowed(false);
assertEquals(false, commandLine.isPosixClusteredShortOptionsAllowed());

int childCount = 0;
int grandChildCount = 0;
commandLine.addSubcommand("main", createNestedCommand());
for (CommandLine sub : commandLine.getSubcommands().values()) {
childCount++;
assertEquals("subcommand added afterwards is not impacted", true, sub.isPosixClusteredShortOptionsAllowed());
for (CommandLine subsub : sub.getSubcommands().values()) {
grandChildCount++;
assertEquals("subcommand added afterwards is not impacted", true, subsub.isPosixClusteredShortOptionsAllowed());
}
}
assertTrue(childCount > 0);
assertTrue(grandChildCount > 0);
}

@Test
public void testParserPosixClustedShortOptions_AfterSubcommandsAdded() {
@Command class TopLevel {}
CommandLine commandLine = new CommandLine(new TopLevel());
commandLine.addSubcommand("main", createNestedCommand());
assertEquals(true, commandLine.isPosixClusteredShortOptionsAllowed());
commandLine.setPosixClusteredShortOptionsAllowed(false);
assertEquals(false, commandLine.isPosixClusteredShortOptionsAllowed());

int childCount = 0;
int grandChildCount = 0;
for (CommandLine sub : commandLine.getSubcommands().values()) {
childCount++;
assertEquals("subcommand added before IS impacted", false, sub.isPosixClusteredShortOptionsAllowed());
for (CommandLine subsub : sub.getSubcommands().values()) {
grandChildCount++;
assertEquals("subsubcommand added before IS impacted", false, sub.isPosixClusteredShortOptionsAllowed());
}
}
assertTrue(childCount > 0);
assertTrue(grandChildCount > 0);
}

@Test
public void testDoubleDashSeparatesPositionalParameters() {
CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-oout -- -r -v p1 p2".split(" "));
Expand Down

0 comments on commit a22c68c

Please sign in to comment.