private void printArg(ArgSpec arg, PrintWriter pw, String indent) { pw.printf("%sdescription: %s%n", indent, Arrays.toString(arg.description())); pw.printf("%sdescriptionKey: '%s'%n", indent, arg.descriptionKey()); pw.printf("%stypeInfo: %s%n", indent, arg.typeInfo()); pw.printf("%sarity: %s%n", indent, arg.arity()); pw.printf("%ssplitRegex: '%s'%n", indent, arg.splitRegex()); pw.printf("%sinteractive: %s%n", indent, arg.interactive()); pw.printf("%srequired: %s%n", indent, arg.required()); pw.printf("%shidden: %s%n", indent, arg.hidden()); pw.printf("%shideParamSyntax: %s%n", indent, arg.hideParamSyntax()); pw.printf("%sdefaultValue: '%s'%n", indent, arg.defaultValue()); pw.printf("%sshowDefaultValue: %s%n", indent, arg.showDefaultValue()); pw.printf("%shasInitialValue: %s%n", indent, arg.hasInitialValue()); pw.printf("%sinitialValue: '%s'%n", indent, arg.initialValue()); pw.printf("%sparamLabel: '%s'%n", indent, arg.paramLabel()); pw.printf("%sconverters: %s%n", indent, Arrays.toString(arg.converters())); pw.printf("%scompletionCandidates: %s%n", indent, iter(arg.completionCandidates())); pw.printf("%sgetter: %s%n", indent, arg.getter()); pw.printf("%ssetter: %s%n", indent, arg.setter()); }
if (argSpec.interactive()) { String name = argSpec.isOption() ? ((OptionSpec) argSpec).longestName() : "position " + position; 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 (argSpec.type().isArray()) { 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 {
private boolean assertNoMissingParameters(ArgSpec argSpec, Range arity, Stack<String> args) { if (argSpec.interactive()) { return true; } int available = args.size(); if (available > 0 && commandSpec.parser().splitFirst() && argSpec.splitRegex().length() > 0) { available += argSpec.splitValue(args.peek(), commandSpec.parser(), arity, 0).length - 1; if (argSpec.isOption()) { maybeThrow(new MissingParameterException(CommandLine.this, argSpec, "Missing required parameter for " + optionDescription("", argSpec, 0))); Range paramArity = argSpec.arity(); if (count > 1 || arity.min - available > 1) { msg += "s";
if (cluster.length() > 0 && commandSpec.posixOptionsMap().containsKey(cluster.charAt(0))) { ArgSpec argSpec = commandSpec.posixOptionsMap().get(cluster.charAt(0)); Range arity = argSpec.arity(); String argDescription = "option " + prefix + cluster.charAt(0); if (tracer.isDebug()) {tracer.debug("Found option '%s%s' in %s: %s, arity=%s%n", prefix, cluster.charAt(0), arg,
boolean noMoreValues = args.isEmpty(); Range arity = argSpec.arity().isUnspecified ? derivedArity : argSpec.arity(); // #509 if (arity.max == 0 && !arity.isUnspecified && lookBehind == LookBehind.ATTACHED_WITH_SEPARATOR) { // #509 throw new MaxValuesExceededException(CommandLine.this, optionDescription("", argSpec, 0) + Class<?> cls = argSpec.auxiliaryTypes()[0]; // field may be interface/abstract type, use annotation to get concrete type if (arity.min <= 0) { // value may be optional Boolean currentValue = (Boolean) argSpec.getValue(); Object oldValue = argSpec.getValue(); String traceMessage = "Setting %s to '%3$s' (was '%2$s') for %4$s%n"; if (initialized.contains(argSpec)) { if (tracer.isInfo()) { tracer.info(traceMessage, argSpec.toString(), String.valueOf(oldValue), String.valueOf(newValue), argDescription); } argSpec.setValue(newValue);
public Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles) { Range capacity = argSpec.isOption() ? argSpec.arity() : ((PositionalParamSpec)argSpec).capacity(); if (capacity.max == 0) { return ansi.new Text(""); } if (argSpec.hideParamSyntax()) { return ansi.apply((argSpec.isOption() ? separator() : "") + argSpec.paramLabel(), styles); } Text paramName = ansi.apply(argSpec.paramLabel(), styles); String split = argSpec.splitRegex(); String mandatorySep = empty(split) ? " " : split; String optionalSep = empty(split) ? " [" : "[" + split; if (!argSpec.arity().isVariable && argSpec.arity().min > 1) { result = ansi.new Text("(").concat(result).concat(")"); // repeating group String optionSeparator = argSpec.isOption() ? separator() : ""; if (capacity.min == 0) { // optional String sep2 = empty(optionSeparator.trim()) ? optionSeparator + "[" : "[" + optionSeparator;
private boolean assertNoMissingParameters(ArgSpec argSpec, Range arity, Stack<String> args) { if (argSpec.interactive()) { return true; } int available = args.size(); if (available > 0 && commandSpec.parser().splitFirst() && argSpec.splitRegex().length() > 0) { available += argSpec.splitValue(args.peek(), commandSpec.parser(), arity, 0).length - 1; if (argSpec.isOption()) { maybeThrow(new MissingParameterException(CommandLine.this, argSpec, "Missing required parameter for " + optionDescription("", argSpec, 0))); Range paramArity = argSpec.arity(); if (count > 1 || arity.min - available > 1) { msg += "s";
if (argSpec.interactive()) { String name = argSpec.isOption() ? ((OptionSpec) argSpec).longestName() : "position " + position; 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 (argSpec.type().isArray()) { 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 {
assertEquals("positional parameter at index 0..* (<values>) requires at least 2 values, but only 1 were specified: [a,b,c,d,e]", ex.getMessage()); assertEquals(1, ex.getMissing().size()); assertTrue(ex.getMissing().get(0).toString(), ex.getMissing().get(0) instanceof CommandLine.Model.PositionalParamSpec);
Set<ArgSpec> initialized, String argDescription) throws Exception { Object existing = argSpec.getValue(); int length = existing == null ? 0 : Array.getLength(existing); Class<?> type = argSpec.auxiliaryTypes()[0]; List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription); List<Object> newValues = new ArrayList<Object>(); Array.set(array, i, newValues.get(i)); argSpec.setValue(array); parseResult.add(argSpec, position); return converted.size(); // return how many args were consumed
/** Returns the default value String displayed in the description. If this ArgSpec is part of a * CommandSpec with a {@link IDefaultValueProvider}, this method will first try to obtain * the default value from the default value provider; if the provider is {@code null} or if it * returns a {@code null} value, then next any value set to {@link ArgSpec#defaultValue()} * is returned, and if this is also {@code null}, finally the {@linkplain ArgSpec#initialValue() initial value} is returned. * @see CommandSpec#defaultValueProvider() * @see ArgSpec#defaultValue() */ public String defaultValueString() { String fromProvider = null; IDefaultValueProvider defaultValueProvider = null; try { defaultValueProvider = commandSpec.defaultValueProvider(); fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(this); } catch (Exception ex) { new Tracer().info("Error getting default value for %s from %s: %s", this, defaultValueProvider, ex); } String defaultVal = fromProvider == null ? this.defaultValue() : fromProvider; Object value = defaultVal == null ? initialValue() : defaultVal; if (value != null && value.getClass().isArray()) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < Array.getLength(value); i++) { sb.append(i > 0 ? ", " : "").append(Array.get(value, i)); } return sb.insert(0, "[").append("]").toString(); } return String.valueOf(value); }
@Test public void test130MixPositionalParamsWithOptionsArity() { class Arg { @Parameters(arity = "2") List<String> parameters; @Option(names = "-o") List<String> options; } Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3", "p4"); assertEquals(Arrays.asList("v1", "v2"), result.options); assertEquals(Arrays.asList("p1", "p2", "p3", "p4"), result.parameters); try { CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "-o", "v2", "p3"); fail("Expected MissingParameterException"); } catch (MissingParameterException ex) { assertEquals("Expected parameter 2 (of 2 mandatory parameters) for positional parameter at index 0..* (<parameters>) but found '-o'", ex.getMessage()); assertEquals(1, ex.getMissing().size()); assertTrue(ex.getMissing().get(0).toString(), ex.getMissing().get(0) instanceof PositionalParamSpec); } try { CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3"); fail("Expected MissingParameterException"); } catch (MissingParameterException ex) { assertEquals("positional parameter at index 0..* (<parameters>) requires at least 2 values, but only 1 were specified: [p3]", ex.getMessage()); assertEquals(1, ex.getMissing().size()); assertTrue(ex.getMissing().get(0).toString(), ex.getMissing().get(0) instanceof PositionalParamSpec); } }
@Test public void testArrayOptionWithoutArityConsumesOneArgument() { // #192 class OptionsNoArityAndParameters { @Parameters char[] charParams; @Option(names = "-chars") char[] charOptions; } OptionsNoArityAndParameters params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a b c d".split(" ")); assertArrayEquals(Arrays.toString(params.charOptions), new char[] {'a', }, params.charOptions); assertArrayEquals(Arrays.toString(params.charParams), new char[] {'b', 'c', 'd'}, params.charParams); // repeated occurrence params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a -chars b c d".split(" ")); assertArrayEquals(Arrays.toString(params.charOptions), new char[] {'a', 'b', }, params.charOptions); assertArrayEquals(Arrays.toString(params.charParams), new char[] {'c', 'd'}, params.charParams); try { CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars".split(" ")); fail("expected MissingParameterException"); } catch (MissingParameterException ok) { assertEquals("Missing required parameter for option '-chars' (<charOptions>)", ok.getMessage()); assertEquals(1, ok.getMissing().size()); assertTrue(ok.getMissing().get(0).toString(), ok.getMissing().get(0) instanceof Model.OptionSpec); } }
@SuppressWarnings("unchecked") private int applyValuesToCollectionField(ArgSpec argSpec, LookBehind lookBehind, Range arity, Stack<String> args, Set<ArgSpec> initialized, String argDescription) throws Exception { Collection<Object> collection = (Collection<Object>) argSpec.getValue(); Class<?> type = argSpec.auxiliaryTypes()[0]; List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription); if (collection == null || (!collection.isEmpty() && !initialized.contains(argSpec))) { tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName()); collection = createCollection(argSpec.type()); // collection type argSpec.setValue(collection); } initialized.add(argSpec); for (Object element : converted) { if (element instanceof Collection<?>) { collection.addAll((Collection<?>) element); } else { collection.add(element); } } parseResult.add(argSpec, position); argSpec.setValue(collection); return converted.size(); }
private void consumeOneMapArgument(ArgSpec argSpec, LookBehind lookBehind, Range arity, int consumed, String arg, Class<?>[] classes, ITypeConverter<?> keyConverter, ITypeConverter<?> valueConverter, Map<Object, Object> result, int index, String argDescription) { if (!lookBehind.isAttached()) { parseResult.nowProcessing(argSpec, arg); } String raw = trim(arg); String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed); for (String value : values) { String[] keyValue = splitKeyValue(argSpec, value); Object mapKey = tryConvert(argSpec, index, keyConverter, keyValue[0], classes[0]); Object mapValue = tryConvert(argSpec, index, valueConverter, keyValue[1], classes[1]); result.put(mapKey, mapValue); if (tracer.isInfo()) { tracer.info("Putting [%s : %s] in %s<%s, %s> %s for %s%n", String.valueOf(mapKey), String.valueOf(mapValue), result.getClass().getSimpleName(), classes[0].getSimpleName(), classes[1].getSimpleName(), argSpec.toString(), argDescription); } parseResult.addStringValue(argSpec, keyValue[0]); parseResult.addStringValue(argSpec, keyValue[1]); } parseResult.addOriginalStringValue(argSpec, raw); }
private int consumeOneArgument(ArgSpec argSpec, LookBehind lookBehind, Range arity, int consumed, String arg, Class<?> type, List<Object> result, int index, String argDescription) { if (!lookBehind.isAttached()) { parseResult.nowProcessing(argSpec, arg); } String raw = trim(arg); String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed); ITypeConverter<?> converter = getTypeConverter(type, argSpec, 0); for (int j = 0; j < values.length; j++) { result.add(tryConvert(argSpec, index, converter, values[j], type)); if (tracer.isInfo()) { tracer.info("Adding [%s] to %s for %s%n", String.valueOf(result.get(result.size() - 1)), argSpec.toString(), argDescription); } parseResult.addStringValue(argSpec, values[j]); } parseResult.addOriginalStringValue(argSpec, raw); return ++index; } private boolean canConsumeOneArgument(ArgSpec argSpec, Range arity, int consumed, String arg, Class<?> type, String argDescription) {
private ITypeConverter<?> getTypeConverter(final Class<?> type, ArgSpec argSpec, int index) { if (argSpec.converters().length > index) { return argSpec.converters()[index]; } if (converterRegistry.containsKey(type)) { return converterRegistry.get(type); } if (type.isEnum()) { return new ITypeConverter<Object>() { @SuppressWarnings("unchecked") public Object convert(String value) throws Exception { if (commandSpec.parser().caseInsensitiveEnumValuesAllowed()) { String upper = value.toUpperCase(); for (Object enumConstant : type.getEnumConstants()) { if (upper.equals(String.valueOf(enumConstant).toUpperCase())) { return enumConstant; } } } try { return Enum.valueOf((Class<Enum>) type, value); } catch (Exception ex) { throw new TypeConversionException( String.format("expected one of %s but was '%s'", Arrays.asList(type.getEnumConstants()), value)); } } }; } throw new MissingTypeConverterException(CommandLine.this, "No TypeConverter registered for " + type.getName() + " of " + argSpec); }
/** Returns the description of this option, after variables are rendered. Used when generating the usage documentation. * @see Option#description() * @since 3.2 */ public String[] renderedDescription() { String[] desc = description(); if (desc.length == 0) { return desc; } StringBuilder candidates = new StringBuilder(); if (completionCandidates() != null) { for (String c : completionCandidates()) { if (candidates.length() > 0) { candidates.append(", "); } candidates.append(c); } } String defaultValueString = defaultValueString(); String[] result = new String[desc.length]; for (int i = 0; i < desc.length; i++) { result[i] = String.format(desc[i].replace(DESCRIPTION_VARIABLE_DEFAULT_VALUE, defaultValueString) .replace(DESCRIPTION_VARIABLE_COMPLETION_CANDIDATES, candidates.toString())); } return result; }
private int applyValuesToMapField(ArgSpec argSpec, LookBehind lookBehind, Range arity, Stack<String> args, Set<ArgSpec> initialized, String argDescription) throws Exception { Class<?>[] classes = argSpec.auxiliaryTypes(); if (classes.length < 2) { throw new ParameterException(CommandLine.this, argSpec.toString() + " needs two types (one for the map key, one for the value) but only has " + classes.length + " types configured.",argSpec, null); } ITypeConverter<?> keyConverter = getTypeConverter(classes[0], argSpec, 0); ITypeConverter<?> valueConverter = getTypeConverter(classes[1], argSpec, 1); @SuppressWarnings("unchecked") Map<Object, Object> map = (Map<Object, Object>) argSpec.getValue(); if (map == null || (!map.isEmpty() && !initialized.contains(argSpec))) { tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName()); map = createMap(argSpec.type()); // map class argSpec.setValue(map); } initialized.add(argSpec); int originalSize = map.size(); consumeMapArguments(argSpec, lookBehind, arity, args, classes, keyConverter, valueConverter, map, argDescription); parseResult.add(argSpec, position); argSpec.setValue(map); return map.size() - originalSize; }