3 #include <apt-pkg/configuration.h> 
   4 #include <apt-pkg/fileutl.h> 
   5 #include <apt-pkg/strutl.h> 
   6 #include <apt-pkg/install-progress.h> 
  12 #include <sys/ioctl.h> 
  24 PackageManager::PackageManager() : d(NULL
), percentage(0.0), last_reported_progress(-1) {} 
  25 PackageManager::~PackageManager() {} 
  27 /* Return a APT::Progress::PackageManager based on the global 
  28  * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd) 
  30 PackageManager
* PackageManagerProgressFactory() 
  32    // select the right progress 
  33    int status_fd 
= _config
->FindI("APT::Status-Fd", -1); 
  34    int status_deb822_fd 
= _config
->FindI("APT::Status-deb822-Fd", -1); 
  36    APT::Progress::PackageManager 
*progress 
= NULL
; 
  37    if (status_deb822_fd 
> 0) 
  38       progress 
= new APT::Progress::PackageManagerProgressDeb822Fd( 
  40    else if (status_fd 
> 0) 
  41       progress 
= new APT::Progress::PackageManagerProgressFd(status_fd
); 
  42    else if(_config
->FindB("Dpkg::Progress-Fancy", false) == true) 
  43       progress 
= new APT::Progress::PackageManagerFancy(); 
  44    else if (_config
->FindB("Dpkg::Progress",  
  45                            _config
->FindB("DpkgPM::Progress", false)) == true) 
  46       progress 
= new APT::Progress::PackageManagerText(); 
  48       progress 
= new APT::Progress::PackageManager(); 
  52 bool PackageManager::StatusChanged(std::string 
/*PackageName*/, 
  53                                    unsigned int StepsDone
, 
  54                                    unsigned int TotalSteps
, 
  55                                    std::string 
/*HumanReadableAction*/) 
  57    int reporting_steps 
= _config
->FindI("DpkgPM::Reporting-Steps", 1); 
  58    percentage 
= StepsDone
/(float)TotalSteps 
* 100.0; 
  59    strprintf(progress_str
, _("Progress: [%3i%%]"), (int)percentage
); 
  61    if(percentage 
< (last_reported_progress 
+ reporting_steps
)) 
  67 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd
) 
  68    : d(NULL
), StepsDone(0), StepsTotal(1) 
  70    OutStatusFd 
= progress_fd
; 
  72 PackageManagerProgressFd::~PackageManagerProgressFd() {} 
  74 void PackageManagerProgressFd::WriteToStatusFd(std::string s
) 
  78    FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());    
  81 void PackageManagerProgressFd::StartDpkg() 
  86    // FIXME: use SetCloseExec here once it taught about throwing 
  87    //        exceptions instead of doing _exit(100) on failure 
  88    fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);  
  90    // send status information that we are about to fork dpkg 
  92    strprintf(status
, "pmstatus:dpkg-exec:%.4f:%s\n", 
  93          (StepsDone
/float(StepsTotal
)*100.0), _("Running dpkg")); 
  94    WriteToStatusFd(std::move(status
)); 
  97 APT_CONST 
void PackageManagerProgressFd::Stop() 
 101 void PackageManagerProgressFd::Error(std::string PackageName
, 
 102                                      unsigned int StepsDone
, 
 103                                      unsigned int TotalSteps
, 
 104                                      std::string ErrorMessage
) 
 107    strprintf(status
, "pmerror:%s:%.4f:%s\n", PackageName
.c_str(), 
 108          (StepsDone
/float(TotalSteps
)*100.0), ErrorMessage
.c_str()); 
 109    WriteToStatusFd(std::move(status
)); 
 112 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName
, 
 113                                               unsigned int StepsDone
, 
 114                                               unsigned int TotalSteps
, 
 115                                               std::string ConfMessage
) 
 118    strprintf(status
, "pmconffile:%s:%.4f:%s\n", PackageName
.c_str(), 
 119          (StepsDone
/float(TotalSteps
)*100.0), ConfMessage
.c_str()); 
 120    WriteToStatusFd(std::move(status
)); 
 124 bool PackageManagerProgressFd::StatusChanged(std::string PackageName
,  
 125                                              unsigned int xStepsDone
, 
 126                                              unsigned int xTotalSteps
, 
 127                                              std::string pkg_action
) 
 129    StepsDone 
= xStepsDone
; 
 130    StepsTotal 
= xTotalSteps
; 
 132    // build the status str 
 134    strprintf(status
, "pmstatus:%s:%.4f:%s\n", StringSplit(PackageName
, ":")[0].c_str(), 
 135          (StepsDone
/float(StepsTotal
)*100.0), pkg_action
.c_str()); 
 136    WriteToStatusFd(std::move(status
)); 
 138    if(_config
->FindB("Debug::APT::Progress::PackageManagerFd", false) == true) 
 139       std::cerr 
