/* Copyright 2017 Remko Popma Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package picocli; import java.io.*; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.*; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.NetworkInterface; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.ByteOrder; import java.nio.charset.Charset; import java.text.BreakIterator; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import picocli.CommandLine.Help.Ansi.IStyle; import picocli.CommandLine.Help.Ansi.Style; import picocli.CommandLine.Help.Ansi.Text; import picocli.CommandLine.Model.*; import picocli.CommandLine.ParseResult.GroupMatchContainer; import static java.util.Locale.ENGLISH; import static picocli.CommandLine.Help.Column.Overflow.SPAN; import static picocli.CommandLine.Help.Column.Overflow.TRUNCATE; import static picocli.CommandLine.Help.Column.Overflow.WRAP; /** *
* CommandLine interpreter that uses reflection to initialize an annotated user object with values obtained from the * command line arguments. *
* The full user manual is hosted at https://picocli.info. *
* An example that implements {@code Callable} and uses the {@link #execute(String...) CommandLine.execute} convenience API to run in a single line of code: *
** @Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0", * description = "Prints the checksum (SHA-1 by default) of a file to STDOUT.") * class CheckSum implements Callable<Integer> { * * @Parameters(index = "0", description = "The file whose checksum to calculate.") * private File file; * * @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...") * private String algorithm = "SHA-1"; * * @Override * public Integer call() throws Exception { // your business logic goes here... * byte[] fileContents = Files.readAllBytes(file.toPath()); * byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents); * System.out.printf("%0" + (digest.length*2) + "x%n", new BigInteger(1,digest)); * return 0; * } * * // CheckSum implements Callable, so parsing, error handling and handling user * // requests for usage help or version help can be done with one line of code. * public static void main(String[] args) { * int exitCode = new CommandLine(new CheckSum()).execute(args); * System.exit(exitCode); * } * } **
Another example where the application calls {@code parseArgs} and takes responsibility * for error handling and checking whether the user requested help:
*import static picocli.CommandLine.*; * * @Command(mixinStandardHelpOptions = true, version = "v3.0.0", * header = "Encrypt FILE(s), or standard input, to standard output or to the output file.") * public class Encrypt { * * @Parameters(description = "Any number of input files") * private List<File> files = new ArrayList<File>(); * * @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)") * private File outputFile; * * @Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.") * private boolean[] verbose; * } **
* Use {@code CommandLine} to initialize a user object as follows: *
* public static void main(String... args) { * Encrypt encrypt = new Encrypt(); * try { * ParseResult parseResult = new CommandLine(encrypt).parseArgs(args); * if (!CommandLine.printHelpIfRequested(parseResult)) { * runProgram(encrypt); * } * } catch (ParameterException ex) { // command line arguments could not be parsed * System.err.println(ex.getMessage()); * ex.getCommandLine().usage(System.err); * } * } *
* Invoke the above program with some command line arguments. The below are all equivalent: *
** --verbose --out=outfile in1 in2 * --verbose --out outfile in1 in2 * -v --out=outfile in1 in2 * -v -o outfile in1 in2 * -v -o=outfile in1 in2 * -vo outfile in1 in2 * -vo=outfile in1 in2 * -v -ooutfile in1 in2 * -vooutfile in1 in2 **
* *
** *
*/ public class CommandLine { /** This is picocli version {@value}. */ public static final String VERSION = "4.7.6-SNAPSHOT"; private static final Tracer TRACER = new Tracer(); private CommandSpec commandSpec; private final Interpreter interpreter; private final IFactory factory; private Object executionResult; private PrintWriter out; private PrintWriter err; private Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO); private IExitCodeExceptionMapper exitCodeExceptionMapper; private IExecutionStrategy executionStrategy = new RunLast(); private IParameterExceptionHandler parameterExceptionHandler = new IParameterExceptionHandler() { public int handleParseException(ParameterException ex, String[] args) { CommandLine cmd = ex.getCommandLine(); DefaultExceptionHandler.internalHandleParseException(ex, cmd.getErr(), cmd.getColorScheme()); return mappedExitCode(ex, cmd.getExitCodeExceptionMapper(), cmd.getCommandSpec().exitCodeOnInvalidInput()); } }; private IExecutionExceptionHandler executionExceptionHandler = new IExecutionExceptionHandler() { public int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) throws Exception { throw ex; } }; /** * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and a default {@linkplain IFactory factory}. *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 and methods, in which case picocli automatically * constructs a {@code CommandSpec} from this user object. *
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 default factory to get an instance. *
* If the specified object implements {@code Runnable} or {@code Callable}, or if it is a {@code Method} object, * the command can be run as an application in a single line of code by using the * {@link #execute(String...) execute} method to omit some boilerplate code for handling help requests and invalid input. * See {@link #getCommandMethods(Class, String) getCommandMethods} for a convenient way to obtain a command {@code Method}. *
* When the {@link #parseArgs(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. *
* @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation */ public CommandLine(Object command) { this(command, new DefaultFactory()); } /** * 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. *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 and methods, in which case picocli automatically * constructs a {@code CommandSpec} from this user object. *
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. *
* If the specified object implements {@code Runnable} or {@code Callable}, or if it is a {@code Method} object, * the command can be run as an application in a single line of code by using the * {@link #execute(String...) execute} method to omit some boilerplate code for handling help requests and invalid input. * See {@link #getCommandMethods(Class, String) getCommandMethods} for a convenient way to obtain a command {@code Method}. *
* When the {@link #parseArgs(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. *
* @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(command, factory, true); } private CommandLine(Object command, IFactory factory, boolean userCalled) { this.factory = Assert.notNull(factory, "factory"); interpreter = new Interpreter(); commandSpec = CommandSpec.forAnnotatedObject(command, factory); commandSpec.commandLine(this); if (userCalled) { this.applyModelTransformations(); } commandSpec.validate(); if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); } } /** Apply transformers to command spec recursively. */ private void applyModelTransformations() { if (commandSpec.modelTransformer != null) { commandSpec = commandSpec.modelTransformer.transform(commandSpec); } for (CommandLine cmd : getSubcommands().values()) { cmd.applyModelTransformations(); } } private CommandLine copy() { CommandLine result = new CommandLine(commandSpec.copy(), factory); // create a new sub-hierarchy result.err = err; result.out = out; result.colorScheme = colorScheme; result.executionStrategy = executionStrategy; result.exitCodeExceptionMapper = exitCodeExceptionMapper; result.executionExceptionHandler = executionExceptionHandler; result.parameterExceptionHandler = parameterExceptionHandler; result.interpreter.converterRegistry.clear(); result.interpreter.converterRegistry.putAll(interpreter.converterRegistry); return result; } /** * Returns the {@code CommandSpec} model that this {@code CommandLine} was constructed with. * @return the {@code CommandSpec} model * @since 3.0 */ public CommandSpec getCommandSpec() { return commandSpec; } /** * Adds the options and positional parameters in the specified mixin to this command. *The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a user object with * {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically * constructs a {@code CommandSpec} from this user object. *
* @param name the name by which the mixin object may later be retrieved * @param mixin an annotated user object or a {@link CommandSpec CommandSpec} object whose options and positional parameters to add to this command * @return this CommandLine object, to allow method chaining * @since 3.0 */ public CommandLine addMixin(String name, Object mixin) { getCommandSpec().addMixin(name, CommandSpec.forAnnotatedObject(mixin, factory)); return this; } /** * Returns a map of user objects whose options and positional parameters were added to ("mixed in" with) this command. * @return a new Map containing the user objects mixed in with this command. If {@code CommandSpec} objects without * user objects were programmatically added, use the {@link CommandSpec#mixins() underlying model} directly. * @since 3.0 */ public Map* CommandLine commandLine = new CommandLine(new Git()) * .addSubcommand("status", new GitStatus()) * .addSubcommand("commit", new GitCommit(); * .addSubcommand("add", new GitAdd()) * .addSubcommand("branch", new GitBranch()) * .addSubcommand("checkout", new GitCheckout()) * //... * ; ** *
The specified object can be an annotated object or a * {@code CommandLine} instance with its own nested subcommands. For example:
** CommandLine commandLine = new CommandLine(new MainCommand()) * .addSubcommand("cmd1", new ChildCommand1()) // subcommand * .addSubcommand("cmd2", new ChildCommand2()) * .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands * .addSubcommand("cmd3sub1", new GrandChild3Command1()) * .addSubcommand("cmd3sub2", new GrandChild3Command2()) * .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting * .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1()) * .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2()) * ) * ); **
The default type converters are available on all subcommands and nested sub-subcommands, but custom type * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered. * To ensure a custom type converter is available to all subcommands, register the type converter last, after * adding subcommands.
*See also the {@link Command#subcommands()} annotation to register subcommands declaratively.
* * @param name the string to recognize on the command line as a subcommand. * If {@code null}, the {@linkplain CommandSpec#name() name} of the specified subcommand is used; * if this is also {@code null}, the first {@linkplain CommandSpec#aliases() alias} is used. * @param command the object to initialize with command line arguments following the subcommand name. * This may be a {@code Class} that has a {@code @Command} annotation, or an instance of such a * class, or a {@code CommandSpec} or {@code CommandLine} instance with its own (nested) subcommands. * @return this CommandLine object, to allow method chaining * @see #registerConverter(Class, ITypeConverter) * @since 0.9.7 * @see Command#subcommands() * @throws InitializationException if the specified name is {@code null}, and no alternative name could be found, * or if another subcommand was already registered under the same name, or if one of the aliases * of the specified subcommand was already used by another subcommand. */ public CommandLine addSubcommand(String name, Object command) { return addSubcommand(name, command, new String[0]); } /** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}. * @param name the string to recognize on the command line as a subcommand. * If {@code null}, the {@linkplain CommandSpec#name() name} of the specified subcommand is used; * if this is also {@code null}, the first {@linkplain CommandSpec#aliases() alias} is used. * @param command the object to initialize with command line arguments following the subcommand name. * This may be a {@code Class} that has a {@code @Command} annotation, or an instance of such a * class, or a {@code CommandSpec} or {@code CommandLine} instance with its own (nested) subcommands. * @param aliases zero or more alias names that are also recognized on the command line as this subcommand * @return this CommandLine object, to allow method chaining * @since 3.1 * @see #addSubcommand(String, Object) * @throws InitializationException if the specified name is {@code null}, and no alternative name could be found, * or if another subcommand was already registered under the same name, or if one of the aliases * of the specified subcommand was already used by another subcommand. */ public CommandLine addSubcommand(String name, Object command, String... aliases) { CommandLine subcommandLine = toCommandLine(command, factory); subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases)); getCommandSpec().addSubcommand(name, subcommandLine); return this; } /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance. * @return a map with the registered subcommands * @since 0.9.7 */ public MapThe specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param helpFactory the new help factory. Must be non-{@code null}. * @return this {@code CommandLine} object, to allow method chaining * @since 3.9 */ public CommandLine setHelpFactory(IHelpFactory helpFactory) { getCommandSpec().usageMessage().helpFactory(helpFactory); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setHelpFactory(helpFactory); } return this; } /** * Returns the section keys in the order that the usage help message should render the sections. * This ordering may be modified with {@link #setHelpSectionKeys(List) setSectionKeys}. The default keys are (in order): *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
*Use {@link UsageMessageSpec#sectionKeys(List)} to customize a command without affecting its subcommands.
* @see #getHelpSectionKeys * @since 3.9 */ public CommandLine setHelpSectionKeys(List* NOTE: By modifying the returned {@code Map}, only the usage help message of this command is affected. * Use {@link #setHelpSectionMap(Map)} to customize the usage help message for this command and all subcommands. *
* @since 3.9 */ public MapThe specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
*Use {@link UsageMessageSpec#sectionMap(Map)} to customize a command without affecting its subcommands.
* @see #getHelpSectionMap * @since 3.9 */ public CommandLine setHelpSectionMap(MapThe specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param adjustForWideChars if true, wide Chinese, Japanese and Korean characters are counted as double the size of other characters for line-breaking purposes * @since 4.0 */ public CommandLine setAdjustLineBreaksForWideCJKCharacters(boolean adjustForWideChars) { getCommandSpec().usageMessage().adjustLineBreaksForWideCJKCharacters(adjustForWideChars); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setAdjustLineBreaksForWideCJKCharacters(adjustForWideChars); } return this; } /** Returns whether the value of boolean flag options should be "toggled" when the option is matched. * From 4.0, this is {@code false} by default, and when a flag option is specified on the command line picocli * will set its value to the opposite of its default value. * If this method returns {@code true}, flags are toggled, so if the value is {@code true} it is * set to {@code false}, and when the value is {@code false} it is set to {@code true}. * When toggling is enabled, specifying a flag option twice on the command line will have no effect because they cancel each other out. * @return {@code true} the value of boolean flag options should be "toggled" when the option is matched, {@code false} otherwise * @since 3.0 */ public boolean isToggleBooleanFlags() { return getCommandSpec().parser().toggleBooleanFlags(); } /** Sets whether the value of boolean flag options should be "toggled" when the option is matched. The default is {@code false}, * and when a flag option is specified on the command line picocli will set its value to the opposite of its default value. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 3.0 */ public CommandLine setToggleBooleanFlags(boolean newValue) { getCommandSpec().parser().toggleBooleanFlags(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setToggleBooleanFlags(newValue); } return this; } /** Returns whether variables should be interpolated in String values. The default is {@code true}. * @since 4.0 */ public boolean isInterpolateVariables() { return getCommandSpec().interpolateVariables(); } /** Sets whether variables should be interpolated in String values. The default is {@code true}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @since 4.0 */ public CommandLine setInterpolateVariables(boolean interpolate) { getCommandSpec().interpolateVariables(interpolate); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setInterpolateVariables(interpolate); } return this; } /** Returns whether options for single-value fields can be specified multiple times on the command line. * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens. * When {@code true}, the last specified value is retained. * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise * @since 0.9.7 */ public boolean isOverwrittenOptionsAllowed() { return getCommandSpec().parser().overwrittenOptionsAllowed(); } /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown. * The default is {@code false}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 0.9.7 */ public CommandLine setOverwrittenOptionsAllowed(boolean newValue) { getCommandSpec().parser().overwrittenOptionsAllowed(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setOverwrittenOptionsAllowed(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}. The default is {@code true}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @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 should ignore case when converting arguments to {@code enum} values. The default is {@code false}. * @return {@code true} if enum values can be specified that don't match the {@code toString()} value of the enum constant, {@code false} otherwise; * e.g., for an option of type java.time.DayOfWeek, * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}. * @since 3.4 */ public boolean isCaseInsensitiveEnumValuesAllowed() { return getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(); } /** Sets whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}. * When set to true, for example, for an option of type java.time.DayOfWeek, * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 3.4 */ public CommandLine setCaseInsensitiveEnumValuesAllowed(boolean newValue) { getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setCaseInsensitiveEnumValuesAllowed(newValue); } return this; } /** Returns whether the parser should trim quotes from command line arguments. The default is * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty, * or if its value is "true". *If this property is set to {@code true}, the parser will remove quotes from the command line arguments, as follows:
*If this property is set to {@code true}, the parser will remove quotes from the command line arguments, as follows:
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
*Calling this method will cause the "picocli.trimQuotes" property to have no effect.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @see ParserSpec#trimQuotes(boolean) * @since 3.7 */ public CommandLine setTrimQuotes(boolean newValue) { getCommandSpec().parser().trimQuotes(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setTrimQuotes(newValue); } return this; } /** Returns whether the parser is allowed to split quoted Strings or not. The default is {@code false}, * so quotes are respected: quoted strings are treated as a single value that should not be broken up. ** For example, take a single command line parameter {@code "a,b","x,y"}. With a comma split regex, the default of {@code splitQuotedStrings = false} * means that this value will be split into two strings: {@code "a,b"} and {@code "x,y"}. This is usually what you want. *
* If {@code splitQuotedStrings} is set to {@code true}, quotes are not respected, and the value is split up into four parts: * the first is {@code "a}, the second is {@code b"}, the third is {@code "x}, and the last part is {@code y"}. This is generally not what you want. *
* @deprecated Most applications should not change the default. The rare application that does need to split parameter values * without respecting quotes should use {@link ParserSpec#splitQuotedStrings(boolean)}. * @return {@code true} if the parser is allowed to split quoted Strings, {@code false} otherwise; * @see ArgSpec#splitRegex() * @see ParserSpec#splitQuotedStrings() * @since 3.7 */ @Deprecated public boolean isSplitQuotedStrings() { return getCommandSpec().parser().splitQuotedStrings(); } /** Sets whether the parser is allowed to split quoted Strings. The default is {@code false}, * so quotes are respected: quoted strings are treated as a single value that should not be broken up. ** For example, take a single command line parameter {@code "a,b","x,y"}. With a comma split regex, the default of {@code splitQuotedStrings = false} * means that this value will be split into two strings: {@code "a,b"} and {@code "x,y"}. This is usually what you want. *
* However, if {@code splitQuotedStrings} is set to {@code true}, quotes are not respected, and the value is split up into four parts: * the first is {@code "a}, the second is {@code b"}, the third is {@code "x}, and the last part is {@code y"}. This is generally not what you want. *
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @deprecated Most applications should not change the default. The rare application that does need to split parameter values * without respecting quotes should use {@link ParserSpec#splitQuotedStrings(boolean)}. * @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @see ArgSpec#splitRegex() * @see ParserSpec#splitQuotedStrings(boolean) * @since 3.7 */ @Deprecated public CommandLine setSplitQuotedStrings(boolean newValue) { getCommandSpec().parser().splitQuotedStrings(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setSplitQuotedStrings(newValue); } return this; } /** Returns the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters. * @return the end-of-options delimiter. The default is {@code "--"}. * @since 3.5 */ public String getEndOfOptionsDelimiter() { return getCommandSpec().parser().endOfOptionsDelimiter(); } /** Sets the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters. * @param delimiter the end-of-options delimiter; must not be {@code null}. The default is {@code "--"}. * @return this {@code CommandLine} object, to allow method chaining * @since 3.5 */ public CommandLine setEndOfOptionsDelimiter(String delimiter) { getCommandSpec().parser().endOfOptionsDelimiter(delimiter); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setEndOfOptionsDelimiter(delimiter); } return this; } /** Returns whether upper case and lower case should be ignored when matching subcommands. The default is {@code false}. * @return {@code true} if subcommands can be matched when they differ only in case from the {@code getCommandName()} value of a registered one, {@code false} otherwise. * For example, if true, for a subcommand with name {@code help}, inputs like {@code help}, {@code HeLp} and {@code HELP} are all recognized. * @since 4.3 */ public boolean isSubcommandsCaseInsensitive() { return getCommandSpec().subcommandsCaseInsensitive(); } /** Sets whether upper case and lower case should be ignored when matching subcommands. The default is {@code false}. * For example, when set to {@code true}, for a subcommand with name {@code help}, inputs like {@code help}, {@code HeLp} and {@code HELP} are all recognized. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 4.3 */ public CommandLine setSubcommandsCaseInsensitive(boolean newValue) { getCommandSpec().subcommandsCaseInsensitive(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setSubcommandsCaseInsensitive(newValue); } return this; } /** Returns whether upper case and lower case should be ignored when matching option names. The default is {@code false}. * @return {@code true} if options can be matched when they differ only in case from the {@code names()} value of a registered one, {@code false} otherwise; * For example, if true, for an option with name {@code -h}, inputs like {@code -h}, {@code -H} are both recognized. * @since 4.3 */ public boolean isOptionsCaseInsensitive() { return getCommandSpec().optionsCaseInsensitive(); } /** Sets whether upper case and lower case should be ignored when matching option names. The default is {@code false}. * For example, when set to {@code true}, for an option with name {@code -h}, inputs like {@code -h}, {@code -H} are both recognized. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* Note that changing case sensitivity will also change the case sensitivity of {@linkplain Option#negatable() negatable} options: * any custom {@link INegatableOptionTransformer} that was previously installed will be replaced by the case-insensitive * version of the default transformer. To ensure your custom transformer is used, install it last, after changing case sensitivity. * @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 4.3 */ public CommandLine setOptionsCaseInsensitive(boolean newValue) { getCommandSpec().optionsCaseInsensitive(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setOptionsCaseInsensitive(newValue); } return this; } /** Returns whether abbreviation of subcommands should be allowed when matching subcommands. The default is {@code false}. * @return {@code true} if subcommands can be matched when they are abbreviations of the {@code getCommandName()} value of a registered one, {@code false} otherwise. * For example, if true, for a subcommand with name {@code helpCommand}, inputs like {@code h}, {@code h-c} and {@code hC} are all recognized. * @since 4.4 */ public boolean isAbbreviatedSubcommandsAllowed() { return getCommandSpec().parser().abbreviatedSubcommandsAllowed(); } /** Sets whether abbreviated subcommands should be matched. The default is {@code false}. * For example, when set to {@code true}, for a subcommand {@code helpCommand}, inputs like {@code h}, {@code h-c} and {@code hC} are all recognized. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 4.4 */ public CommandLine setAbbreviatedSubcommandsAllowed(boolean newValue) { getCommandSpec().parser().abbreviatedSubcommandsAllowed(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setAbbreviatedSubcommandsAllowed(newValue); } return this; } /** Returns whether abbreviation of option names should be allowed when matching options. The default is {@code false}. * @return {@code true} if options can be matched when they are abbreviations of the {@code names()} value of a registered one, {@code false} otherwise. * For example, if true, for a subcommand with name {@code --helpMe}, inputs like {@code --h}, {@code --h-m} and {@code --hM} are all recognized. * @since 4.4 */ public boolean isAbbreviatedOptionsAllowed() { return getCommandSpec().parser().abbreviatedOptionsAllowed(); } /** Sets whether abbreviated option names should be matched. The default is {@code false}. * For example, when set to {@code true}, for an option with name {@code --helpMe}, inputs like {@code --h}, {@code --h-m} and {@code --hM} are all recognized. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 4.4 */ public CommandLine setAbbreviatedOptionsAllowed(boolean newValue) { getCommandSpec().parser().abbreviatedOptionsAllowed(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setAbbreviatedOptionsAllowed(newValue); } return this; } /** Returns the default value provider for the command, or {@code null} if none has been set. * @return the default value provider for this command, or {@code null} * @since 3.6 * @see Command#defaultValueProvider() * @see CommandSpec#defaultValueProvider() * @see ArgSpec#defaultValueString() */ public IDefaultValueProvider getDefaultValueProvider() { return getCommandSpec().defaultValueProvider(); } /** Sets a default value provider for the command and sub-commands *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * sub-commands and nested sub-subcommands at the moment this method is called. Sub-commands added * later will have the default setting. To ensure a setting is applied to all * sub-commands, call the setter last, after adding sub-commands.
* @param newValue the default value provider to use * @return this {@code CommandLine} object, to allow method chaining * @since 3.6 */ public CommandLine setDefaultValueProvider(IDefaultValueProvider newValue) { getCommandSpec().defaultValueProvider(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setDefaultValueProvider(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 * @since 2.3 */ public boolean isStopAtPositional() { return getCommandSpec().parser().stopAtPositional(); } /** Sets 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}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise * @return this {@code CommandLine} object, to allow method chaining * @since 2.3 */ public CommandLine setStopAtPositional(boolean newValue) { getCommandSpec().parser().stopAtPositional(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setStopAtPositional(newValue); } return this; } /** Returns whether the parser should stop interpreting options and positional parameters as soon as it encounters an * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited). * The default is {@code false}. *Setting this flag to {@code true} automatically sets the {@linkplain #isUnmatchedArgumentsAllowed() unmatchedArgumentsAllowed} flag to {@code true} also.
* @return {@code true} when an unmatched option should result in the remaining command line arguments to be added to the * {@linkplain #getUnmatchedArguments() unmatchedArguments list} * @since 2.3 */ public boolean isStopAtUnmatched() { return getCommandSpec().parser().stopAtUnmatched(); } /** Sets whether the parser should stop interpreting options and positional parameters as soon as it encounters an * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited). * The default is {@code false}. *Setting this flag to {@code true} automatically sets the {@linkplain #setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} flag to {@code true} also.
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue {@code true} when an unmatched option should result in the remaining command line arguments to be added to the * {@linkplain #getUnmatchedArguments() unmatchedArguments list} * @return this {@code CommandLine} object, to allow method chaining * @since 2.3 */ public CommandLine setStopAtUnmatched(boolean newValue) { getCommandSpec().parser().stopAtUnmatched(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setStopAtUnmatched(newValue); } if (newValue) { setUnmatchedArgumentsAllowed(true); } return this; } /** Returns whether options can have parameter values that match subcommand names or aliases, * or whether such values should be rejected with a missing parameter exception. * The default is {@code false}, so by default input like {@code -x=subcommand} is rejected if {@code -x} is an option that takes a String parameter, and {@code subcommand} is a subcommand of this command. * @return {@code true} when options can have parameter values that match subcommand names or aliases, {@code false} when such values should be rejected with a missing parameter exception * @since 4.7.6-SNAPSHOT * @see ParserSpec#allowSubcommandsAsOptionParameters() */ public boolean isAllowSubcommandsAsOptionParameters() { return getCommandSpec().parser().allowSubcommandsAsOptionParameters(); } /** Sets whether options can have parameter values that match subcommand names or aliases, or whether such values should be rejected with a missing parameter exception. * The default is {@code false}, so by default * input like {@code -x=subcommand} is rejected if {@code -x} is an option that takes a String parameter, and {@code subcommand} is a subcommand of this command. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, options can have parameter values that match subcommand names or aliases, when {@code false}, such values are rejected with a missing parameter exception * @return this {@code CommandLine} object, to allow method chaining * @since 4.7.6-SNAPSHOT * @see ParserSpec#allowSubcommandsAsOptionParameters(boolean) */ public CommandLine setAllowSubcommandsAsOptionParameters(boolean newValue) { getCommandSpec().parser().allowSubcommandsAsOptionParameters(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setAllowSubcommandsAsOptionParameters(newValue); } return this; } /** Returns whether options can have parameter values that match the name of an option in this command, * or whether such values should be rejected with a missing parameter exception. * The default is {@code false}, so by default input like {@code -x=--some-option} is rejected if {@code -x} is an option that takes a String parameter, and {@code --some-option} is an option of this command. *This method only considers actual options of this command, as opposed to {@link #isUnmatchedOptionsAllowedAsOptionParameters()}, which considers values that resemble options.
* @return {@code true} when options can have parameter values that match the name of an option in this command, {@code false} when such values should be rejected with a missing parameter exception * @since 4.7.6-SNAPSHOT * @see #isUnmatchedOptionsAllowedAsOptionParameters() * @see ParserSpec#allowOptionsAsOptionParameters() */ public boolean isAllowOptionsAsOptionParameters() { return getCommandSpec().parser().allowOptionsAsOptionParameters(); } /** Sets whether options can have parameter values that match the name of an option in this command, or whether such values should be rejected with a missing parameter exception. * The default is {@code false}, so by default * input like {@code -x=--some-option} is rejected if {@code -x} is an option that takes a String parameter, and {@code --some-option} is an option of this command. *This method only considers actual options of this command, as opposed to {@link #setUnmatchedOptionsAllowedAsOptionParameters(boolean)}, which considers values that resemble options.
*Use with caution! When set to {@code true}, any option in the command will consume the maximum number of arguments possible for its arity. * This means that an option with {@code arity = "*"} will consume all command line arguments following that option. * If this is not what you want, consider custom parameter processing.
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, options can have parameter values that match the name of an option in this command, when {@code false}, such values are rejected with a missing parameter exception * @return this {@code CommandLine} object, to allow method chaining * @since 4.7.6-SNAPSHOT * @see #setUnmatchedOptionsAllowedAsOptionParameters(boolean) * @see ParserSpec#allowOptionsAsOptionParameters(boolean) */ public CommandLine setAllowOptionsAsOptionParameters(boolean newValue) { getCommandSpec().parser().allowOptionsAsOptionParameters(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setAllowOptionsAsOptionParameters(newValue); } return this; } /** Returns whether options can have parameter values that resemble an option, or whether such values should be rejected as unknown options. * The default is {@code true}, so by default input like {@code -x=-unknown} is accepted if {@code -x} is an option that takes a String parameter. *This method only considers values that resemble options, as opposed to {@link #isAllowOptionsAsOptionParameters()}, which considers actual options of this command.
* @return {@code true} when options can have parameter values that resemble an option, {@code false} when such values should be rejected as unknown options * @since 4.4 * @see #isAllowOptionsAsOptionParameters() * @see ParserSpec#unmatchedOptionsAllowedAsOptionParameters() */ public boolean isUnmatchedOptionsAllowedAsOptionParameters() { return getCommandSpec().parser().unmatchedOptionsAllowedAsOptionParameters(); } /** Sets whether options can have parameter values that resemble an option, or whether such values should be rejected as unknown options. * The default is {@code true}, so by default * input like {@code -x=-unknown} is accepted if {@code -x} is an option that takes a String parameter. *This method only considers values that resemble options, as opposed to {@link #setAllowOptionsAsOptionParameters(boolean)}, which considers actual options of this command.
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, options can have parameter values that resemble an option, when {@code false}, such values are rejected as unknown options * @return this {@code CommandLine} object, to allow method chaining * @since 4.4 * @see #setAllowOptionsAsOptionParameters(boolean) * @see ParserSpec#unmatchedOptionsAllowedAsOptionParameters(boolean) */ public CommandLine setUnmatchedOptionsAllowedAsOptionParameters(boolean newValue) { getCommandSpec().parser().unmatchedOptionsAllowedAsOptionParameters(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setUnmatchedOptionsAllowedAsOptionParameters(newValue); } return this; } /** Returns whether arguments on the command line that resemble an option should be treated as positional parameters. * The default is {@code false} and the parser behaviour depends on {@link #isUnmatchedArgumentsAllowed()}. * @return {@code true} arguments on the command line that resemble an option should be treated as positional parameters, {@code false} otherwise * @see #getUnmatchedArguments() * @since 3.0 */ public boolean isUnmatchedOptionsArePositionalParams() { return getCommandSpec().parser().unmatchedOptionsArePositionalParams(); } /** Sets whether arguments on the command line that resemble an option should be treated as positional parameters. * The default is {@code false}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, arguments on the command line that resemble an option should be treated as positional parameters. * @return this {@code CommandLine} object, to allow method chaining * @since 3.0 * @see #getUnmatchedArguments() * @see #isUnmatchedArgumentsAllowed */ public CommandLine setUnmatchedOptionsArePositionalParams(boolean newValue) { getCommandSpec().parser().unmatchedOptionsArePositionalParams(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setUnmatchedOptionsArePositionalParams(newValue); } return this; } /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields. * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens. * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method. * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise * @see #getUnmatchedArguments() * @since 0.9.7 */ public boolean isUnmatchedArgumentsAllowed() { return getCommandSpec().parser().unmatchedArgumentsAllowed(); } /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown. * The default is {@code false}. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method. * @return this {@code CommandLine} object, to allow method chaining * @since 0.9.7 * @see #getUnmatchedArguments() */ public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) { getCommandSpec().parser().unmatchedArgumentsAllowed(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setUnmatchedArgumentsAllowed(newValue); } return this; } /** Returns the list of unmatched command line arguments, if any. * @return the list of unmatched command line arguments or an empty list * @see #isUnmatchedArgumentsAllowed() * @since 0.9.7 */ public ListCommands can override these defaults with annotations (e.g. {@code @Command(exitCodeOnInvalidInput = 64, exitCodeOnExecutionException = 70)} * or programmatically (e.g. {@link CommandSpec#exitCodeOnInvalidInput(int)}).
*Additionally, there are several mechanisms for commands to return custom exit codes. * See the javadoc of the {@link #execute(String...) execute} method for details.
*There are a few conventions, but there is no * standard. The specific set of codes returned is unique to the program that sets it. * Typically an exit code of zero indicates success, any non-zero exit code indicates failure. For reference, here are a few conventions:
* *Note that *nix shells may restrict exit codes to the 0-255 range, DOS seems to allow larger numbers. * See this StackOverflow question.
* @since 4.0 */ public static final class ExitCode { /** Return value from the {@link #execute(String...) execute} and * {@link #executeHelpRequest(ParseResult) executeHelpRequest} methods signifying successful termination. *The value of this constant is {@value}.
*/ public static final int OK = 0; /** Return value from the {@link #execute(String...) execute} method signifying internal software error: an exception occurred when invoking the Runnable, Callable or Method user object of a command.The value of this constant is {@value}.
*/ public static final int SOFTWARE = 1; /** Return value from the {@link #execute(String...) execute} method signifying command line usage error: user input for the command was incorrect, e.g., the wrong number of arguments, a bad flag, a bad syntax in a parameter, or whatever.The value of this constant is {@value}.
*/ public static final int USAGE = 2; private ExitCode() {} // don't instantiate } /** {@code @Command}-annotated classes can implement this interface to specify an exit code that will be returned * from the {@link #execute(String...) execute} method when the command is successfully invoked. * *Example usage:
** @Command * class MyCommand implements Runnable, IExitCodeGenerator { * public void run() { System.out.println("Hello"); } * public int getExitCode() { return 123; } * } * CommandLine cmd = new CommandLine(new MyCommand()); * int exitCode = cmd.execute(args); * assert exitCode == 123; * System.exit(exitCode); ** @since 4.0 */ public interface IExitCodeGenerator { /** Returns the exit code that should be returned from the {@link #execute(String...) execute} method. * @return the exit code */ int getExitCode(); } /** Interface that provides the appropriate exit code that will be returned from the {@link #execute(String...) execute} * method for an exception that occurred during parsing or while invoking the command's Runnable, Callable, or Method. *
Example usage:
** @Command * class FailingCommand implements Callable<Void> { * public Void call() throws IOException { * throw new IOException("error"); * } * } * IExitCodeExceptionMapper mapper = new IExitCodeExceptionMapper() { * public int getExitCode(Throwable t) { * if (t instanceof IOException && "error".equals(t.getMessage())) { * return 123; * } * return 987; * } * } * * CommandLine cmd = new CommandLine(new FailingCommand()); * cmd.setExitCodeExceptionMapper(mapper); * int exitCode = cmd.execute(args); * assert exitCode == 123; * System.exit(exitCode); ** @see #setExitCodeExceptionMapper(IExitCodeExceptionMapper) * @since 4.0 */ public interface IExitCodeExceptionMapper { /** Returns the exit code that should be returned from the {@link #execute(String...) execute} method. * @param exception the exception that occurred during parsing or while invoking the command's Runnable, Callable, or Method. * @return the exit code */ int getExitCode(Throwable exception); } private static int mappedExitCode(Throwable t, IExitCodeExceptionMapper mapper, int defaultExitCode) { try { return (mapper != null) ? mapper.getExitCode(t) : defaultExitCode; } catch (Exception ex) { ex.printStackTrace(); return defaultExitCode; } } /** Returns the color scheme to use when printing help. * The default value is the {@linkplain picocli.CommandLine.Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme} with {@link Help.Ansi#AUTO Ansi.AUTO}. * @see #execute(String...) * @see #usage(PrintStream) * @see #usage(PrintWriter) * @see #getUsageMessage() * @see Help#defaultColorScheme(CommandLine.Help.Ansi) * @since 4.0 */ public Help.ColorScheme getColorScheme() { return colorScheme; } /** Sets the color scheme to use when printing help. *
The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param colorScheme the new color scheme * @see #execute(String...) * @see #usage(PrintStream) * @see #usage(PrintWriter) * @see #getUsageMessage() * @since 4.0 */ public CommandLine setColorScheme(Help.ColorScheme colorScheme) { this.colorScheme = Assert.notNull(colorScheme, "colorScheme"); for (CommandLine sub : getSubcommands().values()) { sub.setColorScheme(colorScheme); } return this; } /** Returns the writer used when printing user-requested usage help or version help during command {@linkplain #execute(String...) execution}. * Defaults to a PrintWriter wrapper around {@code System.out} unless {@link #setOut(PrintWriter)} was called with a different writer. *This method is used by {@link #execute(String...)}. Custom {@link IExecutionStrategy IExecutionStrategy} implementations should also use this writer. *
* By convention, when the user requests * help with a {@code --help} or similar option, the usage help message is printed to the standard output stream so that it can be easily searched and paged.
* @since 4.0 */ public PrintWriter getOut() { if (out == null) { setOut(newPrintWriter(System.out, getStdoutEncoding())); } return out; } /** Sets the writer to use when printing user-requested usage help or version help during command {@linkplain #execute(String...) execution}. *This method is used by {@link #execute(String...)}. Custom {@link IExecutionStrategy IExecutionStrategy} implementations should also use this writer.
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param out the new PrintWriter to use * @return this CommandLine for method chaining * @since 4.0 */ public CommandLine setOut(PrintWriter out) { this.out = Assert.notNull(out, "out"); for (CommandLine sub : getSubcommands().values()) { sub.setOut(out); } return this; } /** Returns the writer to use when printing diagnostic (error) messages during command {@linkplain #execute(String...) execution}. * Defaults to a PrintWriter wrapper around {@code System.err}, unless {@link #setErr(PrintWriter)} was called with a different writer. *This method is used by {@link #execute(String...)}. * {@link IParameterExceptionHandler IParameterExceptionHandler} and {@link IExecutionExceptionHandler IExecutionExceptionHandler} implementations * should use this writer to print error messages (which may include a usage help message) when an unexpected error occurs.
* @since 4.0 */ public PrintWriter getErr() { if (err == null) { setErr(newPrintWriter(System.err, getStderrEncoding())); } return err; } /** Sets the writer to use when printing diagnostic (error) messages during command {@linkplain #execute(String...) execution}. *This method is used by {@link #execute(String...)}. * {@link IParameterExceptionHandler IParameterExceptionHandler} and {@link IExecutionExceptionHandler IExecutionExceptionHandler} implementations * should use this writer to print error messages (which may include a usage help message) when an unexpected error occurs.
*The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param err the new PrintWriter to use * @return this CommandLine for method chaining * @since 4.0 */ public CommandLine setErr(PrintWriter err) { this.err = Assert.notNull(err, "err"); for (CommandLine sub : getSubcommands().values()) { sub.setErr(err); } return this; } /** * Returns the mapper that was set by the application to map from exceptions to exit codes, for use by the {@link #execute(String...) execute} method. * @return the mapper that was {@linkplain #setExitCodeExceptionMapper(IExitCodeExceptionMapper) set}, or {@code null} if none was set * @since 4.0 */ public IExitCodeExceptionMapper getExitCodeExceptionMapper() { return exitCodeExceptionMapper; } /** Sets the mapper used by the {@link #execute(String...) execute} method to map exceptions to exit codes. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param exitCodeExceptionMapper the new value * @return this CommandLine for method chaining * @since 4.0 */ public CommandLine setExitCodeExceptionMapper(IExitCodeExceptionMapper exitCodeExceptionMapper) { this.exitCodeExceptionMapper = Assert.notNull(exitCodeExceptionMapper, "exitCodeExceptionMapper"); for (CommandLine sub : getSubcommands().values()) { sub.setExitCodeExceptionMapper(exitCodeExceptionMapper); } return this; } /** Returns the execution strategy used by the {@link #execute(String...) execute} method to invoke * the business logic on the user objects of this command and/or the user-specified subcommand(s). * The default value is {@link RunLast RunLast}. * @return the execution strategy to run the user-specified command * @since 4.0 */ public IExecutionStrategy getExecutionStrategy() { return executionStrategy; } /** Sets the execution strategy that the {@link #execute(String...) execute} method should use to invoke * the business logic on the user objects of this command and/or the user-specified subcommand(s). *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param executionStrategy the new execution strategy to run the user-specified command * @return this CommandLine for method chaining * @since 4.0 */ public CommandLine setExecutionStrategy(IExecutionStrategy executionStrategy) { this.executionStrategy = Assert.notNull(executionStrategy, "executionStrategy"); for (CommandLine sub : getSubcommands().values()) { sub.setExecutionStrategy(executionStrategy); } return this; } /** * Returns the handler for dealing with invalid user input when the command is {@linkplain #execute(String...) executed}. *The default implementation prints an error message describing the problem, followed by either {@linkplain UnmatchedArgumentException#printSuggestions(PrintWriter) suggested alternatives} * for mistyped options, or the full {@linkplain #usage(PrintWriter, Help.ColorScheme) usage} help message of the {@linkplain ParameterException#getCommandLine() problematic command}; * it then delegates to the {@linkplain #getExitCodeExceptionMapper() exit code exception mapper} for an exit code, with * {@link CommandSpec#exitCodeOnInvalidInput() exitCodeOnInvalidInput} as the default exit code.
** Alternatively, you can install a "short error message handler" like this: *
** static class ShortErrorMessageHandler implements IParameterExceptionHandler { * public int handleParseException(ParameterException ex, String[] args) { * CommandLine cmd = ex.getCommandLine(); * PrintWriter writer = cmd.getErr(); * * writer.println(ex.getMessage()); * UnmatchedArgumentException.printSuggestions(ex, writer); * writer.print(cmd.getHelp().fullSynopsis()); * * CommandSpec spec = cmd.getCommandSpec(); * writer.printf("Try '%s --help' for more information.%n", spec.qualifiedName()); * * return cmd.getExitCodeExceptionMapper() != null * ? cmd.getExitCodeExceptionMapper().getExitCode(ex) * : spec.exitCodeOnInvalidInput(); * } * } **
Install this error handler like this:
** new CommandLine(new MyApp()) * .setParameterExceptionHandler(new ShortErrorMessageHandler()) * .execute(args); ** @return the handler for dealing with invalid user input * @since 4.0 */ public IParameterExceptionHandler getParameterExceptionHandler() { return parameterExceptionHandler; } /** * Sets the handler for dealing with invalid user input when the command is {@linkplain #execute(String...) executed}. *
The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param parameterExceptionHandler the new handler for dealing with invalid user input * @return this CommandLine for method chaining * @see #getParameterExceptionHandler() an example short exception handler * @since 4.0 */ public CommandLine setParameterExceptionHandler(IParameterExceptionHandler parameterExceptionHandler) { this.parameterExceptionHandler = Assert.notNull(parameterExceptionHandler, "parameterExceptionHandler"); for (CommandLine sub : getSubcommands().values()) { sub.setParameterExceptionHandler(parameterExceptionHandler); } return this; } /** Returns the handler for dealing with exceptions that occurred in the {@code Callable}, {@code Runnable} or {@code Method} * user object of a command when the command was {@linkplain #execute(String...) executed}. *The default implementation rethrows the specified exception.
* @return the handler for dealing with exceptions that occurred in the business logic when the {@link #execute(String...) execute} method was invoked. * @since 4.0 */ public IExecutionExceptionHandler getExecutionExceptionHandler() { return executionExceptionHandler; } /** * Sets a custom handler for dealing with exceptions that occurred in the {@code Callable}, {@code Runnable} or {@code Method} * user object of a command when the command was executed via the {@linkplain #execute(String...) execute} method. *The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.
* @param executionExceptionHandler the handler for dealing with exceptions that occurred in the business logic when the {@link #execute(String...) execute} method was invoked. * @return this CommandLine for method chaining * @since 4.0 */ public CommandLine setExecutionExceptionHandler(IExecutionExceptionHandler executionExceptionHandler) { this.executionExceptionHandler = Assert.notNull(executionExceptionHandler, "executionExceptionHandler"); for (CommandLine sub : getSubcommands().values()) { sub.setExecutionExceptionHandler(executionExceptionHandler); } return this; } /** ** Convenience method that initializes the specified annotated object from the specified command line arguments. *
* This is equivalent to *
* new CommandLine(command).parseArgs(args); * return command; **
All this method does is parse the arguments and populate the annotated fields and methods. * The caller is responsible for catching any exceptions, handling requests for usage help * or version information, and invoking the business logic. * Applications may be interested in using the {@link #execute(String...)} method instead.
* * @param command the object to initialize. This object contains fields annotated with * {@code @Option} or {@code @Parameters}. * @param args the command line arguments to parse * @param* Convenience method that derives the command specification from the specified interface class, and returns an * instance of the specified interface. The interface is expected to have annotated getter methods. Picocli will * instantiate the interface and the getter methods will return the option and positional parameter values matched on the command line. *
* This is equivalent to *
* CommandLine cli = new CommandLine(spec); * cli.parse(args); * return cli.getCommand(); **
All this method does is parse the arguments and return an instance whose annotated methods return the specified values. * The caller is responsible for catching any exceptions, handling requests for usage help * or version information, and invoking the business logic. * Applications may be interested in using the {@link #execute(String...)} method instead.
* * @param spec the interface that defines the command specification. This object contains getter methods annotated with * {@code @Option} or {@code @Parameters}. * @param args the command line arguments to parse * @param* If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered} * and these subcommands were initialized by matching command line arguments. If parsing fails, a * {@link ParameterException} is thrown. *
*All this method does is parse the arguments and populate the annotated fields and methods. * The caller is responsible for catching any exceptions, handling requests for usage help * or version information, and invoking the business logic. * Applications may be interested in using the {@link #execute(String...)} method instead.
* * @param args the command line arguments to parse * @return a list with the top-level command and any subcommands initialized by this method * @throws ParameterException if the specified command line arguments are invalid; use * {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid * @deprecated use {@link #parseArgs(String...)} instead */ @Deprecated public ListIf parsing fails, a {@link ParameterException} is thrown.
*All this method does is parse the arguments and populate the annotated fields and methods. * The caller is responsible for catching any exceptions, handling requests for usage help * or version information, and invoking the business logic. * Applications may be interested in using the {@link #execute(String...)} method instead.
* * @param args the command line arguments to parse * @return a list with the top-level command and any subcommands initialized by this method * @throws ParameterException if the specified command line arguments are invalid; use * {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid * @see #execute(String...) */ public ParseResult parseArgs(String... args) { interpreter.parse(args); return getParseResult(); } public ParseResult getParseResult() { return interpreter.parseResultBuilder == null ? null : interpreter.parseResultBuilder.build(); } /** Returns the result of calling the user object {@code Callable} or invoking the user object {@code Method} * after parsing the user input, or {@code null} if this command has not been {@linkplain #execute(String...) executed} * or if this {@code CommandLine} is for a subcommand that was not specified by the end user on the command line. *Implementation note:
*It is the responsibility of the {@link IExecutionStrategy IExecutionStrategy} to set this value.
* @param* Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler} * methods to take some next step after the command line was successfully parsed. *
* @see RunFirst * @see RunLast * @see RunAll * @deprecated Use {@link IExecutionStrategy} instead. * @since 2.0 */ @Deprecated public interface IParseResultHandler { /** Processes a List of {@code CommandLine} objects resulting from successfully * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results. * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments * @param out the {@code PrintStream} to print help to if requested * @param ansi for printing help messages using ANSI styles and colors * @return a list of results, or an empty list if there are no results * @throws ParameterException if a help command 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 IExceptionHandler} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed */ List