#include <sys/ioctl.h>
#include <sstream>
#include <fcntl.h>
+#include <algorithm>
+#include <stdio.h>
namespace APT {
namespace Progress {
-bool PackageManager::StatusChanged(std::string PackageName,
+
+/* Return a APT::Progress::PackageManager based on the global
+ * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)
+ */
+PackageManager* PackageManagerProgressFactory()
+{
+ // select the right progress
+ int status_fd = _config->FindI("APT::Status-Fd", -1);
+ int status_deb822_fd = _config->FindI("APT::Status-deb822-Fd", -1);
+
+ APT::Progress::PackageManager *progress = NULL;
+ if (status_deb822_fd > 0)
+ progress = new APT::Progress::PackageManagerProgressDeb822Fd(
+ status_deb822_fd);
+ else if (status_fd > 0)
+ progress = new APT::Progress::PackageManagerProgressFd(status_fd);
+ else if(_config->FindB("Dpkg::Progress-Fancy", false) == true)
+ progress = new APT::Progress::PackageManagerFancy();
+ else if (_config->FindB("Dpkg::Progress",
+ _config->FindB("DpkgPM::Progress", false)) == true)
+ progress = new APT::Progress::PackageManagerText();
+ else
+ progress = new APT::Progress::PackageManager();
+ return progress;
+}
+
+bool PackageManager::StatusChanged(std::string /*PackageName*/,
unsigned int StepsDone,
unsigned int TotalSteps,
- std::string HumanReadableAction)
+ std::string /*HumanReadableAction*/)
{
int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1);
percentage = StepsDone/(float)TotalSteps * 100.0;
FileFd::Write(OutStatusFd, s.c_str(), s.size());
}
-void PackageManagerProgressFd::Start()
+void PackageManagerProgressFd::StartDpkg()
{
if(OutStatusFd <= 0)
return;
void PackageManagerProgressFd::Stop()
{
- // clear the Keep-Fd again
- _config->Clear("APT::Keep-Fds", OutStatusFd);
}
void PackageManagerProgressFd::Error(std::string PackageName,
FileFd::Write(OutStatusFd, s.c_str(), s.size());
}
-void PackageManagerProgressDeb822Fd::Start()
+void PackageManagerProgressDeb822Fd::StartDpkg()
{
// FIXME: use SetCloseExec here once it taught about throwing
// exceptions instead of doing _exit(100) on failure
void PackageManagerProgressDeb822Fd::Stop()
{
- // clear the Keep-Fd again
- _config->Clear("APT::Keep-Fds", OutStatusFd);
}
void PackageManagerProgressDeb822Fd::Error(std::string PackageName,
}
+PackageManagerFancy::PackageManagerFancy()
+ : child_pty(-1)
+{
+ // setup terminal size
+ old_SIGWINCH = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
+ instances.push_back(this);
+}
+std::vector<PackageManagerFancy*> PackageManagerFancy::instances;
+
+PackageManagerFancy::~PackageManagerFancy()
+{
+ instances.erase(find(instances.begin(), instances.end(), this));
+ signal(SIGWINCH, old_SIGWINCH);
+}
+
+void PackageManagerFancy::staticSIGWINCH(int signum)
+{
+ std::vector<PackageManagerFancy *>::const_iterator I;
+ for(I = instances.begin(); I != instances.end(); ++I)
+ (*I)->HandleSIGWINCH(signum);
+}
+
+int PackageManagerFancy::GetNumberTerminalRows()
+{
+ struct winsize win;
+ // FIXME: get from "child_pty" instead?
+ if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) != 0)
+ return -1;
+
+ if(_config->FindB("Debug::InstallProgress::Fancy", false) == true)
+ std::cerr << "GetNumberTerminalRows: " << win.ws_row << std::endl;
+
+ return win.ws_row;
+}
+
void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
{
+ if(_config->FindB("Debug::InstallProgress::Fancy", false) == true)
+ std::cerr << "SetupTerminalScrollArea: " << nr_rows << std::endl;
+
// scroll down a bit to avoid visual glitch when the screen
// area shrinks by one row
std::cout << "\n";
std::cout << "\033[s";
// set scroll region (this will place the cursor in the top left)
- std::cout << "\033[1;" << nr_rows - 1 << "r";
+ std::cout << "\033[0;" << 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;
+ // ensure its flushed
std::flush(std::cout);
+
+ // setup tty size to ensure xterm/linux console are working properly too
+ // see bug #731738
+ struct winsize win;
+ ioctl(child_pty, TIOCGWINSZ, (char *)&win);
+ win.ws_row = nr_rows - 1;
+ ioctl(child_pty, TIOCSWINSZ, (char *)&win);
}
-PackageManagerFancy::PackageManagerFancy()
- : nr_terminal_rows(-1)
+void PackageManagerFancy::HandleSIGWINCH(int)
{
- struct winsize win;
- if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) == 0)
- {
- nr_terminal_rows = win.ws_row;
- }
+ int nr_terminal_rows = GetNumberTerminalRows();
+ SetupTerminalScrollArea(nr_terminal_rows);
}
-void PackageManagerFancy::Start()
+void PackageManagerFancy::Start(int a_child_pty)
{
+ child_pty = a_child_pty;
+ int nr_terminal_rows = GetNumberTerminalRows();
if (nr_terminal_rows > 0)
SetupTerminalScrollArea(nr_terminal_rows);
}
void PackageManagerFancy::Stop()
{
+ int nr_terminal_rows = GetNumberTerminalRows();
if (nr_terminal_rows > 0)
{
SetupTerminalScrollArea(nr_terminal_rows + 1);
static const char* clear_screen_below_cursor = "\033[J";
std::cout << clear_screen_below_cursor;
}
+ child_pty = -1;
}
bool PackageManagerFancy::StatusChanged(std::string PackageName,
HumanReadableAction))
return false;
- int row = nr_terminal_rows;
+ int row = GetNumberTerminalRows();
static string save_cursor = "\033[s";
static string restore_cursor = "\033[u";
-}; // namespace progress
-}; // namespace apt
+} // namespace progress
+} // namespace apt