while ((token = reader.readLine()) != null) { if (token.length() > 0 && !token.trim().startsWith(String.valueOf(commandSpec.parser().atFileCommentChar()))) { addOrExpand(token, result, visited); addOrExpand(tok.sval, result, visited);
private void parse(List<CommandLine> parsedCommands, Stack<String> argumentStack, String[] originalArgs, List<Object> nowProcessing) { clear(); // first reset any state in case this CommandLine instance is being reused if (tracer.isDebug()) {tracer.debug("Initializing %s: %d options, %d positional parameters, %d required, %d subcommands.%n", commandSpec.toString(), new HashSet<ArgSpec>(commandSpec.optionsMap().values()).size(), int stackSize = argumentStack.size(); try { applyDefaultValues(required); processArguments(parsedCommands, argumentStack, required, initialized, originalArgs, nowProcessing); } catch (ParameterException ex) { maybeThrow(ex); } catch (Exception ex) { int offendingArgIndex = originalArgs.length - argumentStack.size() - 1; String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length ? originalArgs[offendingArgIndex] : "?"; maybeThrow(ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs)); if (!isAnyHelpRequested() && !required.isEmpty()) { for (ArgSpec missing : required) { if (missing.isOption()) { maybeThrow(MissingParameterException.create(CommandLine.this, required, config().separator())); } else { assertNoMissingParameters(missing, missing.arity(), argumentStack); unmatchedArgsBinding.addAll(unmatched.clone()); if (!isUnmatchedArgumentsAllowed()) { maybeThrow(new UnmatchedArgumentException(CommandLine.this, Collections.unmodifiableList(parseResult.unmatched))); } if (tracer.isInfo()) { tracer.info("Unmatched arguments: %s%n", parseResult.unmatched); }
paramAttachedToOption = cluster.length() > 0; LookBehind lookBehind = paramAttachedToOption ? LookBehind.ATTACHED : LookBehind.SEPARATE; if (cluster.startsWith(config().separator())) {// attached with separator, like -f=FILE or -v=true lookBehind = LookBehind.ATTACHED_WITH_SEPARATOR; cluster = cluster.substring(config().separator().length()); arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1 int consumed = applyOption(argSpec, lookBehind, arity, args, initialized, argDescription); if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options if (tracer.isDebug()) {tracer.debug("Could not match any short options in %s, deciding whether to treat as unmatched option or positional parameter...%n", arg);} if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); return; } // #149 processPositionalParameter(required, initialized, args); return; handleUnmatchedArgument(args); } else { args.push(cluster); if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);} processPositionalParameter(required, initialized, args);
paramAttachedToOption = cluster.length() > 0; LookBehind lookBehind = paramAttachedToOption ? LookBehind.ATTACHED : LookBehind.SEPARATE; if (cluster.startsWith(config().separator())) {// attached with separator, like -f=FILE or -v=true lookBehind = LookBehind.ATTACHED_WITH_SEPARATOR; cluster = cluster.substring(config().separator().length()); arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1 int consumed = applyOption(argSpec, lookBehind, arity, args, initialized, argDescription); if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options if (tracer.isDebug()) {tracer.debug("Could not match any short options in %s, deciding whether to treat as unmatched option or positional parameter...%n", arg);} if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); return; } // #149 processPositionalParameter(required, initialized, args); return; handleUnmatchedArgument(args); } else { args.push(cluster); if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);} processPositionalParameter(required, initialized, args);
private void parse(List<CommandLine> parsedCommands, Stack<String> argumentStack, String[] originalArgs, List<Object> nowProcessing) { clear(); // first reset any state in case this CommandLine instance is being reused if (tracer.isDebug()) {tracer.debug("Initializing %s: %d options, %d positional parameters, %d required, %d subcommands.%n", commandSpec.toString(), new HashSet<ArgSpec>(commandSpec.optionsMap().values()).size(), int stackSize = argumentStack.size(); try { applyDefaultValues(required); processArguments(parsedCommands, argumentStack, required, initialized, originalArgs, nowProcessing); } catch (ParameterException ex) { maybeThrow(ex); } catch (Exception ex) { int offendingArgIndex = originalArgs.length - argumentStack.size() - 1; String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length ? originalArgs[offendingArgIndex] : "?"; maybeThrow(ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs)); if (!isAnyHelpRequested() && !required.isEmpty()) { for (ArgSpec missing : required) { if (missing.isOption()) { maybeThrow(MissingParameterException.create(CommandLine.this, required, config().separator())); } else { assertNoMissingParameters(missing, missing.arity(), argumentStack); unmatchedArgsBinding.addAll(unmatched.clone()); if (!isUnmatchedArgumentsAllowed()) { maybeThrow(new UnmatchedArgumentException(CommandLine.this, Collections.unmodifiableList(parseResult.unmatched))); } if (tracer.isInfo()) { tracer.info("Unmatched arguments: %s%n", parseResult.unmatched); }
private void processPositionalParameter(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception { if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter at index=%d. Remainder=%s%n", position, reverse(copy(args)));} if (config().stopAtPositional()) { if (!endOfOptions && tracer.isDebug()) {tracer.debug("Parser was configured with stopAtPositional=true, treating remaining arguments as positional parameters.%n");} endOfOptions = true; Range arity = positionalParam.arity(); if (tracer.isDebug()) {tracer.debug("Position %d is in index range %s. Trying to assign args to %s, arity=%s%n", position, indexRange, positionalParam, arity);} if (!assertNoMissingParameters(positionalParam, arity, argsCopy)) { break; } // #389 collectErrors parsing int originalSize = argsCopy.size(); int actuallyConsumed = applyOption(positionalParam, LookBehind.SEPARATE, arity, argsCopy, initialized, "args[" + indexRange + "] at position " + position); int count = originalSize - argsCopy.size(); if (count > 0 || actuallyConsumed > 0) { if (tracer.isDebug()) {tracer.debug("Consumed %d arguments and %d interactive values, moving position to index %d.%n", argsConsumed, interactiveConsumed, position);} if (argsConsumed == 0 && interactiveConsumed == 0 && !args.isEmpty()) { handleUnmatchedArgument(args);
int consumed = consumedCount(0, initialSize, argSpec); for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) { List<Object> typedValuesAtPosition = new ArrayList<Object>(); parseResult.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition); assertNoMissingMandatoryParameter(argSpec, args, i, arity); consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription); result.addAll(typedValuesAtPosition); consumed = consumedCount(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE; if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; } if (!canConsumeOneArgument(argSpec, arity, consumed, args.peek(), type, argDescription)) { break; // leave empty list at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription); result.addAll(typedValuesAtPosition); consumed = consumedCount(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE;
while ((token = reader.readLine()) != null) { if (token.length() > 0 && !token.trim().startsWith(String.valueOf(commandSpec.parser().atFileCommentChar()))) { addOrExpand(token, result, visited); addOrExpand(tok.sval, result, visited);
int consumed = consumedCountMap(0, initialSize, argSpec); for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) { Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>(); parseResult.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition); assertNoMissingMandatoryParameter(argSpec, args, i, arity); consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription); result.putAll(typedValuesAtPosition); consumed = consumedCountMap(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE; if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; } if (!canConsumeOneMapArgument(argSpec, arity, consumed, args.peek(), classes, keyConverter, valueConverter, argDescription)) { break; // leave empty map at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription); result.putAll(typedValuesAtPosition); consumed = consumedCountMap(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE;
Set<ArgSpec> initialized, String argDescription) throws Exception { updateHelpRequested(argSpec); boolean consumeOnlyOne = commandSpec.parser().aritySatisfiedByAttachedOptionParam() && lookBehind.isAttached(); Stack<String> workingStack = args; if (consumeOnlyOne) { workingStack = args.isEmpty() ? args : stack(args.pop()); } else { if (!assertNoMissingParameters(argSpec, arity, args)) { return 0; } // #389 collectErrors parsing String prompt = String.format("Enter value for %s (%s): ", name, str(argSpec.renderedDescription(), 0)); if (tracer.isDebug()) {tracer.debug("Reading value for %s from console...%n", name);} char[] value = readPassword(prompt); if (tracer.isDebug()) {tracer.debug("User entered '%s' for %s.%n", value, name);} workingStack.push(new String(value)); result = applyValuesToArrayField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else if (Collection.class.isAssignableFrom(argSpec.type())) { result = applyValuesToCollectionField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else if (Map.class.isAssignableFrom(argSpec.type())) { result = applyValuesToMapField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else { result = applyValueToSingleValuedField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
/** * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and object factory. * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically * constructs a {@code CommandSpec} from this user object. * </p><p> If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods, * picocli creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values. * If the specified command object is a concrete {@code Class}, picocli delegates to the {@linkplain IFactory factory} to get an instance. * </p><p> * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this * user object will be initialized based on the command line arguments.</p> * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation * @since 2.2 */ public CommandLine(Object command, IFactory factory) { this.factory = Assert.notNull(factory, "factory"); interpreter = new Interpreter(); commandSpec = CommandSpec.forAnnotatedObject(command, factory); commandSpec.commandLine(this); commandSpec.validate(); if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); } }
/** * Entry point into parsing command line arguments. * @param args the command line arguments * @return a list with all commands and subcommands initialized by this method * @throws ParameterException if the specified command line arguments are invalid */ List<CommandLine> parse(String... args) { Assert.notNull(args, "argument array"); if (tracer.isInfo()) {tracer.info("Picocli version: %s%n", versionString());} if (tracer.isInfo()) {tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));} if (tracer.isDebug()){tracer.debug("Parser configuration: %s%n", config());} if (tracer.isDebug()){tracer.debug("(ANSI is %s by default: isatty=%s, XTERM=%s, OSTYPE=%s, isWindows=%s, JansiConsoleInstalled=%s, ANSICON=%s, ConEmuANSI=%s, NO_COLOR=%s, CLICOLOR=%s, CLICOLOR_FORCE=%s)%n", Help.Ansi.ansiPossible() ? "enabled" : "disabled", Help.Ansi.isTTY(), System.getenv("XTERM"), System.getenv("OSTYPE"), Help.Ansi.isWindows(), Help.Ansi.isJansiConsoleInstalled(), System.getenv("ANSICON"), System.getenv("ConEmuANSI"), System.getenv("NO_COLOR"), System.getenv("CLICOLOR"), System.getenv("CLICOLOR_FORCE"));} List<String> expanded = new ArrayList<String>(); for (String arg : args) { addOrExpand(arg, expanded, new LinkedHashSet<String>()); } Stack<String> arguments = new Stack<String>(); arguments.addAll(reverseList(expanded)); List<CommandLine> result = new ArrayList<CommandLine>(); parse(result, arguments, args, new ArrayList<Object>()); return result; }
private void processStandaloneOption(Collection<ArgSpec> required, Set<ArgSpec> initialized, String arg, Stack<String> args, boolean paramAttachedToKey) throws Exception { ArgSpec argSpec = commandSpec.optionsMap().get(arg); required.remove(argSpec); Range arity = argSpec.arity(); if (paramAttachedToKey) { arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1 } LookBehind lookBehind = paramAttachedToKey ? LookBehind.ATTACHED_WITH_SEPARATOR : LookBehind.SEPARATE; if (tracer.isDebug()) {tracer.debug("Found option named '%s': %s, arity=%s%n", arg, argSpec, arity);} parseResult.nowProcessing.add(argSpec); applyOption(argSpec, lookBehind, arity, args, initialized, "option " + arg); }
private void applyDefaultValues(List<ArgSpec> required) throws Exception { parseResult.isInitializingDefaultValues = true; for (OptionSpec option : commandSpec.options()) { applyDefault(commandSpec.defaultValueProvider(), option, required); } for (PositionalParamSpec positional : commandSpec.positionalParameters()) { applyDefault(commandSpec.defaultValueProvider(), positional, required); } parseResult.isInitializingDefaultValues = false; }
private void applyDefault(IDefaultValueProvider defaultValueProvider, ArgSpec arg, List<ArgSpec> required) throws Exception { // Default value provider return value is only used if provider exists and if value // is not null otherwise the original default or initial value are used String fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(arg); String defaultValue = fromProvider == null ? arg.defaultValue() : fromProvider; if (defaultValue == null) { return; } if (tracer.isDebug()) {tracer.debug("Applying defaultValue (%s) to %s%n", defaultValue, arg);} Range arity = arg.arity().min(Math.max(1, arg.arity().min)); applyOption(arg, LookBehind.SEPARATE, arity, stack(defaultValue), new HashSet<ArgSpec>(), arg.toString); required.remove(arg); }
private void processPositionalParameter(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception { if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter at index=%d. Remainder=%s%n", position, reverse(copy(args)));} if (config().stopAtPositional()) { if (!endOfOptions && tracer.isDebug()) {tracer.debug("Parser was configured with stopAtPositional=true, treating remaining arguments as positional parameters.%n");} endOfOptions = true; Range arity = positionalParam.arity(); if (tracer.isDebug()) {tracer.debug("Position %d is in index range %s. Trying to assign args to %s, arity=%s%n", position, indexRange, positionalParam, arity);} if (!assertNoMissingParameters(positionalParam, arity, argsCopy)) { break; } // #389 collectErrors parsing int originalSize = argsCopy.size(); int actuallyConsumed = applyOption(positionalParam, LookBehind.SEPARATE, arity, argsCopy, initialized, "args[" + indexRange + "] at position " + position); int count = originalSize - argsCopy.size(); if (count > 0 || actuallyConsumed > 0) { if (tracer.isDebug()) {tracer.debug("Consumed %d arguments and %d interactive values, moving position to index %d.%n", argsConsumed, interactiveConsumed, position);} if (argsConsumed == 0 && interactiveConsumed == 0 && !args.isEmpty()) { handleUnmatchedArgument(args);
int consumed = consumedCount(0, initialSize, argSpec); for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) { List<Object> typedValuesAtPosition = new ArrayList<Object>(); parseResult.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition); assertNoMissingMandatoryParameter(argSpec, args, i, arity); consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription); result.addAll(typedValuesAtPosition); consumed = consumedCount(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE; if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; } if (!canConsumeOneArgument(argSpec, arity, consumed, args.peek(), type, argDescription)) { break; // leave empty list at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription); result.addAll(typedValuesAtPosition); consumed = consumedCount(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE;
int consumed = consumedCountMap(0, initialSize, argSpec); for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) { Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>(); parseResult.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition); assertNoMissingMandatoryParameter(argSpec, args, i, arity); consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription); result.putAll(typedValuesAtPosition); consumed = consumedCountMap(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE; if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; } if (!canConsumeOneMapArgument(argSpec, arity, consumed, args.peek(), classes, keyConverter, valueConverter, argDescription)) { break; // leave empty map at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription); result.putAll(typedValuesAtPosition); consumed = consumedCountMap(i + 1, initialSize, argSpec); lookBehind = LookBehind.SEPARATE;
Set<ArgSpec> initialized, String argDescription) throws Exception { updateHelpRequested(argSpec); boolean consumeOnlyOne = commandSpec.parser().aritySatisfiedByAttachedOptionParam() && lookBehind.isAttached(); Stack<String> workingStack = args; if (consumeOnlyOne) { workingStack = args.isEmpty() ? args : stack(args.pop()); } else { if (!assertNoMissingParameters(argSpec, arity, args)) { return 0; } // #389 collectErrors parsing String prompt = String.format("Enter value for %s (%s): ", name, str(argSpec.renderedDescription(), 0)); if (tracer.isDebug()) {tracer.debug("Reading value for %s from console...%n", name);} char[] value = readPassword(prompt); if (tracer.isDebug()) {tracer.debug("User entered '%s' for %s.%n", value, name);} workingStack.push(new String(value)); result = applyValuesToArrayField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else if (Collection.class.isAssignableFrom(argSpec.type())) { result = applyValuesToCollectionField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else if (Map.class.isAssignableFrom(argSpec.type())) { result = applyValuesToMapField(argSpec, lookBehind, arity, workingStack, initialized, argDescription); } else { result = applyValueToSingleValuedField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
/** * Entry point into parsing command line arguments. * @param args the command line arguments * @return a list with all commands and subcommands initialized by this method * @throws ParameterException if the specified command line arguments are invalid */ List<CommandLine> parse(String... args) { Assert.notNull(args, "argument array"); if (tracer.isInfo()) {tracer.info("Picocli version: %s%n", versionString());} if (tracer.isInfo()) {tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));} if (tracer.isDebug()){tracer.debug("Parser configuration: %s%n", config());} if (tracer.isDebug()){tracer.debug("(ANSI is %s by default: isatty=%s, XTERM=%s, OSTYPE=%s, isWindows=%s, JansiConsoleInstalled=%s, ANSICON=%s, ConEmuANSI=%s, NO_COLOR=%s, CLICOLOR=%s, CLICOLOR_FORCE=%s)%n", Help.Ansi.ansiPossible() ? "enabled" : "disabled", Help.Ansi.isTTY(), System.getenv("XTERM"), System.getenv("OSTYPE"), Help.Ansi.isWindows(), Help.Ansi.isJansiConsoleInstalled(), System.getenv("ANSICON"), System.getenv("ConEmuANSI"), System.getenv("NO_COLOR"), System.getenv("CLICOLOR"), System.getenv("CLICOLOR_FORCE"));} List<String> expanded = new ArrayList<String>(); for (String arg : args) { addOrExpand(arg, expanded, new LinkedHashSet<String>()); } Stack<String> arguments = new Stack<String>(); arguments.addAll(reverseList(expanded)); List<CommandLine> result = new ArrayList<CommandLine>(); parse(result, arguments, args, new ArrayList<Object>()); return result; }