Skip to content

execute() does not flush out/err PrintWriters after command execution #2514

Description

@hashhar

CommandLine.execute() never flushes the out and err PrintWriter instances after a command's Callable.call() (or Runnable.run()) completes. This means output written via print() can be silently lost.

newPrintWriter() creates writers with autoFlush=true.
However it seems autoFlush only triggers on println(), printf(), and format(). Since execute() has no finally block that flushes the writers any data written via print() is lost when the JVM exits.

To reproduce:

@Command(name = "demo")
public class Demo implements Callable<Integer> {
    @Spec CommandSpec spec;

    @Override
    public Integer call() {
        spec.commandLine().getOut().print("hello"); // never appears
        return 0;
    }

    public static void main(String[] args) {
        System.exit(new CommandLine(new Demo()).execute(args));
    }
}

Running produces no output. Changing print to println makes it work and adding an explicit flush() also works.

Expected behavior:

execute() should flush both getOut() and getErr() after command execution, similar to how handleUnhandled() already flushes getErr().

Proposed fix:

Add a finally block which flushes in execute?

Workaround that I applied on my end for now

CommandLine cmd = new CommandLine(new Demo());
CommandLine.IExecutionStrategy delegate = cmd.getExecutionStrategy();
cmd.setExecutionStrategy(parseResult -> {
    try {
        return delegate.execute(parseResult);
    } finally {
        parseResult.commandSpec().commandLine().getOut().flush();
        parseResult.commandSpec().commandLine().getErr().flush();
    }
});

I'm using 4.7.7 which I think is the latest, right?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions