From af6b41692b21a7fd1561d9ad4b3e4407ab93246f Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 7 Oct 2013 10:26:50 +0200 Subject: add -o DpkgPM::Progress-Fancy for better dpkg progress output on vt100+ terminals --- apt-pkg/deb/dpkgpm.cc | 88 +++++++++++++++++++++++++++++++++++++++++++++------ apt-pkg/deb/dpkgpm.h | 2 ++ 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index a5097a04f..4eb373fb7 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -54,9 +54,15 @@ class pkgDPkgPMPrivate public: pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0), term_out(NULL), history_out(NULL), - last_reported_progress(0.0) + last_reported_progress(0.0), nr_terminal_rows(0), + fancy_progress_output(false) { dpkgbuf[0] = '\0'; + if(_config->FindB("DpkgPM::Progress-Fancy", false)) + { + fancy_progress_output = true; + _config->Set("DpkgPM::Progress", true); + } } bool stdin_is_dev_null; // the buffer we use for the dpkg status-fd reading @@ -67,6 +73,8 @@ public: string dpkg_error; float last_reported_progress; + int nr_terminal_rows; + bool fancy_progress_output; }; namespace @@ -892,10 +900,37 @@ void pkgDPkgPM::SendTerminalProgress(float percentage) if(percentage < (d->last_reported_progress + reporting_steps)) return; - // FIXME: use colors too - std::cout << "\r\n" - << "Progress: [" << std::setw(3) << int(percentage) << "%]" - << "\r\n"; + std::string progress_str; + strprintf(progress_str, "Progress: [%3i%%]", (int)percentage); + if (d->fancy_progress_output) + { + int row = d->nr_terminal_rows; + + static string save_cursor = "\033[s"; + static string restore_cursor = "\033[u"; + + static string set_bg_color = "\033[42m"; // green + static string set_fg_color = "\033[30m"; // black + + static string restore_bg = "\033[49m"; + static string restore_fg = "\033[39m"; + + std::cout << save_cursor + // move cursor position to last row + << "\033[" << row << ";0f" + << set_bg_color + << set_fg_color + << progress_str + << restore_cursor + << restore_bg + << restore_fg; + } + else + { + std::cout << progress_str << "\r\n"; + } + std::flush(std::cout); + d->last_reported_progress = percentage; } /*}}}*/ @@ -920,6 +955,29 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds, return retval; } /*}}}*/ + +void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows) +{ + if(!d->fancy_progress_output) + return; + + // scroll down a bit to avoid visual glitch when the screen + // area shrinks by one row + std::cout << "\n\n"; + + // save cursor + std::cout << "\033[s"; + + // set scroll region (this will place the cursor in the top left) + std::cout << "\033[1;" << nr_rows - 1 << "r"; + + // restore cursor but ensure its inside the scrolling area + std::cout << "\033[u"; + static const char *move_cursor_up = "\033[1A"; + std::cout << move_cursor_up; + std::flush(std::cout); +} + // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- /* This globs the operations and calls dpkg @@ -1276,7 +1334,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) _error->PushToStack(); if (tcgetattr(STDOUT_FILENO, &tt) == 0) { - ioctl(0, TIOCGWINSZ, (char *)&win); + ioctl(1, TIOCGWINSZ, (char *)&win); + d->nr_terminal_rows = win.ws_row; if (openpty(&master, &slave, NULL, &tt, &win) < 0) { _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?")); @@ -1318,11 +1377,12 @@ bool pkgDPkgPM::Go(int OutStatusFd) << endl; FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); } + Child = ExecFork(); - // This is the child if (Child == 0) { + if(slave >= 0 && master >= 0) { setsid(); @@ -1339,7 +1399,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); - + if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO)) { int Flags,dummy; @@ -1355,6 +1415,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) _exit(100); } + SetupTerminalScrollArea(d->nr_terminal_rows); /* No Job Control Stop Env is a magic dpkg var that prevents it from using sigstop */ @@ -1449,6 +1510,15 @@ bool pkgDPkgPM::Go(int OutStatusFd) signal(SIGHUP,old_SIGHUP); + // reset scroll area + SetupTerminalScrollArea(d->nr_terminal_rows); + if(d->fancy_progress_output) + { + // override the progress line (sledgehammer) + static const char* clear_screen_below_cursor = "\033[J"; + std::cout << clear_screen_below_cursor; + } + if(master >= 0) { tcsetattr(0, TCSAFLUSH, &tt); @@ -1488,7 +1558,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) // dpkg is done at this point if(_config->FindB("DPkgPM::Progress", false) == true) SendTerminalProgress(100); - + if (pkgPackageManager::SigINTStop) _error->Warning(_("Operation was interrupted before it could finish")); diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index 29901a204..3b8d36623 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -84,6 +84,8 @@ class pkgDPkgPM : public pkgPackageManager bool SendPkgsInfo(FILE * const F, unsigned int const &Version); void WriteHistoryTag(std::string const &tag, std::string value); + // Terminal progress + void SetupTerminalScrollArea(int nr_scrolled_rows); void SendTerminalProgress(float percentage); // apport integration -- cgit v1.2.3 From 1c6089d72ddf59875fae4f281f023abba0d4fda0 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 7 Oct 2013 13:37:28 +0200 Subject: use Dpkg::Progress-Fancy to be consitent with Dpkg::Progress --- apt-pkg/deb/dpkgpm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 4eb373fb7..a116db9cf 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -58,7 +58,7 @@ public: fancy_progress_output(false) { dpkgbuf[0] = '\0'; - if(_config->FindB("DpkgPM::Progress-Fancy", false)) + if(_config->FindB("Dpkg::Progress-Fancy", false) == true) { fancy_progress_output = true; _config->Set("DpkgPM::Progress", true); -- cgit v1.2.3 From 28e3b6f6f822a640aec35a41d5e99a97cfa1e9b1 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 7 Oct 2013 13:46:30 +0200 Subject: fix off-by-one error in pkgDPkgPM::SetupTerminalScrollArea() --- apt-pkg/deb/dpkgpm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index a116db9cf..7d8c9b4e0 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -963,7 +963,7 @@ void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows) // scroll down a bit to avoid visual glitch when the screen // area shrinks by one row - std::cout << "\n\n"; + std::cout << "\n"; // save cursor std::cout << "\033[s"; -- cgit v1.2.3