picocli
picocli copied to clipboard
Avoid calling `stty` when ANSICON is set
This is a follow-up ticket for #1103 based on @dwalluck's suggestion.
When running the picocli tests on Cygwin/ConEmu, the following output is generated:
stty: /dev/tty: No such device or address
stty: /dev/tty: No such device or address
stty: /dev/tty: No such device or address
...
Picocli internally calls stty -a -F /dev/tty
in a separate process when the usageHelpAutoWidth=true
to determine the window width. In a non-interactive session, that may result in the above output. The problem is, that from Java, the only way to detect whether the process is connected to a terminal is to see if System.console()
returns null
, and since Cygwin and MSYS use a pseudo-tty, the console is always null
in these environments...
@dwalluck pointed out that
At least under ConEmu, it will set the environment variable
ANSICON = "WxH (wxh)
, whereW,H
is the size of the buffer, andw,h
is the size of the window.
Example ANSICON
value: 80x1000 (80x25)
. (See also the Ansicon Manual.)
One idea to avoid the "No such device or address" output is to get the terminal window width from the ANSICON
value if available instead of unconditionally calling stty -a -F /dev/tty
.
There is also some information here https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable. It looks like this is only set if you have ANSI codes enabled?
Started to happen on JDK 22-ea in JUnit's integration tests: https://github.com/junit-team/junit5/issues/3419
Underlying change in JDK 22-ea+8 is:
Build 8 JLine As The Default Console Provider (JDK-8308591) System.console() has changed in this release to return a Console with enhanced editing features that improve the experience of programs that use the Console API. In addition, System.console() now returns a Console object when the standard streams are redirected or connected to a virtual terminal. In prior releases, System.console() returned null for these cases. This change may impact code that uses the return from System.console() to test if the VM is connected to a terminal. If needed, running with -Djdk.console=java.base will restore older behavior where the console is only returned when it is connected to a terminal.
A new method
Console.isTerminal()
has been added to test if console is connected to a terminal.
Could this new method help to decide whether to unconditionally call stty -a -F /dev/tty
?
I created https://github.com/sormuras/JDK-8313893 to reproduce this issue.
Seems like Picocli 4.7.x (used in JUnit 5.9 and higher) introduced the stty -a -F /dev/tty
call. Picocli 4.6.x (used in JUnit 5.8) doesn't emit that line - even on Java 22-ea.
@sormuras Would #2083 and #2084 fix this issue?
Yes, I think so.
FWIW, I tried usageHelpAutoWidth = false
via https://github.com/junit-team/junit5/pull/3423 and as expected the stty: /dev/tty: No such device or address
is no longer emitted. The appearance of a NullPointerException
might or might not be related.