<< "progress: " << PackageName 
<< " " << xStepsDone
 
 140                 << " " << xTotalSteps 
<< " " << pkg_action
 
 148 PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd
) 
 149    : d(NULL
), StepsDone(0), StepsTotal(1) 
 151    OutStatusFd 
= progress_fd
; 
 153 PackageManagerProgressDeb822Fd::~PackageManagerProgressDeb822Fd() {} 
 155 void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s
) 
 157    FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());    
 160 void PackageManagerProgressDeb822Fd::StartDpkg() 
 162    // FIXME: use SetCloseExec here once it taught about throwing 
 163    //        exceptions instead of doing _exit(100) on failure 
 164    fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);  
 166    // send status information that we are about to fork dpkg 
 168    strprintf(status
, "Status: %s\nPercent: %.4f\nMessage: %s\n\n", "progress", 
 169          (StepsDone
/float(StepsTotal
)*100.0), _("Running dpkg")); 
 170    WriteToStatusFd(std::move(status
)); 
 173 APT_CONST 
void PackageManagerProgressDeb822Fd::Stop() 
 177 void PackageManagerProgressDeb822Fd::Error(std::string PackageName
, 
 178                                      unsigned int StepsDone
, 
 179                                      unsigned int TotalSteps
, 
 180                                      std::string ErrorMessage
) 
 183    strprintf(status
, "Status: %s\nPackage: %s\nPercent: %.4f\nMessage: %s\n\n", "Error", 
 184          PackageName
.c_str(), (StepsDone
/float(TotalSteps
)*100.0), ErrorMessage
.c_str()); 
 185    WriteToStatusFd(std::move(status
)); 
 188 void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName
, 
 189                                               unsigned int StepsDone
, 
 190                                               unsigned int TotalSteps
, 
 191                                               std::string ConfMessage
) 
 194    strprintf(status
, "Status: %s\nPackage: %s\nPercent: %.4f\nMessage: %s\n\n", "ConfFile", 
 195          PackageName
.c_str(), (StepsDone
/float(TotalSteps
)*100.0), ConfMessage
.c_str()); 
 196    WriteToStatusFd(std::move(status
)); 
 200 bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName
,  
 201                                              unsigned int xStepsDone
, 
 202                                              unsigned int xTotalSteps
, 
 205    StepsDone 
= xStepsDone
; 
 206    StepsTotal 
= xTotalSteps
; 
 209    strprintf(status
, "Status: %s\nPackage: %s\nPercent: %.4f\nMessage: %s\n\n", "progress", 
 210          PackageName
.c_str(), (StepsDone
/float(StepsTotal
)*100.0), message
.c_str()); 
 211    WriteToStatusFd(std::move(status
)); 
 216 PackageManagerFancy::PackageManagerFancy() 
 217    : d(NULL
), child_pty(-1) 
 219    // setup terminal size 
 220    old_SIGWINCH 
= signal(SIGWINCH
, PackageManagerFancy::staticSIGWINCH
); 
 221    instances
.push_back(this); 
 223 std::vector
<PackageManagerFancy
*> PackageManagerFancy::instances
; 
 225 PackageManagerFancy::~PackageManagerFancy() 
 227    instances
.erase(find(instances
.begin(), instances
.end(), this)); 
 228    signal(SIGWINCH
, old_SIGWINCH
); 
 231 void PackageManagerFancy::staticSIGWINCH(int signum
) 
 233    std::vector
<PackageManagerFancy 
*>::const_iterator I
; 
 234    for(I 
= instances
.begin(); I 
!= instances
.end(); ++I
) 
 235       (*I
)->HandleSIGWINCH(signum
); 
 238 PackageManagerFancy::TermSize
 
 239 PackageManagerFancy::GetTerminalSize() 
 242    PackageManagerFancy::TermSize s 
= { 0, 0 }; 
 244    // FIXME: get from "child_pty" instead? 
 245    if(ioctl(STDOUT_FILENO
, TIOCGWINSZ
, (char *)&win
) != 0) 
 248    if(_config
->FindB("Debug::InstallProgress::Fancy", false) == true) 
 249       std::cerr 
<< "GetTerminalSize: " << win
.ws_row 
<< " x " << win
.ws_col 
<< std::endl
; 
 252    s
.columns 
= win
.ws_col
; 
 256 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows
) 
 258      if(_config
->FindB("Debug::InstallProgress::Fancy", false) == true) 
 259         std::cerr 
<< "SetupTerminalScrollArea: " << nr_rows 
<< std::endl
; 
 261      if (unlikely(nr_rows 
<= 1)) 
 264      // scroll down a bit to avoid visual glitch when the screen 
 265      // area shrinks by one row 
 269      std::cout 
<< "\0337"; 
 271      // set scroll region (this will place the cursor in the top left) 
 272      std::cout 
