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
Progress indicator improvements #4296
base: master
Are you sure you want to change the base?
Conversation
cef088c
to
cbab288
Compare
Does this preserve color of log messages? Can we customize the colors and used characters? |
If you mean color in build output, then yes (example). There is no customization yet. |
return stats; | ||
} | ||
|
||
enum StatusLineGroup { |
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.
Wouldn't it make sense to use a enum class
here for some "free" type-safety?
I hope this can take some more inspiration from https://github.com/maralorn/nix-output-monitor. I particularly like the list of packages that are currently being built and on which machines that happens. |
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.
Just did a quick read through some of the code and had a few remarks. I really like the prospect of having this (or something like it) in Nix. Having a better progress indicator for what Nix is doing is great. 👍
if (errno == EINTR) continue; | ||
break; | ||
} | ||
c = std::tolower(c); |
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.
std::tolower
is locale aware and at least cpp ref says "To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char".
} | ||
c = std::tolower(c); | ||
|
||
if (c == 3 || c == 4 || c == 'q') { |
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.
Nit: for readability we could use some constant for ETX/EOT or add a comment here?
|
||
inputPipe.create(); | ||
|
||
inputThread = std::thread([this]() { |
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.
This whole function has become quite a beast. Would it make sense to move it into a function instead?
} | ||
} | ||
|
||
if (c == 'l') { |
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.
These c == 'x'
switches should probably have an explicit else if
for all the other cases. That makes it explicit that only one of them will be active at a time. Making reading this code easier and more explicit. Another option would be a switch on c
.
bool isTTY; | ||
std::optional<struct termios> savedTermAttrs; | ||
|
||
Pipe inputPipe; |
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.
inputPipe
is only used to cancel the inputThread
. Is that right? It didn't occur to me in the first passage of reading the thread that was the intend of it. It is a bit unfortunate to have the whole indirection through the pollfd.
@@ -184,8 +438,8 @@ class ProgressBar : public Logger | |||
auto sub = getS(fields, 1); | |||
i->s = fmt( | |||
hasPrefix(sub, "local") | |||
? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s" | |||
: "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", | |||
? ANSI_BOLD "%s" ANSI_NORMAL " from %s" |
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.
These two cases appear to be identical.
std::string s; | ||
|
||
for (size_t i = 1; i < state.prevStatusLines; ++i) | ||
s += "\r\e[K\e[A"; |
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.
What are these escape sequences? Maybe drop a comment what they are doing and why they are here.
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 was curious so I looked it up. Posting the answer in case anybody else wonders.
Anything of the form \e[A
is an ansi escape, that is interpreted by the terminal. It's the same kind that is used to output color. '\r' is a carriage return, which puts the cursor back at the beginning of the line.
All put together we have:
\r
return the cursor at the beginning of the line\e[K
erases the line from the cursor\e[A
moves the cursor one line up
So, for each line we had in the previous status line, we erase a full line and move the cursor up. Ie, we delete all we printed previously.
Looks interesting. Btw I tried this a bit and seems |
cbab288
to
9c02bdc
Compare
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/tweag-nix-dev-update-5/10560/1 |
Looks cool! One concern I've had with the new nix shell commands is how they work with a It would be nice if we detected dumb terminals and reverted to basic output. |
Fyi dumb terms are detected, but only by TERM it seems? E.g. Try running your nix commands with |
During a build you can hit 'L' to enable/disable printing of build logs, 'v' or '+' to increase verbosity, and '-' to decrease verbosity.
Using '-L' caused another call to setLogFormat(), which caused another ProgressBar to be created. But the ProgressBar should be a singleton. To do: remove LogFormat::barWithLogs. '-L' should be a setting of the ProgressBar, not a different log format.
This will make it easier to add more settings to the progress bar.
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/nixos-rebuild-progress-bar/31149/4 |
Triaged in the Nix team meeting
Will discuss further |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2023-08-18-nix-team-meeting-minutes-80/32081/1 |
Discussed in Nix team meeting:
Complete discussion
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2023-11-13-nix-team-meeting-minutes-103/35400/1 |
I very much appreciate any effort to improve nix command user interface, but I watched asciinema demo and think I like the output of nom (Nix output monitor) much more. Since very long time has passed since this PR was submitted, did you consider taking some experience from this tool ? |
@imincik Expand the detailed discussion in the meeting notes, this was discussed. In short, nom being written in Haskell makes this very tricky, but if somebody had the resources to rewrite it in C++ and PR it, that would change the game. |
Imo the default progress indicator should be simple (max 1-3 lines) and most importantly have a fixed output height so the output doesn't bounce around. This is a major usability issue with nom (example). It's fine to have a more advanced progress indicator, but please put it behind a flag (or toggle). Taking another shot at nom: it doesn't do the most basic thing a progress indicator should do, namely: show progress. |
@szlend I think your concern is a valid one that I believe can be solved with the appropriate configuration, on top of some sane defaults. With UI (especially TUI) you can never satisfy every user. I believe a similar point appears in the meeting notes. |
This replaces the current one-line progress bar with a progress indicator with the following features:
Interactive: you can hit the
L
key to enable display of build output,v
to increase verbosity,r
to show which paths are remaining to be built, etc.Multi-line: rather than cramming a lot of info into a single line, it has separate progress bars for substitutions, builds, etc.
More logging: separately from the progress indicator (which only shows transient info), we log to stderr how long successful builds / substitutions took.
More use of colors.