-
Notifications
You must be signed in to change notification settings - Fork 447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds property for jline to prefer using stdout vs stderr #5221
base: 2.1
Are you sure you want to change the base?
Conversation
When the shell is being used with a `-e <command>` option jline does not write the output on stdout when also used with a pipe `|` operator. Instead the output is written to stderr. This causes frustration when attempting to script actions using the accumulo shell.
@ctubbsii While testing this I also found that the issue could be fixed by setting the accumulo/shell/src/main/java/org/apache/accumulo/shell/Shell.java Lines 301 to 304 in 4eff735
Jline's documentation states that the default is the system output stream so it's interested that explicitly setting it fixes the issue. |
I did see #3446 which was originally fixed in jline 3.24.0. The property I found was added in jline 3.22.0 so it's not super recent (Jan 2023). |
Good find. |
This seems like a sensible solution (though I'm not sure I understand why we should disable jansi). However, looking at the code, it looks like you should call I'm pretty sure that before we upgraded jline, we did explicitly set System.in and System.out when constructing the terminal. Perhaps that got lost in the upgrade?
Tracing through the code, it looks like the default isn't actually I tested by giving it a pseudo tty. This works, and sends it to stdout so I can grep: socat - EXEC:'accumulo shell -e tables\\ -np',pty,setsid,ctty | grep meta However, neither a pipe nor a redirection works without simulating a tty. So, neither of these work: accumulo shell -e tables | grep meta
accumulo shell -e tables > tables.txt I added ACCUMULO_JAVA_OPTS=-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager accumulo shell -e tables This gave some useful output about which terminal provider it was loading and which pty implementation it was using (skipping the stack traces for the providers which couldn't be loaded). It seems to be loading both the
I believe the problem is that the You can verify this by redirecting both streams to separate files. When you do that, it is unable to construct a terminal using any output stream, and instead falls back to the DumbTerminal. I think ultimately, the problem is the logic at https://github.com/jline/jline3/blob/c75301facc8716b59c1d57d3e3c5943358022560/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java#L407-L410 This logic sets the system stream based on whether the provider says any of the passed streams are considered system streams. But for the JniTerminalProvider, it's only considered a "system stream" if the stream is a tty, which is false for the stdout, but true for stderr, so JniTerminalProvider ends up being the selected provider using the stderr, which is still a tty. What it should do instead, it should only use that provider if all of the provided streams are considered system streams (but I think that reverts the intent of jline/jline3#787, so there may be a philosophical disagreement with upstream devs on what the correct behavior should be when one stream is a tty and the other is not). Otherwise, it should use the DumbTerminalProvider with the system stream. I'm not sure if this worked at all after #3446. I think the original behavior that was implemented in jline/jline3#787 to use the terminal with stderr only still exists after jline/jline3#854, which I don't think fixed the issue. Or, if it did, a subsequent change broke it again. jline/jline3#854 only changed which output stream was used for the DumbTerminal, but the bug we're now seeing is that the DumbTerminal isn't being selected... the JniTerminal is being selected but with only stderr since stdout is not a tty. I think this issue needs to be raised again upstream. In the meantime, I think setting the stream directly to stdout will be the right fix for Accumulo. The property can be mentioned to users who need a workaround in the meantime, but I don't think our code should rely on that property being set in the config for shell redirection to work correctly. What I'd be curious to know, though, is whether pagination is attempted after setting the system output stream correctly. I noticed while testing, when I gave a pseudo tty, if I didn't specify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer the code change, so the fix isn't dependent on user config. The property is a helpful workaround to document for users in the meantime, though.
Change the output behavior manually instead of using the jline properties.
5946bd7
to
5c86af4
Compare
When the shell is being used with an execute command and pipe
./accumulo shell -e '<command>' | grep "<>"
,jline does not write the output on stdout and instead writes it to stderr.
This causes frustration when attempting to script actions using the accumulo shell.
Without Property Set:
With Property Set:
What made this odd was that the shell writes to stdout if not using a pipe
|
as redirecting the output to a file works/accumulo shell -e '<command>' > output.txt
Related Jline Code:
https://github.com/jline/jline3/blob/c75301facc8716b59c1d57d3e3c5943358022560/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java#L541
https://github.com/jline/jline3/blob/c75301facc8716b59c1d57d3e3c5943358022560/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java#L588