question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to trigger system exit with a given return code and Feature request

See original GitHub issue

Dear,

Firstly, thanks for your awesome library.

I would like to follow as much as possible standard return type on *NIX . Thus I defined some constants (see below ) and use picocli through a Runnable class .

In order to capture exception throw by picocli I invoke CommandLine.populateCommand method followed by App.run . And inside the run method I can do some checks on both options and parameters and return an error code if it is needed.

But I fail to catch MissingParameterException and seem to be consumed by CommandLine::handleParseException and CommandLine::internalHandleParseException

So what is the recommended way to capture all errors events in order to exit with the proper system exit code ?

Any improvement of the current library in order to ease custom/standard status code usage is welcome.

@CommandLine.Command(name = "Foo")
public final class App implements Runnable {

    @CommandLine.Option(names = {"-v", "--verbose"}, description = "Turn-on informative messages. " +
                                                                   "Multiple -v options increase the verbosity.")
    private boolean[] verbose = new boolean[0];

    @CommandLine.Parameters(index = "0", paramLabel = "Input", description = "Input to load.")
    private File input;

    @CommandLine.Parameters(index = "1", paramLabel = "LOG DIR", description = "Directory to store log files.")
    private File logDir;

    public static void exit(final int status) {
        new Thread("App-exit") {
            @Override
            public void run() {
                System.exit(status);
            }
        }.start();
    }
    public static void main(final String[] args) {
        // Configure the number of columns used for the help message
        int width = Integer.parseInt(System.getProperty("picocli.usage.width", String.valueOf(DEFAULT_USAGE_WIDTH)));
        System.setProperty("picocli.usage.width", String.valueOf(width));

        try {
            final App app = CommandLine.populateCommand(new App(), args);
            app.run();
        }
        catch (CommandLine.MissingParameterException e){
            System.err.printf("Error missing parameter: %s%n%n", e.getMessage());
            CommandLine.usage(new App(), System.err);
            exit(SysExit.USAGE);
        }
        catch (CommandLine.ParameterException e){
            System.err.printf("Error: %s%n%n", e.getMessage());
            CommandLine.usage(new App(), System.err);
            exit(SysExit.USAGE);
        }
        catch (Exception e){
            System.err.printf("Unknown Error: %s%n%n", e.getMessage());
            CommandLine.usage(new App(), System.err);
            exit(SysExit.USAGE);
        }

    }


    @Override
    public void run() {

        if (!model.exists()) {
            System.err.printf("The file " + input+ " do not exists!%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.IO_ERROR);
        } else if (!model.isFile()) {
            System.err.printf("The item " + input+ " is not a file!%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.USAGE);
        }
        else if( model == null ) {
            System.err.printf("Missing required parameter: INPUT%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.USAGE);
        }

        if (!logDir.exists()) {
            System.err.printf("The directory " + logDir + " do not exists!%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.IO_ERROR);
        } else if (!logDir.isDirectory()) {
            System.err.printf("The item " + logDir + " is not a directory!%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.USAGE);
        }
        else if( logDir == null ) {
            System.err.printf("Missing required parameter: LOG DIR!%n%n");
            new CommandLine(this).usage(System.err);
            exit(SysExit.USAGE);
        }

        final Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        switch (verbose.length) {
            case 0:
                root.setLevel(Level.OFF);
            case 1:
                root.setLevel(Level.INFO);
            case 2:
                root.setLevel(Level.WARN);
            case 3:
                root.setLevel(Level.DEBUG);
            default:
                root.setLevel(Level.DEBUG);
        }
    }
}

// FROM /usr/include/sysexits.h
public final class SysExit {
    public static final int OK = 0;
    public static final int GENERIC_ERROR = 1;
    public static final int BASE = 64;
    public static final int USAGE = 64;
    public static final int NO_DATA = 65;
    public static final int NO_INPUT = 66;
    public static final int NO_USER = 67;
    public static final int NO_HOST = 68;
    public static final int UNAVAILLABLE = 69;
    public static final int SOFTWARE = 70;
    public static final int OS_ERROR = 71;
    public static final int OS_FILE = 72;
    public static final int CAN_NOT_CREATE = 73;
    public static final int IO_ERROR = 74;
    public static final int TEMP_FAIL = 75;
    public static final int PROTOCOL = 76;
    public static final int NO_PERM = 77;
    public static final int CONFIG = 78;
}

Thanks for your insight

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:14 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
remkopcommented, Jul 27, 2018

@gerardbosch Would you mind creating a new ticket?

1reaction
remkopcommented, Jul 27, 2018

Yes I’m also not 100% happy about exit code handling as it stands. I don’t have a good answer on how to fix it yet, need to think about this more.

Read more comments on GitHub >

github_iconTop Results From Across the Web

A Guide to System.exit() - Baeldung
In this tutorial, we'll have a look at what System.exit means in Java. We'll see its purposes, where to use and how to...
Read more >
System.exit() in Java - CodeGym
The exit() method takes an integer as an argument and returns nothing. So you will call the exit method as System.exit(i) where i...
Read more >
How Python SystemExit Work with Examples - eduCBA
This sys. exit() function takes an argument (integer recommended) which gives exit status and zero or none is considered as successful termination of...
Read more >
Why does Java compiler refuse to recognize System.exit() as ...
Java's compiler, at least the one from Oracle that I use, refuses to recognize System.exit() as a procedure termination. Yes, it would.
Read more >
Stopping a service should handle System.exit(0) gracefully
If that's true, then I think this a bug, or at least a feature request... It seems to me that any exit code...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found