List<String> originalArgs = pr.originalArgs(); // lists all command line args assert Arrays.asList(args).equals(originalArgs); assert pr.hasMatchedOption("--verbose"); // as specified on command line assert pr.hasMatchedOption("-V"); // other aliases work also assert pr.hasMatchedOption('V'); // single-character alias works too assert pr.hasMatchedOption("verbose"); // and, command name without hyphens List<File> expected = Arrays.asList(new File("file1"), new File("file2")); assert expected.equals(pr.matchedOptionValue('f', defaultValue)); assert expected.equals(pr.matchedOptionValue("--file", defaultValue)); assert Arrays.equals(new int[]{1,2,3}, pr.matchedOptionValue('n', new int[0])); assert "1".equals(pr.matchedOption('n').stringValues().get(0)); assert "2".equals(pr.matchedOption('n').stringValues().get(1)); assert "3".equals(pr.matchedOption('n').stringValues().get(2)); assert "1,2,3".equals(pr.matchedOption("--num").originalStringValues().get(0));
if (CommandLine.printHelpIfRequested(pr)) { return; } int count = pr.matchedOptionValue('c', 1); List<File> files = pr.matchedPositionalValue(0, Collections.<File>emptyList()); for (File f : files) { for (int i = 0; i < count; i++) {
/** Executes the most specific {@code Runnable} or {@code Callable} subcommand. * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} * is thrown detailing the problem and capturing the offending {@code CommandLine} object. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return an empty list if help was requested, or a list containing a single element: the result of calling the * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed * @since 3.0 */ protected List<Object> handle(ParseResult parseResult) throws ExecutionException { List<CommandLine> parsedCommands = parseResult.asCommandLineList(); return execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>()); } @Override protected RunLast self() { return this; }
assertEquals(Arrays.asList(args), result.originalArgs()); assertSame(result.commandSpec().positionalParameters().get(0), result.tentativeMatch.get(0)); assertSame(result.commandSpec().positionalParameters().get(0), result.tentativeMatch.get(1)); assertSame(result.commandSpec().positionalParameters().get(1), result.tentativeMatch.get(2)); assertSame(result.commandSpec().positionalParameters().get(1), result.tentativeMatch.get(3)); assertSame(result.commandSpec().positionalParameters().get(1), result.tentativeMatch.get(4)); assertTrue(result.unmatched().isEmpty()); assertFalse(result.hasSubcommand()); assertFalse(result.isUsageHelpRequested()); assertFalse(result.isVersionHelpRequested()); assertEquals(Collections.emptyList(), result.matchedOptions()); assertEquals(3, result.matchedPositionals().size()); assertEquals(Range.valueOf("0..1"), result.matchedPositionals().get(0).index()); assertEquals(Range.valueOf("0..*"), result.matchedPositionals().get(1).index()); assertEquals(Range.valueOf("1..*"), result.matchedPositionals().get(2).index()); assertArrayEquals(args, (String[]) result.matchedPositionals().get(1).getValue()); assertArrayEquals(new String[]{"a", "b"}, (String[]) result.matchedPositionals().get(0).getValue()); assertArrayEquals(new String[]{"b", "c", "d", "e"}, (String[]) result.matchedPositionals().get(2).getValue()); assertTrue(result.hasMatchedPositional(i)); assertEquals(args[i], result.matchedPositional(i).stringValues().get(i)); assertFalse(result.hasMatchedPositional(args.length));
cmd.addSubcommand("sub", new Sub()); ParseResult parseResult = cmd.parseArgs("-x", "xval", "sub", "1", "2", "3"); assertEquals(Arrays.asList("-x", "xval", "sub", "1", "2", "3"), parseResult.originalArgs()); assertSame(parseResult.commandSpec().findOption("-x"), parseResult.tentativeMatch.get(0)); assertSame(parseResult.originalArgs().get(1), parseResult.tentativeMatch.get(1)); assertSame(parseResult.subcommand().commandSpec(), parseResult.tentativeMatch.get(2)); assertSame(parseResult.subcommand().commandSpec().positionalParameters().get(0), parseResult.tentativeMatch.get(3)); assertSame(parseResult.subcommand().commandSpec().positionalParameters().get(0), parseResult.tentativeMatch.get(4)); assertSame(parseResult.subcommand().commandSpec().positionalParameters().get(0), parseResult.tentativeMatch.get(5)); assertTrue(parseResult.hasMatchedOption("-x")); assertEquals("xval", parseResult.matchedOption("-x").stringValues().get(0)); assertEquals("xval", parseResult.matchedOptionValue("-x", "xval")); assertFalse(parseResult.hasMatchedPositional(0)); assertTrue(parseResult.hasSubcommand()); ParseResult subResult = parseResult.subcommand(); assertEquals(Arrays.asList("-x", "xval", "sub", "1", "2", "3"), subResult.originalArgs()); // TODO should subresult.originalArgs include the args consumed by the parent? assertTrue(subResult.hasMatchedPositional(0)); assertTrue(subResult.hasMatchedPositional(1)); assertTrue(subResult.hasMatchedPositional(2)); assertFalse(subResult.hasMatchedPositional(3)); assertEquals("1", subResult.matchedPositional(0).stringValues().get(0)); assertEquals("2", subResult.matchedPositional(1).stringValues().get(1)); assertEquals("3", subResult.matchedPositional(2).stringValues().get(2));
@Test public void testRawOptionValueReturnsFirstValue() { CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-V", "--verbose").build()); spec.addOption(OptionSpec.builder("-f", "--file") .paramLabel("FILES") .type(List.class) .auxiliaryTypes(File.class) // List<File> .description("The files to process").build()); CommandLine commandLine = new CommandLine(spec); String[] args = { "--verbose", "-f", "file1", "--file=file2" }; ParseResult pr = commandLine.parseArgs(args); assertEquals(Arrays.asList(args), pr.originalArgs()); assertEquals("file1", pr.matchedOption('f').stringValues().get(0)); assertEquals("file1", pr.matchedOption("-f").stringValues().get(0)); assertEquals("file1", pr.matchedOption("--file").stringValues().get(0)); List<String> expected = Arrays.asList("file1", "file2"); assertEquals(expected, pr.matchedOption('f').stringValues()); assertEquals(expected, pr.matchedOption("file").stringValues()); // for examples in Programmatic API wiki page assert expected.equals(pr.matchedOption('f').stringValues()); assert expected.equals(pr.matchedOption("file").stringValues()); assertSame(pr.commandSpec().findOption("-V"), pr.tentativeMatch.get(0)); assertSame(pr.commandSpec().findOption("-f"), pr.tentativeMatch.get(1)); assertSame(pr.originalArgs().get(2), pr.tentativeMatch.get(2)); assertSame(pr.commandSpec().findOption("-f"), pr.tentativeMatch.get(3)); assertEquals(4, pr.tentativeMatch.size()); }
@Test public void testMatchedPositionalsByIndex() { class App { @Option(names = "-x") String x; @Parameters(index = "0", arity = "0..1") int index0 = -1; @Parameters(index = "1", arity = "0..1") int index1 = -1; @Parameters(index = "2", arity = "0..1") int index2 = -1; } CommandLine cmd = new CommandLine(new App()); ParseResult parseResult = cmd.parseArgs("-x", "xval", "0", "1"); List<PositionalParamSpec> all = cmd.getCommandSpec().positionalParameters(); assertEquals(3, all.size()); List<PositionalParamSpec> foundFirst = parseResult.matchedPositionals(0); assertEquals(1, foundFirst.size()); assertSame(all.get(0), foundFirst.get(0)); assertSame(parseResult.matchedPositional(0), foundFirst.get(0)); List<PositionalParamSpec> foundSecond = parseResult.matchedPositionals(1); assertEquals(1, foundSecond.size()); assertSame(all.get(1), foundSecond.get(0)); assertSame(parseResult.matchedPositional(1), foundSecond.get(0)); List<PositionalParamSpec> foundThird = parseResult.matchedPositionals(2); assertEquals(0, foundThird.size()); }
@Test public void testBasicUsage() { class App { @Option(names = {"-t", "-ttt"}) boolean boolVal; @Option(names = {"-i", "-int"}) int intVal; @Parameters String[] positional; } ParseResult result = new CommandLine(new App()).parseArgs("-t", "-i", "1", "a", "b"); assertEquals(Arrays.asList("-t", "-i", "1", "a", "b"), result.originalArgs()); assertSame(result.commandSpec().findOption("-t"), result.tentativeMatch.get(0)); assertSame(result.commandSpec().findOption("-i"), result.tentativeMatch.get(1)); assertSame(result.originalArgs().get(2), result.tentativeMatch.get(2)); assertSame(result.commandSpec().positionalParameters().get(0), result.tentativeMatch.get(3)); assertSame(result.commandSpec().positionalParameters().get(0), result.tentativeMatch.get(4)); assertTrue(result.unmatched().isEmpty()); assertFalse(result.hasSubcommand()); assertFalse(result.isUsageHelpRequested()); assertFalse(result.isVersionHelpRequested()); assertTrue(result.hasMatchedOption("-ttt")); assertTrue(result.hasMatchedOption("-t")); assertTrue(result.hasMatchedOption("-i")); assertTrue(result.hasMatchedOption("-int")); assertFalse(result.hasMatchedOption("-unknown")); assertTrue(result.hasMatchedPositional(0)); assertTrue(result.hasMatchedPositional(1)); } @Test
@Override protected List<Object> handle(final ParseResult parseResult) throws ExecutionException { final CommandLine commandLine = parseResult.asCommandLineList().get(0); if (parseResult.hasMatchedOption(configFileOptionName)) { final OptionSpec configFileOption = parseResult.matchedOption(configFileOptionName); final File configFile; try { configFile = configFileOption.getter().get(); } catch (final Exception e) { throw new ExecutionException(commandLine, e.getMessage(), e); } final TomlConfigFileDefaultProvider tomlConfigFileDefaultProvider = new TomlConfigFileDefaultProvider(commandLine, configFile); commandLine.setDefaultValueProvider(tomlConfigFileDefaultProvider); } else if (isDocker) { final File configFile = new File(DOCKER_CONFIG_LOCATION); if (configFile.exists()) { final TomlConfigFileDefaultProvider tomlConfigFileDefaultProvider = new TomlConfigFileDefaultProvider(commandLine, configFile); commandLine.setDefaultValueProvider(tomlConfigFileDefaultProvider); } } commandLine.parseWithHandlers( resultHandler, exceptionHandler, parseResult.originalArgs().toArray(new String[0])); return new ArrayList<>(); }
@Test public void testOptionValue() { class App { @Option(names = {"-x", "++XX", "/XXX"}) int[] x; @Option(names = "-y") double y; } CommandLine cmd = new CommandLine(new App()); ParseResult result = cmd.parseArgs("-x", "123", "-x", "456", "-y", "3.14"); int[] expected = {123, 456}; assertArrayEquals(expected, result.matchedOptionValue("x", expected)); assertArrayEquals(expected, result.matchedOptionValue("-x", expected)); assertArrayEquals(expected, result.matchedOptionValue("XX", expected)); assertArrayEquals(expected, result.matchedOptionValue("++XX", expected)); assertArrayEquals(expected, result.matchedOptionValue("XXX", expected)); assertArrayEquals(expected, result.matchedOptionValue("/XXX", expected)); assertEquals(Double.valueOf(3.14), result.matchedOptionValue("y", 3.14)); assertEquals(Double.valueOf(3.14), result.matchedOptionValue("-y", 3.14)); assertSame(result.commandSpec().findOption("-x"), result.tentativeMatch.get(0)); assertSame(result.originalArgs().get(1), result.tentativeMatch.get(1)); assertSame(result.commandSpec().findOption("-x"), result.tentativeMatch.get(2)); assertSame(result.originalArgs().get(3), result.tentativeMatch.get(3)); assertSame(result.commandSpec().findOption("-y"), result.tentativeMatch.get(4)); assertSame(result.originalArgs().get(5), result.tentativeMatch.get(5)); }
@Test public void testMatchedPositionals_ReturnsOnlyMatchedPositionals() { class App { @Option(names = "-x") String x; @Parameters(index = "0", arity = "0..1") int index0 = -1; @Parameters(index = "1", arity = "0..1") int index1 = -1; @Parameters(index = "2", arity = "0..1") int index2 = -1; } CommandLine cmd = new CommandLine(new App()); ParseResult parseResult = cmd.parseArgs("-x", "xval", "0", "1"); List<PositionalParamSpec> all = cmd.getCommandSpec().positionalParameters(); assertEquals(3, all.size()); List<PositionalParamSpec> found = parseResult.matchedPositionals(); assertEquals(2, found.size()); assertSame(all.get(0), found.get(0)); assertSame(all.get(1), found.get(1)); assertSame(parseResult.matchedPositional(0), found.get(0)); assertSame(parseResult.matchedPositional(1), found.get(1)); assertNull(parseResult.matchedPositional(2)); }
@Test public void testParseResetsRawAndOriginalStringValues() { CommandSpec spec = CommandSpec.create() .addOption(OptionSpec.builder("-x").type(String.class).build()) .addPositional(PositionalParamSpec.builder().build()); CommandLine cmd = new CommandLine(spec); ParseResult parseResult = cmd.parseArgs("-x", "XVAL", "POSITIONAL"); assertEquals("XVAL", parseResult.matchedOption('x').getValue()); assertEquals(Arrays.asList("XVAL"), parseResult.matchedOption('x').stringValues()); assertEquals(Arrays.asList("XVAL"), parseResult.matchedOption('x').originalStringValues()); assertEquals("POSITIONAL", parseResult.matchedPositional(0).getValue()); assertEquals(Arrays.asList("POSITIONAL"), parseResult.matchedPositional(0).stringValues()); assertEquals(Arrays.asList("POSITIONAL"), parseResult.matchedPositional(0).originalStringValues()); ParseResult parseResult2 = cmd.parseArgs("-x", "222", "$$$$"); assertEquals("222", parseResult2.matchedOption('x').getValue()); assertEquals(Arrays.asList("222"), parseResult2.matchedOption('x').stringValues()); assertEquals(Arrays.asList("222"), parseResult2.matchedOption('x').originalStringValues()); assertEquals("$$$$", parseResult2.matchedPositional(0).getValue()); assertEquals(Arrays.asList("$$$$"), parseResult2.matchedPositional(0).stringValues()); assertEquals(Arrays.asList("$$$$"), parseResult2.matchedPositional(0).originalStringValues()); }
@Test public void testHasMatchedOptionByName_VariousPrefixes() { class App { @Option(names = {"-x", "++XX", "/XXX"}) String[] x; @Option(names = "-y") String y; } CommandLine cmd = new CommandLine(new App()); ParseResult result = cmd.parseArgs("-x", "value1", "-x", "value2"); assertTrue(result.hasMatchedOption("x")); assertTrue(result.hasMatchedOption("-x")); assertTrue(result.hasMatchedOption("XX")); assertTrue(result.hasMatchedOption("++XX")); assertTrue(result.hasMatchedOption("XXX")); assertTrue(result.hasMatchedOption("/XXX")); assertFalse(result.hasMatchedOption("y")); assertFalse(result.hasMatchedOption("-y")); assertSame(result.commandSpec().findOption("-x"), result.tentativeMatch.get(0)); assertSame(result.originalArgs().get(1), result.tentativeMatch.get(1)); assertSame(result.commandSpec().findOption("-x"), result.tentativeMatch.get(2)); assertSame(result.originalArgs().get(3), result.tentativeMatch.get(3)); }
/** Executes the top-level command and all subcommands as {@code Runnable} or {@code Callable}. * If any of the {@code CommandLine} commands does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} * is thrown detailing the problem and capturing the offending {@code CommandLine} object. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return an empty list if help was requested, or a list containing the result of executing all commands: * the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed * @since 3.0 */ protected List<Object> handle(ParseResult parseResult) throws ExecutionException { List<Object> result = new ArrayList<Object>(); execute(parseResult.commandSpec().commandLine(), result); while (parseResult.hasSubcommand()) { parseResult = parseResult.subcommand(); execute(parseResult.commandSpec().commandLine(), result); } return returnResultOrExit(result); } @Override protected RunAll self() { return this; }
@Test public void testHasMatchedPositionalByPositionalSpec() { class App { @Option(names = "-x") String x; @Parameters(index = "0", arity = "0..1") int index0 = -1; @Parameters(index = "1", arity = "0..1") int index1 = -1; @Parameters(index = "2", arity = "0..1") int index2 = -1; } CommandLine cmd = new CommandLine(new App()); ParseResult result = cmd.parseArgs("-x", "xval", "0", "1"); assertSame(result.commandSpec().findOption("-x"), result.tentativeMatch.get(0)); assertSame(result.originalArgs().get(1), result.tentativeMatch.get(1)); assertSame(result.commandSpec().positionalParameters().get(0), result.tentativeMatch.get(2)); assertSame(result.commandSpec().positionalParameters().get(1), result.tentativeMatch.get(3)); List<PositionalParamSpec> all = cmd.getCommandSpec().positionalParameters(); assertTrue(result.hasMatchedPositional(all.get(0))); assertTrue(result.hasMatchedPositional(all.get(1))); assertFalse(result.hasMatchedPositional(all.get(2))); }
/** Prints help if requested, and otherwise calls {@link #handle(CommandLine.ParseResult)}. * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return the result of {@link #handle(ParseResult) processing parse results} * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions} * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2} * @throws ExecutionException if a problem occurred while processing the parse results; client code can use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed */ public R handleParseResult(ParseResult parseResult) throws ExecutionException { if (printHelpIfRequested(parseResult.asCommandLineList(), out(), err(), ansi())) { return returnResultOrExit(null); } return returnResultOrExit(handle(parseResult)); }
/** Executes the most specific {@code Runnable} or {@code Callable} subcommand. * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} * is thrown detailing the problem and capturing the offending {@code CommandLine} object. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return an empty list if help was requested, or a list containing a single element: the result of calling the * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed * @since 3.0 */ protected List<Object> handle(ParseResult parseResult) throws ExecutionException { List<CommandLine> parsedCommands = parseResult.asCommandLineList(); return execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>()); } @Override protected RunLast self() { return this; }
@Test public void testPositionalParamSpec_defaultValue_overwritesInitialValue() { class Params { @Parameters int num = 12345; } CommandLine cmd = new CommandLine(new Params()); PositionalParamSpec x = cmd.getCommandSpec().positionalParameters().get(0).toBuilder().defaultValue("54321").build(); cmd = new CommandLine(CommandSpec.create().add(x)); ParseResult parseResult = cmd.parseArgs(); // default not in the parse result assertFalse(parseResult.hasMatchedPositional(0)); assertEquals(Integer.valueOf(-1), parseResult.matchedPositionalValue(0, -1)); // but positional spec does have the default value assertEquals(Integer.valueOf(54321), parseResult.commandSpec().positionalParameters().get(0).getValue()); }
@Test public void testRawPositionalValue_ReturnsNullForNonMatchedPosition() { class App { @Parameters(index = "0", arity = "0..1") int index0 = -1; @Parameters(index = "1", arity = "0..1") int index1 = -1; @Parameters(index = "2", arity = "0..1") int index2 = -1; } CommandLine cmd = new CommandLine(new App()); ParseResult parseResult = cmd.parseArgs("0", "1"); assertEquals("0", parseResult.matchedPositional(0).stringValues().get(0)); assertEquals("1", parseResult.matchedPositional(1).stringValues().get(0)); assertNull(parseResult.matchedPositional(2)); assertNull(parseResult.matchedPositional(3)); }
@Test public void testRawPositionalValueWithDefault_ReturnsDefaultForNonMatchedPosition() { class App { @Parameters(index = "0", arity = "0..1") int index0 = -1; @Parameters(index = "1", arity = "0..1") int index1 = -1; @Parameters(index = "2", arity = "0..1") int index2 = -1; } CommandLine cmd = new CommandLine(new App()); ParseResult parseResult = cmd.parseArgs("0", "1"); assertEquals(Integer.valueOf(0), parseResult.matchedPositionalValue(0, Integer.valueOf(123))); assertEquals(Integer.valueOf(1), parseResult.matchedPositionalValue(1, Integer.valueOf(456))); assertEquals(Integer.valueOf(123), parseResult.matchedPositionalValue(2, Integer.valueOf(123))); assertEquals(Integer.valueOf(456), parseResult.matchedPositionalValue(3, Integer.valueOf(456))); }