]> git.saurik.com Git - apt.git/blobdiff - apt-private/acqprogress.cc
add a simple unit test for acquire progress
[apt.git] / apt-private / acqprogress.cc
index ee6c4536f1c3ffb964dcb3d3c8d9a9e8af5b6aa1..0c606e48e85b823c9d9e03310f1242070b726115 100644 (file)
@@ -1,10 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: acqprogress.cc,v 1.24 2003/04/27 01:56:48 doogie Exp $
 /* ######################################################################
 
-   Acquire Progress - Command line progress meter 
-   
+   Acquire Progress - Command line progress meter
+
    ##################################################################### */
                                                                        /*}}}*/
 // Include files                                                       /*{{{*/
 #include <stdio.h>
 #include <signal.h>
 #include <iostream>
+#include <sstream>
 #include <unistd.h>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
-using namespace std;
-
 // AcqTextStatus::AcqTextStatus - Constructor                          /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int const Quiet) :
-    pkgAcquireStatus(), ScreenWidth(ScreenWidth), ID(0), Quiet(Quiet)
+AcqTextStatus::AcqTextStatus(std::ostream &out, unsigned int &ScreenWidth,unsigned int const Quiet) :
+    pkgAcquireStatus(), out(out), ScreenWidth(ScreenWidth), LastLineLength(0), ID(0), Quiet(Quiet)
 {
-   BlankLine[0] = 0;
    // testcases use it to disable pulses without disabling other user messages
    if (Quiet == 0 && _config->FindB("quiet::NoUpdate", false) == true)
       this->Quiet = 1;
@@ -48,7 +45,7 @@ AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int const Quiet)
 void AcqTextStatus::Start()
 {
    pkgAcquireStatus::Start();
-   BlankLine[0] = 0;
+   LastLineLength = 0;
    ID = 1;
 }
                                                                        /*}}}*/
@@ -60,13 +57,10 @@ void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
    if (Quiet > 1)
       return;
 
-   if (Quiet <= 0)
-      cout << '\r' << BlankLine << '\r';
+   clearLastLine();
 
-   cout << _("Hit ") << Itm.Description;
-   if (Itm.Owner->FileSize != 0)
-      cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
-   cout << endl;
+   out << _("Hit ") << Itm.Description;
+   out << std::endl;
    Update = true;
 }
                                                                        /*}}}*/
@@ -84,13 +78,12 @@ void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
    if (Quiet > 1)
       return;
 
-   if (Quiet <= 0)
-      cout << '\r' << BlankLine << '\r';
+   clearLastLine();
 
-   cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description;
+   out << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description;
    if (Itm.Owner->FileSize != 0)
-      cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
-   cout << endl;
+      out << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
+   out << std::endl;
 }
                                                                        /*}}}*/
 // AcqTextStatus::Done - Completed a download                          /*{{{*/
@@ -113,17 +106,19 @@ void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
    if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
       return;
 
-   if (Quiet <= 0)
-      cout << '\r' << BlankLine << '\r';
+   clearLastLine();
 
    if (Itm.Owner->Status == pkgAcquire::Item::StatDone)
    {
-      cout << _("Ign ") << Itm.Description << endl;
+      out << _("Ign ") << Itm.Description << std::endl;
+      if (Itm.Owner->ErrorText.empty() == false &&
+           _config->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == true)
+        out << "  " << Itm.Owner->ErrorText << std::endl;
    }
    else
    {
-      cout << _("Err ") << Itm.Description << endl;
-      cout << "  " << Itm.Owner->ErrorText << endl;
+      out << _("Err ") << Itm.Description << std::endl;
+      out << "  " << Itm.Owner->ErrorText << std::endl;
    }
 
    Update = true;
@@ -139,11 +134,13 @@ void AcqTextStatus::Stop()
    if (Quiet > 1)
       return;
 
-   if (Quiet <= 0)
-      cout << '\r' << BlankLine << '\r' << flush;
+   clearLastLine();
+
+   if (_config->FindB("quiet::NoStatistic", false) == true)
+      return;
 
    if (FetchedBytes != 0 && _error->PendingError() == false)
