"Fossies" - the Fresh Open Source Software Archive

Member "apt-2.2.4/apt-private/acqprogress.cc" (10 Jun 2021, 11708 Bytes) of package /linux/misc/apt-2.2.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "acqprogress.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.2.3_vs_2.2.4.

    1 // -*- mode: cpp; mode: fold -*-
    2 // Description                              /*{{{*/
    3 /* ######################################################################
    4 
    5    Acquire Progress - Command line progress meter
    6 
    7    ##################################################################### */
    8                                     /*}}}*/
    9 // Include files                            /*{{{*/
   10 #include <config.h>
   11 
   12 #include <apt-pkg/acquire-item.h>
   13 #include <apt-pkg/acquire-worker.h>
   14 #include <apt-pkg/acquire.h>
   15 #include <apt-pkg/configuration.h>
   16 #include <apt-pkg/error.h>
   17 #include <apt-pkg/strutl.h>
   18 
   19 #include <apt-private/acqprogress.h>
   20 #include <apt-private/private-output.h>
   21 
   22 #include <iostream>
   23 #include <sstream>
   24 #include <signal.h>
   25 #include <stdio.h>
   26 #include <string.h>
   27 #include <unistd.h>
   28 
   29 #include <apti18n.h>
   30                                     /*}}}*/
   31 
   32 // AcqTextStatus::AcqTextStatus - Constructor               /*{{{*/
   33 // ---------------------------------------------------------------------
   34 /* */
   35 AcqTextStatus::AcqTextStatus(std::ostream &out, unsigned int &ScreenWidth,unsigned int const Quiet) :
   36     pkgAcquireStatus(), out(out), ScreenWidth(ScreenWidth), LastLineLength(0), ID(0), Quiet(Quiet)
   37 {
   38    // testcases use it to disable pulses without disabling other user messages
   39    if (Quiet == 0 && _config->FindB("quiet::NoUpdate", false) == true)
   40       this->Quiet = 1;
   41    if (Quiet < 2 && _config->FindB("quiet::NoProgress", false) == true)
   42       this->Quiet = 2;
   43 }
   44                                     /*}}}*/
   45 // AcqTextStatus::Start - Downloading has started           /*{{{*/
   46 // ---------------------------------------------------------------------
   47 /* */
   48 void AcqTextStatus::Start()
   49 {
   50    pkgAcquireStatus::Start();
   51    LastLineLength = 0;
   52    ID = 1;
   53 }
   54                                     /*}}}*/
   55 void AcqTextStatus::AssignItemID(pkgAcquire::ItemDesc &Itm)     /*{{{*/
   56 {
   57    /* In theory calling it from Fetch() would be enough, but to be
   58       safe we call it from IMSHit and Fail as well.
   59       Also, an Item can pass through multiple stages, so ensure
   60       that it keeps the same number */
   61    if (Itm.Owner->ID == 0)
   62       Itm.Owner->ID = ID++;
   63 }
   64                                     /*}}}*/
   65 // AcqTextStatus::IMSHit - Called when an item got a HIT response   /*{{{*/
   66 // ---------------------------------------------------------------------
   67 /* */
   68 void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
   69 {
   70    if (Quiet > 1)
   71       return;
   72 
   73    AssignItemID(Itm);
   74    clearLastLine();
   75 
   76    // TRANSLATOR: Very short word to be displayed before unchanged files in 'apt-get update'
   77    ioprintf(out, _("Hit:%lu %s"), Itm.Owner->ID, Itm.Description.c_str());
   78    out << std::endl;
   79    Update = true;
   80 }
   81                                     /*}}}*/
   82 // AcqTextStatus::Fetch - An item has started to download       /*{{{*/
   83 // ---------------------------------------------------------------------
   84 /* This prints out the short description and the expected size */
   85 void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
   86 {
   87    Update = true;
   88    if (Itm.Owner->Complete == true)
   89       return;
   90    AssignItemID(Itm);
   91 
   92    if (Quiet > 1)
   93       return;
   94 
   95    clearLastLine();
   96 
   97    // TRANSLATOR: Very short word to be displayed for files processed in 'apt-get update'
   98    // Potentially replaced later by "Hit:", "Ign:" or "Err:" if something (bad) happens
   99    ioprintf(out, _("Get:%lu %s"), Itm.Owner->ID, Itm.Description.c_str());
  100    if (Itm.Owner->FileSize != 0)
  101       out << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
  102    out << std::endl;
  103 }
  104                                     /*}}}*/
  105 // AcqTextStatus::Done - Completed a download               /*{{{*/
  106 // ---------------------------------------------------------------------
  107 /* We don't display anything... */
  108 void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm)
  109 {
  110    Update = true;
  111    AssignItemID(Itm);
  112 }
  113                                     /*}}}*/
  114 // AcqTextStatus::Fail - Called when an item fails to download      /*{{{*/
  115 // ---------------------------------------------------------------------
  116 /* We print out the error text  */
  117 void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
  118 {
  119    if (Quiet > 1)
  120       return;
  121 
  122    AssignItemID(Itm);
  123    clearLastLine();
  124 
  125    bool ShowErrorText = true;
  126    if (Itm.Owner->Status == pkgAcquire::Item::StatDone || Itm.Owner->Status == pkgAcquire::Item::StatIdle)
  127    {
  128       // TRANSLATOR: Very short word to be displayed for files in 'apt-get update'
  129       // which failed to download, but the error is ignored (compare "Err:")
  130       ioprintf(out, _("Ign:%lu %s"), Itm.Owner->ID, Itm.Description.c_str());
  131       if (Itm.Owner->ErrorText.empty() ||
  132         _config->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == false)
  133      ShowErrorText = false;
  134    }
  135    else
  136    {
  137       // TRANSLATOR: Very short word to be displayed for files in 'apt-get update'
  138       // which failed to download and the error is critical (compare "Ign:")
  139       ioprintf(out, _("Err:%lu %s"), Itm.Owner->ID, Itm.Description.c_str());
  140    }
  141 
  142    if (ShowErrorText)
  143    {
  144       std::string::size_type line_start = 0;
  145       std::string::size_type line_end;
  146       while ((line_end = Itm.Owner->ErrorText.find_first_of("\n\r", line_start)) != std::string::npos) {
  147      out << std::endl << "  " << Itm.Owner->ErrorText.substr(line_start, line_end - line_start);
  148      line_start = Itm.Owner->ErrorText.find_first_not_of("\n\r", line_end + 1);
  149      if (line_start == std::string::npos)
  150         break;
  151       }
  152       if (line_start == 0)
  153      out << std::endl << "  " << Itm.Owner->ErrorText;
  154       else if (line_start != std::string::npos)
  155      out << std::endl << "  " << Itm.Owner->ErrorText.substr(line_start);
  156    }
  157    out << std::endl;
  158 
  159    Update = true;
  160 }
  161                                     /*}}}*/
  162 // AcqTextStatus::Stop - Finished downloading               /*{{{*/
  163 // ---------------------------------------------------------------------
  164 /* This prints out the bytes downloaded and the overall average line
  165    speed */
  166 void AcqTextStatus::Stop()
  167 {
  168    pkgAcquireStatus::Stop();
  169    if (Quiet > 1)
  170       return;
  171 
  172    clearLastLine();
  173 
  174    if (_config->FindB("quiet::NoStatistic", false) == true)
  175       return;
  176 
  177    if (FetchedBytes != 0 && _error->PendingError() == false)
  178       ioprintf(out,_("Fetched %sB in %s (%sB/s)\n"),
  179            SizeToStr(FetchedBytes).c_str(),
  180            TimeToStr(ElapsedTime).c_str(),
  181            SizeToStr(CurrentCPS).c_str());
  182 }
  183                                     /*}}}*/
  184 // AcqTextStatus::Pulse - Regular event pulse               /*{{{*/
  185 // ---------------------------------------------------------------------
  186 /* This draws the current progress. Each line has an overall percent
  187    meter and a per active item status meter along with an overall
  188    bandwidth and ETA indicator. */
  189 bool AcqTextStatus::Pulse(pkgAcquire *Owner)
  190 {
  191    pkgAcquireStatus::Pulse(Owner);
  192 
  193    if (Quiet > 0)
  194       return true;
  195 
  196    std::string Line;
  197    {
  198       std::stringstream S;
  199       for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
  200         I = Owner->WorkerStep(I))
  201       {
  202      // There is no item running
  203      if (I->CurrentItem == 0)
  204      {
  205         if (I->Status.empty() == false)
  206            S << " [" << I->Status << "]";
  207 
  208         continue;
  209      }
  210 
  211      // Add in the short description
  212      S << " [";
  213      if (I->CurrentItem->Owner->ID != 0)
  214         S << std::to_string(I->CurrentItem->Owner->ID) << " ";
  215      S << I->CurrentItem->ShortDesc;
  216 
  217      // Show the short mode string
  218      if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
  219         S << " " << I->CurrentItem->Owner->ActiveSubprocess;
  220 
  221      enum {Long = 0,Medium,Short} Mode = Medium;
  222      // Add the current progress
  223      if (Mode == Long)
  224         S << " " << std::to_string(I->CurrentItem->CurrentSize);
  225      else
  226      {
  227         if (Mode == Medium || I->CurrentItem->TotalSize == 0)
  228            S << " " << SizeToStr(I->CurrentItem->CurrentSize) << "B";
  229      }
  230 
  231      // Add the total size and percent
  232      if (I->CurrentItem->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
  233      {
  234         if (Mode == Short)
  235            ioprintf(S, " %.0f%%", (I->CurrentItem->CurrentSize*100.0)/I->CurrentItem->TotalSize);
  236         else
  237            ioprintf(S, "/%sB %.0f%%", SizeToStr(I->CurrentItem->TotalSize).c_str(),
  238              (I->CurrentItem->CurrentSize*100.0)/I->CurrentItem->TotalSize);
  239      }
  240      S << "]";
  241       }
  242 
  243       // Show at least something
  244       Line = S.str();
  245       S.clear();
  246       if (Line.empty() == true)
  247      Line = _(" [Working]");
  248    }
  249    // Put in the percent done
  250    {
  251       std::stringstream S;
  252       ioprintf(S, "%.0f%%", Percent);
  253       S << Line;
  254       Line = S.str();
  255       S.clear();
  256    }
  257 
  258    /* Put in the ETA and cps meter, block off signals to prevent strangeness
  259       during resizing */
  260    sigset_t Sigs,OldSigs;
  261    sigemptyset(&Sigs);
  262    sigaddset(&Sigs,SIGWINCH);
  263    sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
  264 
  265    if (CurrentCPS != 0)
  266    {
  267       unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
  268       std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA);
  269       size_t alignment = Line.length() + Tmp.length();
  270       if (alignment < ScreenWidth)
  271       {
  272      alignment = ScreenWidth - alignment;
  273      for (size_t i = 0; i < alignment; ++i)
  274         Line.append(" ");
  275      Line.append(Tmp);
  276       }
  277    }
  278    if (Line.length() > ScreenWidth)
  279       Line.erase(ScreenWidth);
  280    sigprocmask(SIG_SETMASK,&OldSigs,0);
  281 
  282    // Draw the current status
  283    if (_config->FindB("Apt::Color", false) == true)
  284       out << _config->Find("APT::Color::Yellow");
  285    if (LastLineLength > Line.length())
  286       clearLastLine();
  287    else
  288       out << '\r';
  289    out << Line << std::flush;
  290    if (_config->FindB("Apt::Color", false) == true)
  291       out << _config->Find("APT::Color::Neutral") << std::flush;
  292 
  293    LastLineLength = Line.length();
  294    Update = false;
  295 
  296    return true;
  297 }
  298                                     /*}}}*/
  299 // AcqTextStatus::MediaChange - Media need to be swapped        /*{{{*/
  300 // ---------------------------------------------------------------------
  301 /* Prompt for a media swap */
  302 bool AcqTextStatus::MediaChange(std::string Media, std::string Drive)
  303 {
  304    // If we do not output on a terminal and one of the options to avoid user
  305    // interaction is given, we assume that no user is present who could react
  306    // on your media change request
  307    if (isatty(STDOUT_FILENO) != 1 && Quiet >= 2 &&
  308        (_config->FindB("APT::Get::Assume-Yes",false) == true ||
  309     _config->FindB("APT::Get::Force-Yes",false) == true ||
  310     _config->FindB("APT::Get::Trivial-Only",false) == true))
  311 
  312       return false;
  313 
  314    clearLastLine();
  315    ioprintf(out,_("Media change: please insert the disc labeled\n"
  316            " '%s'\n"
  317            "in the drive '%s' and press [Enter]\n"),
  318         Media.c_str(),Drive.c_str());
  319 
  320    char C = 0;
  321    bool bStatus = true;
  322    while (C != '\n' && C != '\r')
  323    {
  324       int len = read(STDIN_FILENO,&C,1);
  325       if(C == 'c' || len <= 0) {
  326      bStatus = false;
  327      break;
  328       }
  329    }
  330 
  331    if(bStatus)
  332       Update = true;
  333    return bStatus;
  334 }
  335                                     /*}}}*/
  336 bool AcqTextStatus::ReleaseInfoChanges(metaIndex const * const L, metaIndex const * const N, std::vector<ReleaseInfoChange> &&Changes)/*{{{*/
  337 {
  338    if (Quiet >= 2 || isatty(STDOUT_FILENO) != 1 || isatty(STDIN_FILENO) != 1 ||
  339      _config->FindB("APT::Get::Update::InteractiveReleaseInfoChanges", false) == false)
  340       return pkgAcquireStatus::ReleaseInfoChanges(nullptr, nullptr, std::move(Changes));
  341 
  342    _error->PushToStack();
  343    auto const confirmed = pkgAcquireStatus::ReleaseInfoChanges(L, N, std::move(Changes));
  344    if (confirmed == true)
  345    {
  346       _error->MergeWithStack();
  347       return true;
  348    }
  349    clearLastLine();
  350    _error->DumpErrors(out, GlobalError::NOTICE, false);
  351    _error->RevertToStack();
  352    return YnPrompt(_("Do you want to accept these changes and continue updating from this repository?"), false, false, out, out);
  353 }
  354                                     /*}}}*/
  355 void AcqTextStatus::clearLastLine() {                   /*{{{*/
  356    if (Quiet > 0 || LastLineLength == 0)
  357       return;
  358 
  359    // do not try to clear more than the (now smaller) screen
  360    if (LastLineLength > ScreenWidth)
  361       LastLineLength = ScreenWidth;
  362 
  363    out << '\r';
  364    for (size_t i = 0; i < LastLineLength; ++i)
  365       out << ' ';
  366    out << '\r' << std::flush;
  367 }
  368                                     /*}}}*/