picocli icon indicating copy to clipboard operation
picocli copied to clipboard

Avoid calling `stty` when ANSICON is set

Open remkop opened this issue 4 years ago • 5 comments

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), where W,H is the size of the buffer, and w,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.

remkop avatar Jun 08 '20 03:06 remkop

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?

dwalluck avatar Jun 08 '20 03:06 dwalluck

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?

sormuras avatar Aug 10 '23 09:08 sormuras

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 avatar Aug 11 '23 08:08 sormuras

@sormuras Would #2083 and #2084 fix this issue?

remkop avatar Aug 11 '23 12:08 remkop

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.

sormuras avatar Aug 11 '23 15:08 sormuras