-      ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"),
+      ioprintf(out,_("Fetched %sB in %s (%sB/s)\n"),
               SizeToStr(FetchedBytes).c_str(),
               TimeToStr(ElapsedTime).c_str(),
               SizeToStr(CurrentCPS).c_str());
@@ -152,7 +149,7 @@ void AcqTextStatus::Stop()
 // AcqTextStatus::Pulse - Regular event pulse                          /*{{{*/
 // ---------------------------------------------------------------------
 /* This draws the current progress. Each line has an overall percent
-   meter and a per active item status meter along with an overall 
+   meter and a per active item status meter along with an overall
    bandwidth and ETA indicator. */
 bool AcqTextStatus::Pulse(pkgAcquire *Owner)
 {
@@ -163,77 +160,66 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner)
 
    enum {Long = 0,Medium,Short} Mode = Medium;
 
-   char Buffer[sizeof(BlankLine)];
-   char *End = Buffer + sizeof(Buffer);
-   char *S = Buffer;
-   if (ScreenWidth >= sizeof(Buffer))
-      ScreenWidth = sizeof(Buffer)-1;
-
-   // Put in the percent done
-   sprintf(S,"%.0f%%", Percent);
-
-   bool Shown = false;
-   for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
-       I = Owner->WorkerStep(I))
+   std::string Line;
    {
-      S += strlen(S);
-
-      // There is no item running
-      if (I->CurrentItem == 0)
+      std::stringstream S;
+      for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
+           I = Owner->WorkerStep(I))
       {
-        if (I->Status.empty() == false)
+        // There is no item running
+        if (I->CurrentItem == 0)
         {
-           snprintf(S,End-S," [%s]",I->Status.c_str());
-           Shown = true;
-        }
-
-        continue;
-      }
+           if (I->Status.empty() == false)
+              S << " [" << I->Status << "]";
 
-      Shown = true;
+           continue;
+        }
 
-      // Add in the short description
-      if (I->CurrentItem->Owner->ID != 0)
-        snprintf(S,End-S," [%lu %s",I->CurrentItem->Owner->ID,
-                 I->CurrentItem->ShortDesc.c_str());
-      else
-        snprintf(S,End-S," [%s",I->CurrentItem->ShortDesc.c_str());
-      S += strlen(S);
+        // Add in the short description
+        S << " [";
+        if (I->CurrentItem->Owner->ID != 0)
+           S << I->CurrentItem->Owner->ID << " ";
+        S << I->CurrentItem->ShortDesc;
 
-      // Show the short mode string
-      if (I->CurrentItem->Owner->Mode != 0)
-      {
-        snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode);
-        S += strlen(S);
-      }
-
-      // Add the current progress
-      if (Mode == Long)
-        snprintf(S,End-S," %llu",I->CurrentSize);
-      else
-      {
-        if (Mode == Medium || I->TotalSize == 0)
-           snprintf(S,End-S," %sB",SizeToStr(I->CurrentSize).c_str());
-      }
-      S += strlen(S);
+        // Show the short mode string
+        if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
+           S << " " << I->CurrentItem->Owner->ActiveSubprocess;
 
-      // Add the total size and percent
-      if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
-      {
-        if (Mode == Short)
-           snprintf(S,End-S," %.0f%%",
-                    (I->CurrentSize*100.0)/I->TotalSize);
+        // Add the current progress
+        if (Mode == Long)
+           S << " " << I->CurrentSize;
         else
-           snprintf(S,End-S,"/%sB %.0f%%",SizeToStr(I->TotalSize).c_str(),
+        {
+           if (Mode == Medium || I->TotalSize == 0)
+              S << " " << SizeToStr(I->CurrentSize) << "B";
+        }
+
+        // Add the total size and percent
+        if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
+        {
+           if (Mode == Short)
+              ioprintf(S, " %.0f%%", (I->CurrentSize*100.0)/I->TotalSize);
+           else
+              ioprintf(S, "/%sB %.0f%%", SizeToStr(I->TotalSize).c_str(),
                     (I->CurrentSize*100.0)/I->TotalSize);
+        }
+        S << "]";
       }
-      S += strlen(S);
-      snprintf(S,End-S,"]");
-   }
 
