-
Notifications
You must be signed in to change notification settings - Fork 424
Executing Commands
Picocli 4.0 introduces new API to execute commands. Let’s take a quick look at what changed.
Many command line applications return an exit code to signify success or failure. Zero often means success, a non-zero exit code is often used for errors, but other than that, meanings differ per application.
The new CommandLine.execute
method introduced in picocli 4.0 returns an int
, and applications can use this return value to call System.exit
if desired. For example:
public static void main(String... args) {
CommandLine cmd = new CommandLine(new App());
int exitCode = cmd.execute(args);
System.exit(exitCode);
}
Older versions of picocli had some limited exit code support where picocli would call System.exit
, but this is now deprecated.
@Command
-annotated classes that implement Callable
and @Command
-annotated methods can simply return an int
or Integer
, and this value will be returned from CommandLine.execute
. For example:
@Command(name = "greet")
class Greet implements Callable<Integer> {
public Integer call() {
System.out.println("hi");
return 1;
}
@Command
int shout() {
System.out.println("HI!");
return 2;
}
}
assert 1 == new CommandLine(new Greet()).execute();
assert 2 == new CommandLine(new Greet()).execute("shout");
Commands with a user object that implements Runnable
can implement the IExitCodeGenerator
interface to generate an exit code. For example:
@Command(name = "wave")
class Gesture implements Runnable, IExitCodeGenerator {
public void run() {
System.out.println("wave");
}
public int getExitCode() {
return 3;
}
}
assert 3 == new CommandLine(new Gesture()).execute();
By default, the execute
method returns CommandLine.ExitCode.USAGE
(64
) for invalid input, and CommandLine.ExitCode.SOFTWARE
(70
) when an exception occurred in the Runnable, Callable or command method. (For reference, these values are EX_USAGE
and EX_SOFTWARE
, respectively, from Unix and Linux sysexits.h). This can be customized with the @Command
annotation. For example:
@Command(exitCodeOnInvalidInput = 123,
exitCodeOnExecutionException = 456)
Additionally, applications can configure a IExitCodeExceptionMapper
to map a specific exception to an exit code:
class MyMapper implements IExitCodeExceptionMapper {
public int getExitCode(Throwable t) {
if (t instance of FileNotFoundException) {
return 74;
}
return 1;
}
}
When the end user specified invalid input, the execute
method prints an error message followed by the usage help message of the command, and returns an exit code. This can be customized by configuring a IParameterExceptionHandler
.
If the business logic of the command throws an exception, the execute
method prints the stack trace of the exception and returns an exit code. This can be customized by configuring a IExecutionExceptionHandler
.
The new CommandLine.execute
method is an instance method. The older run
, call
and invoke
methods are static methods. Static methods don’t allow configuration. The new API lets applications configure the parser or other aspects before execution. For example:
public static void main(String... args) {
CommandLine cmd = new CommandLine(new App());
cmd.setCaseInsensitiveEnumValuesAllowed(true);
cmd.setUnmarchedArgumentsAllowed(true);
cmd.setStopAtPositional(true);
cmd.setExpandAtFiles(false);
cmd.execute(args);
}
The following configuration methods are new and are only applicable with the execute
method (and executeHelpRequest
):
-
get/setOut
-
get/setErr
-
get/setColorScheme
-
get/setExecutionStrategy
-
get/setParameterExceptionHandler
-
get/setExecutionExceptionHandler
-
get/setExitCodeExceptionMapper
The above methods are not applicable (and ignored) with other entry points like parse
, parseArgs
, populateCommand
, run
, call
, invoke
, parseWithHandler
and parseWithHandlers
.
Previous versions of picocli offered the run
, call
and invoke
methods to execute a Runnable
, Callable
or Method
command. Here are some trade-offs versus the new execute
method:
-
Static - These are static methods, with the drawback that they don’t allow configuration, as mentioned above.
-
Type Safety - It is a compile-time error when an application tries to pass anything else than a
Runnable
to therun
method, and aCallable
to thecall
method. Theexecute
method does not have this type safety, since theCommandLine
constructor allows anyObject
as a parameter. -
Return Value - The
call
andinvoke
static methods allow commands to return any value, while theexecute
method only returns anint
exit code. From 4.0 the result object will be available from theCommandLine.getExecutionResult
method.
-
Any objections to deprecating the
run
,call
,invoke
, andparseWithHandlers
methods and associated classes and interfaces? -
With the new execute API the ColorScheme class will start to play a more central role. I’m considering making the ColorScheme class immutable. This would be a breaking API change. Should it be deprecated first, or not changed at all, or is the upcoming 4.0 release a good time to make breaking changes? Your feedback is very welcome on https://github.com/remkop/picocli/issues/675.