summaryrefslogtreecommitdiff
path: root/apt-pkg/deb/dpkgpm.cc
diff options
context:
space:
mode:
authorMichael Vogt <mvo@debian.org>2013-10-07 10:26:50 +0200
committerMichael Vogt <mvo@debian.org>2013-10-07 10:26:50 +0200
commitaf6b41692b21a7fd1561d9ad4b3e4407ab93246f (patch)
tree8e5796867337d6fed796d352ddf8cdcc8b8dc6d9 /apt-pkg/deb/dpkgpm.cc
parent75cd2506ce7ea411f7a0e888310d622ad330828c (diff)
add -o DpkgPM::Progress-Fancy for better dpkg progress output on vt100+ terminals
Diffstat (limited to 'apt-pkg/deb/dpkgpm.cc')
-rw-r--r--apt-pkg/deb/dpkgpm.cc88
1 files changed, 79 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"));