-
Notifications
You must be signed in to change notification settings - Fork 15
progress: detect real terminal width for messages #316
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
base: main
Are you sure you want to change the base?
Conversation
This will need some (manual) testing and verification since we run in many different places where there might, or might not be any terminal attached; or the terminal might misreport its width, etc. Thank you for splitting this off ❤️. |
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.
Seems to work ok running it locally. But I also don't see anything wrong, so I'm mostly saying it didn't obviously break things :)
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.
Thank you! This looks nice, some idea inline for your consideration but I think we could merge as is (but I think its worth thinking about the inline comments)
// newlines with spaces. If the string is longer than length, it appends | ||
// a unicode ellipsis character. If length is 0, it returns the unmodified | ||
// string. | ||
func ShortenString(msg string, length int) string { |
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.
(nitpick) I'm not sure we should move it out, the side-effect of \n->" " for a general util is a bit weird.
If we move it out, maybe into strutil
to not have a kitchen-sink util
? I think you mention that you generally preferred it this way in another PR. And maybe strutil.ShortenAndNormalize()
or something (this one is a bit long) to indicate that there is this other side-effect
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.
I am a bit thorn on this one, so I am going for a hybrid approach.
- Modified the utility function to be generic, no
\n
replacement. - Added a tiny function in
progress.go
which utilizes this function plus replaces newlines.
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.
No appetite for strutil
:) ? Its fine, just wondering.
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.
If you do not like it in util
i can move it back to progress
. I do not like util
or XXXutil
at all, package name should represent what it does. In this case I would consider strings
if you ask me.
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.
Its fine as is, thanks for the tweaks about the \n
Locally everything works, so not sure what is wrong on the CI/CD. So I am trying out something crazy. I updated the progress integration test to use |
f79b8f5
to
d8006e7
Compare
Using asciicinema runs a small risk of it setting up a pty and the error disappearing. It is possible that in CI (and other cases) that there's no controlling pty at all (in normal cases) and maybe no tty on the receiving end either. What was the exact error you were seeing? |
It was this job: https://github.com/osbuild/image-builder-cli/actions/runs/17951169988/job/51050562633 |
Ha I wonder if So you do not like asciinama then? Since terminal size cannot be set via podman, it actually turns useful now. |
It's not really about |
But that is the goal, podman does not allow too much configuration of pty. Asciinema allows setting the size, other than that it does not change anything. I do not see any problem here, explain please. Here is the recording which I downloaded from the latest (successful) run: |
This code should work in environments where there isn't a size (or that don't report a size) right? It can fall back to non-fancy ( |
Absolutely, I can extend the test and add with and without cases so both are tested in non-tty non-interactive environments. In fact, not only |
pkg/progress/progress.go
Outdated
return msg[:60] + "..." | ||
func getTerminalWidth() int { | ||
width, _, err := term.GetSize(int(os.Stdout.Fd())) | ||
if err != nil { |
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.
It might be safer to assume that the terminal is in fact broken if it's not responding correctly to TIOCGWINSZ
and instead downgrade to a non-interactive terminal. That's not really something we can do when we get to this point of the code so:
If progress is set to auto we currently only check if isatty returns true on the fd; we should probably call GetSize there as well to see if that terminal is behaving correctly.
pkg/progress/progress.go
Outdated
} | ||
|
||
func shortenString(msg string) string { | ||
width := getTerminalWidth() |
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.
Note that doing this repeatedly can cause bogus reads; some terminals can return weird values during resizing (very large, very small). It might be better to keep some state and listen to SIGWINCH
instead though that can also be racy I guess.
Feel free to ignore this one since we always erase the entire line and don't do any moves relative to the line length or such so it's unlikely to cause us any issues.
I put some small comments from my experiences of doing things with terminals, I need to do a deeper look and rack my brain for other issues (I distinctly remember cases where nested pty's are used from another project). Note that these things are all very 'maybe' and very environment dependent. I'm just slightly worried that suddenly It might be good to be a bit defensive and then I'm happy enough to merge since I'm probably being a bit too difficult on this. |
You are presenting great points, don't worry. I drafted everything you mentioned, the process now listens to the UNIX signal and updates w/h accordingly. I should probably move this into the Progress instance and introduce some proper Moreover, the initial check in Also I found a bug in tests - those mocked functions had |
@lzap Could you fix the conflict here, I'm about ready to ack it but otherwise I have to do it a few times. |
There is a common pattern in the progress bar code to shorten strings to fit into terminal width. This commit introduces a new utility function for that. It also introduces a fallback terminal width of 80 columns in case the terminal size cannot be determined. Added a test for the function and made sure it never returns string longer than the specified length. That was not the case for the previous implementation. Additionally, the progress bar implementation was updated to dynamically detect the terminal width and adjust message lengths accordingly. This ensures that progress messages are fully visible without being truncated, enhancing user experience during long-running operations. There is few characters left for the spinner and padding, so we subtract 10 from the terminal width when setting message lengths. A new dependency was introduced, but it was already an indirect one. Testing is difficult, so this change also adds asciinema recordings of the progress bar in action. The recordings are uploaded as artifacts of the CI run. The test verifies that the expected progress messages are present in the output.
Of course, thanks for the heads-up. Rebased. |
output = subprocess.check_output(podman_run + [ | ||
"-t", | ||
|
||
podman_command = [ podman_run + |
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.
Needs to be podman_run + [
instead of [ podman_run +
.
One comment (introduced by the rebase) and linters need appeasement. |
There is a common pattern in the progress bar code to shorten strings to fit into terminal width. This commit introduces a new utility function for that. It also introduces a fallback terminal width of 80 columns in case the terminal size cannot be determined.
Added a test for the function and made sure it never returns string longer than the specified length. That was not the case for the previous implementation.
Additionally, the progress bar implementation was updated to dynamically detect the terminal width and adjust message lengths accordingly. This ensures that progress messages are fully visible without being truncated, enhancing user experience during long-running operations.
There is few characters left for the spinner and padding, so we subtract 10 from the terminal width when setting message lengths.
A new dependency was introduced, but it was already an indirect one.
Also, turns out the container test does not actually run with any terminal size variables, so I added a fixed terminal size to the podman run command.
Split out of: #303