-   // Show something..
-   if (Shown == false)
-      snprintf(S,End-S,_(" [Working]"));
+      // Show at least something
+      Line = S.str();
+      S.clear();
+      if (Line.empty() == true)
+        Line = _(" [Working]");
+   }
+   // Put in the percent done
+   {
+      std::stringstream S;
+      ioprintf(S, "%.0f%%", Percent);
+      S << Line;
+      Line = S.str();
+      S.clear();
+   }
 
    /* Put in the ETA and cps meter, block off signals to prevent strangeness
       during resizing */
@@ -244,34 +230,33 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner)
 
    if (CurrentCPS != 0)
    {
-      char Tmp[300];
       unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
-      sprintf(Tmp," %sB/s %s",SizeToStr(CurrentCPS).c_str(),TimeToStr(ETA).c_str());
-      unsigned int Len = strlen(Buffer);
-      unsigned int LenT = strlen(Tmp);
-      if (Len + LenT < ScreenWidth)
+      std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA);
+      size_t alignment = Line.length() + Tmp.length();
+      if (alignment < ScreenWidth)
       {
-        memset(Buffer + Len,' ',ScreenWidth - Len);
-        strcpy(Buffer + ScreenWidth - LenT,Tmp);
+        alignment = ScreenWidth - alignment;
+        for (size_t i = 0; i < alignment; ++i)
+           Line.append(" ");
+        Line.append(Tmp);
       }
    }
-   Buffer[ScreenWidth] = 0;
-   BlankLine[ScreenWidth] = 0;
+   if (Line.length() > ScreenWidth)
+      Line.erase(ScreenWidth);
    sigprocmask(SIG_SETMASK,&OldSigs,0);
 
    // Draw the current status
    if (_config->FindB("Apt::Color", false) == true)
-      cout << _config->Find("APT::Color::Yellow");
-   if (strlen(Buffer) == strlen(BlankLine))
-      cout << '\r' << Buffer << flush;
+      out << _config->Find("APT::Color::Yellow");
+   if (LastLineLength > Line.length())
+      clearLastLine();
    else
-      cout << '\r' << BlankLine << '\r' << Buffer << flush;
+      out << '\r';
+   out << Line << std::flush;
    if (_config->FindB("Apt::Color", false) == true)
-      cout << _config->Find("APT::Color::Neutral") << flush;
-
-   memset(BlankLine,' ',strlen(Buffer));
-   BlankLine[strlen(Buffer)] = 0;
+      out << _config->Find("APT::Color::Neutral") << std::flush;
 
+   LastLineLength = Line.length();
    Update = false;
 
    return true;
@@ -280,7 +265,7 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner)
 // AcqTextStatus::MediaChange - Media need to be swapped               /*{{{*/
 // ---------------------------------------------------------------------
 /* Prompt for a media swap */
-bool AcqTextStatus::MediaChange(string Media,string Drive)
+bool AcqTextStatus::MediaChange(std::string Media, std::string Drive)
 {
    // If we do not output on a terminal and one of the options to avoid user
    // interaction is given, we assume that no user is present who could react
@@ -292,9 +277,8 @@ bool AcqTextStatus::MediaChange(string Media,string Drive)
 
       return false;
 
-   if (Quiet <= 0)
-      cout << '\r' << BlankLine << '\r';
-   ioprintf(cout,_("Media change: please insert the disc labeled\n"
+   clearLastLine();
+   ioprintf(out,_("Media change: please insert the disc labeled\n"
                   " '%s'\n"
                   "in the drive '%s' and press enter\n"),
            Media.c_str(),Drive.c_str());
@@ -313,3 +297,17 @@ bool AcqTextStatus::MediaChange(string Media,string Drive)
    return bStatus;
 }
                                                                        /*}}}*/
+void AcqTextStatus::clearLastLine() {                                  /*{{{*/
+   if (Quiet > 0 || LastLineLength == 0)
+      return;
+
+   // do not try to clear more than the (now smaller) screen
+   if (LastLineLength > ScreenWidth)
+      LastLineLength = ScreenWidth;
+
+   out << '\r';
+   for (size_t i = 0; i < LastLineLength; ++i)
+      out << ' ';
+   out << '\r' << std::flush;
+}
+                                                                       /*}}}*/