From 1c6cedc489b5eaeed1b7fdb845eca06bc1fccd4f Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 21 Oct 2013 21:23:07 +0200 Subject: move iprogress.{cc,h} to private-progress.{cc,h} until its fully stable --- apt-private/makefile | 2 +- apt-private/private-progress.cc | 221 ++++++++++++++++++++++++++++++++++++++++ apt-private/private-progress.h | 109 ++++++++++++++++++++ 3 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 apt-private/private-progress.cc create mode 100644 apt-private/private-progress.h (limited to 'apt-private') diff --git a/apt-private/makefile b/apt-private/makefile index 1d179f0b2..9b074f189 100644 --- a/apt-private/makefile +++ b/apt-private/makefile @@ -17,7 +17,7 @@ MAJOR=0.0 MINOR=0 SLIBS=$(PTHREADLIB) -lapt-pkg -PRIVATES=list install download output cachefile cacheset update upgrade cmndline moo search show main +PRIVATES=list install download output cachefile cacheset update upgrade cmndline moo search show main progress SOURCE += $(foreach private, $(PRIVATES), private-$(private).cc) HEADERS += $(foreach private, $(PRIVATES), private-$(private).h) diff --git a/apt-private/private-progress.cc b/apt-private/private-progress.cc new file mode 100644 index 000000000..daa7695e2 --- /dev/null +++ b/apt-private/private-progress.cc @@ -0,0 +1,221 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace APT { +namespace Progress { + +bool PackageManager::StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction) +{ + int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1); + percentage = StepsDone/(float)TotalSteps * 100.0; + strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage); + + if(percentage < (last_reported_progress + reporting_steps)) + return false; + + return true; +} + +PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd) + : StepsDone(0), StepsTotal(1) +{ + OutStatusFd = progress_fd; +} + +void PackageManagerProgressFd::WriteToStatusFd(std::string s) +{ + if(OutStatusFd <= 0) + return; + FileFd::Write(OutStatusFd, s.c_str(), s.size()); +} + +void PackageManagerProgressFd::Start() +{ + if(OutStatusFd <= 0) + return; + + // FIXME: use SetCloseExec here once it taught about throwing + // exceptions instead of doing _exit(100) on failure + fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC); + + // send status information that we are about to fork dpkg + std::ostringstream status; + status << "pmstatus:dpkg-exec:" + << (StepsDone/float(StepsTotal)*100.0) + << ":" << _("Running dpkg") + << std::endl; + WriteToStatusFd(status.str()); +} + +void PackageManagerProgressFd::Stop() +{ + // clear the Keep-Fd again + _config->Clear("APT::Keep-Fds", OutStatusFd); +} + +void PackageManagerProgressFd::Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage) +{ + std::ostringstream status; + status << "pmerror:" << PackageName + << ":" << (StepsDone/float(TotalSteps)*100.0) + << ":" << ErrorMessage + << std::endl; + WriteToStatusFd(status.str()); +} + +void PackageManagerProgressFd::ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage) +{ + std::ostringstream status; + status << "pmconffile:" << PackageName + << ":" << (StepsDone/float(TotalSteps)*100.0) + << ":" << ConfMessage + << std::endl; + WriteToStatusFd(status.str()); +} + + +bool PackageManagerProgressFd::StatusChanged(std::string PackageName, + unsigned int xStepsDone, + unsigned int xTotalSteps, + std::string pkg_action) +{ + StepsDone = xStepsDone; + StepsTotal = xTotalSteps; + + // build the status str + std::ostringstream status; + status << "pmstatus:" << StringSplit(PackageName, ":")[0] + << ":" << (StepsDone/float(StepsTotal)*100.0) + << ":" << pkg_action + << std::endl; + WriteToStatusFd(status.str()); + + if(_config->FindB("Debug::APT::Progress::PackageManagerFd", false) == true) + std::cerr << "progress: " << PackageName << " " << xStepsDone + << " " << xTotalSteps << " " << pkg_action + << std::endl; + + + return true; +} + +void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows) +{ + // scroll down a bit to avoid visual glitch when the screen + // area shrinks by one row + std::cout << "\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); +} + +PackageManagerFancy::PackageManagerFancy() + : nr_terminal_rows(-1) +{ + struct winsize win; + if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) == 0) + { + nr_terminal_rows = win.ws_row; + } +} + +void PackageManagerFancy::Start() +{ + if (nr_terminal_rows > 0) + SetupTerminalScrollArea(nr_terminal_rows); +} + +void PackageManagerFancy::Stop() +{ + if (nr_terminal_rows > 0) + { + SetupTerminalScrollArea(nr_terminal_rows + 1); + + // override the progress line (sledgehammer) + static const char* clear_screen_below_cursor = "\033[J"; + std::cout << clear_screen_below_cursor; + } +} + +bool PackageManagerFancy::StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction) +{ + if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, + HumanReadableAction)) + return false; + + int row = 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; + std::flush(std::cout); + last_reported_progress = percentage; + + return true; +} + +bool PackageManagerText::StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction) +{ + if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction)) + return false; + + std::cout << progress_str << "\r\n"; + std::flush(std::cout); + + last_reported_progress = percentage; + + return true; +} + + +}; // namespace progress +}; // namespace apt diff --git a/apt-private/private-progress.h b/apt-private/private-progress.h new file mode 100644 index 000000000..42fa89be4 --- /dev/null +++ b/apt-private/private-progress.h @@ -0,0 +1,109 @@ +#ifndef PKGLIB_IPROGRESS_H +#define PKGLIB_IPROGRESS_H + +#include +#include + + +namespace APT { +namespace Progress { + + class PackageManager + { + private: + /** \brief dpointer placeholder */ + void *d; + + protected: + std::string progress_str; + float percentage; + int last_reported_progress; + + public: + PackageManager() + : percentage(0.0), last_reported_progress(-1) {}; + virtual ~PackageManager() {}; + + virtual void Start() {}; + virtual void Stop() {}; + + virtual pid_t fork() {return fork(); }; + + virtual void Pulse() {}; + virtual long GetPulseInterval() { + return 500000; + }; + + virtual bool StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction) ; + virtual void Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage) {}; + virtual void ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage) {}; + }; + + class PackageManagerProgressFd : public PackageManager + { + protected: + int OutStatusFd; + int StepsDone; + int StepsTotal; + void WriteToStatusFd(std::string msg); + + public: + PackageManagerProgressFd(int progress_fd); + + virtual void Start(); + virtual void Stop(); + + virtual bool StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction); + virtual void Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage); + virtual void ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage); + + }; + + class PackageManagerFancy : public PackageManager + { + protected: + int nr_terminal_rows; + void SetupTerminalScrollArea(int nr_rows); + + public: + PackageManagerFancy(); + virtual void Start(); + virtual void Stop(); + virtual bool StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction); + }; + + class PackageManagerText : public PackageManager + { + public: + virtual bool StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction); + }; + + +}; // namespace Progress +}; // namespace APT + +#endif -- cgit v1.2.3