<< "\033[0;" << std::to_string(nr_rows 
- 1) << "r"; 
 274      // restore cursor but ensure its inside the scrolling area 
 275      std::cout 
<< "\0338"; 
 276      static const char *move_cursor_up 
= "\033[1A"; 
 277      std::cout 
<< move_cursor_up
; 
 279      // ensure its flushed 
 280      std::flush(std::cout
); 
 282      // setup tty size to ensure xterm/linux console are working properly too 
 285      if (ioctl(child_pty
, TIOCGWINSZ
, (char *)&win
) != -1) 
 287         win
.ws_row 
= nr_rows 
- 1; 
 288         ioctl(child_pty
, TIOCSWINSZ
, (char *)&win
); 
 292 void PackageManagerFancy::HandleSIGWINCH(int) 
 294    int const nr_terminal_rows 
= GetTerminalSize().rows
; 
 295    SetupTerminalScrollArea(nr_terminal_rows
); 
 299 void PackageManagerFancy::Start(int a_child_pty
) 
 301    child_pty 
= a_child_pty
; 
 302    int const nr_terminal_rows 
= GetTerminalSize().rows
; 
 303    SetupTerminalScrollArea(nr_terminal_rows
); 
 306 void PackageManagerFancy::Stop() 
 308    int const nr_terminal_rows 
= GetTerminalSize().rows
; 
 309    if (nr_terminal_rows 
> 0) 
 311       SetupTerminalScrollArea(nr_terminal_rows 
+ 1); 
 313       // override the progress line (sledgehammer) 
 314       static const char* clear_screen_below_cursor 
= "\033[J"; 
 315       std::cout 
<< clear_screen_below_cursor
; 
 316       std::flush(std::cout
); 
 322 PackageManagerFancy::GetTextProgressStr(float Percent
, int OutputSize
) 
 325    if (unlikely(OutputSize 
< 3)) 
 328    int const BarSize 
= OutputSize 
- 2; // bar without the leading "[" and trailing "]" 
 329    int const BarDone 
= std::max(0, std::min(BarSize
, static_cast<int>(std::floor(Percent 
* BarSize
)))); 
 331    std::fill_n(std::fill_n(std::back_inserter(output
), BarDone
, '#'), BarSize 
- BarDone
, '.'); 
 336 bool PackageManagerFancy::StatusChanged(std::string PackageName
,  
 337                                         unsigned int StepsDone
, 
 338                                         unsigned int TotalSteps
, 
 339                                         std::string HumanReadableAction
) 
 341    if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
, 
 342           HumanReadableAction
)) 
 345    return DrawStatusLine(); 
 347 bool PackageManagerFancy::DrawStatusLine() 
 349    PackageManagerFancy::TermSize 
const size 
= GetTerminalSize(); 
 350    if (unlikely(size
.rows 
< 1 || size
.columns 
< 1)) 
 353    static std::string save_cursor 
= "\0337"; 
 354    static std::string restore_cursor 
= "\0338"; 
 357    static std::string set_bg_color 
= DeQuoteString( 
 358       _config
->Find("Dpkg::Progress-Fancy::Progress-fg", "%1b[42m")); 
 360    static std::string set_fg_color 
= DeQuoteString( 
 361       _config
->Find("Dpkg::Progress-Fancy::Progress-bg", "%1b[30m")); 
 363    static std::string restore_bg 
=  "\033[49m"; 
 364    static std::string restore_fg 
= "\033[39m"; 
 366    std::cout 
<< save_cursor
 
 367       // move cursor position to last row 
 368              << "\033[" << std::to_string(size
.rows
) << ";0f" 
 374    std::flush(std::cout
); 
 376    // draw text progress bar 
 377    if (_config
->FindB("Dpkg::Progress-Fancy::Progress-Bar", true)) 
 380       float progressbar_size 
= size
.columns 
- padding 
- progress_str
.size(); 
 381       float current_percent 
= percentage 
/ 100.0; 
 383                 << GetTextProgressStr(current_percent
, progressbar_size
) 
 385       std::flush(std::cout
); 
 389    std::cout 
<< restore_cursor
; 
 390    std::flush(std::cout
); 
 392    last_reported_progress 
= percentage
; 
 397 bool PackageManagerText::StatusChanged(std::string PackageName
,  
 398                                        unsigned int StepsDone
, 
 399                                        unsigned int TotalSteps
, 
 400                                        std::string HumanReadableAction
) 
 402    if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
, HumanReadableAction
)) 
 405    std::cout 
<< progress_str 
<< "\r\n"; 
 406    std::flush(std::cout
); 
 408    last_reported_progress 
= percentage
; 
 413 PackageManagerText::PackageManagerText() : PackageManager(), d(NULL
) {} 
 414 PackageManagerText::~PackageManagerText() {} 
 419 } // namespace progress