acqprogress.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: acqprogress.cc,v 1.24 2003/04/27 01:56:48 doogie Exp $
  4. /* ######################################################################
  5. Acquire Progress - Command line progress meter
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include files /*{{{*/
  9. #include<config.h>
  10. #include <apt-pkg/acquire-item.h>
  11. #include <apt-pkg/acquire-worker.h>
  12. #include <apt-pkg/configuration.h>
  13. #include <apt-pkg/strutl.h>
  14. #include <apt-pkg/error.h>
  15. #include <stdio.h>
  16. #include <signal.h>
  17. #include <iostream>
  18. #include <unistd.h>
  19. #include "acqprogress.h"
  20. #include <apti18n.h>
  21. /*}}}*/
  22. using namespace std;
  23. // AcqTextStatus::AcqTextStatus - Constructor /*{{{*/
  24. // ---------------------------------------------------------------------
  25. /* */
  26. AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet) :
  27. ScreenWidth(ScreenWidth), Quiet(Quiet)
  28. {
  29. }
  30. /*}}}*/
  31. // AcqTextStatus::Start - Downloading has started /*{{{*/
  32. // ---------------------------------------------------------------------
  33. /* */
  34. void AcqTextStatus::Start()
  35. {
  36. pkgAcquireStatus::Start();
  37. BlankLine[0] = 0;
  38. ID = 1;
  39. };
  40. /*}}}*/
  41. // AcqTextStatus::IMSHit - Called when an item got a HIT response /*{{{*/
  42. // ---------------------------------------------------------------------
  43. /* */
  44. void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
  45. {
  46. if (Quiet > 1)
  47. return;
  48. if (Quiet <= 0)
  49. cout << '\r' << BlankLine << '\r';
  50. cout << _("Hit ") << Itm.Description;
  51. if (Itm.Owner->FileSize != 0)
  52. cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
  53. cout << endl;
  54. Update = true;
  55. };
  56. /*}}}*/
  57. // AcqTextStatus::Fetch - An item has started to download /*{{{*/
  58. // ---------------------------------------------------------------------
  59. /* This prints out the short description and the expected size */
  60. void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
  61. {
  62. Update = true;
  63. if (Itm.Owner->Complete == true)
  64. return;
  65. Itm.Owner->ID = ID++;
  66. if (Quiet > 1)
  67. return;
  68. if (Quiet <= 0)
  69. cout << '\r' << BlankLine << '\r';
  70. cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description;
  71. if (Itm.Owner->FileSize != 0)
  72. cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
  73. cout << endl;
  74. };
  75. /*}}}*/
  76. // AcqTextStatus::Done - Completed a download /*{{{*/
  77. // ---------------------------------------------------------------------
  78. /* We don't display anything... */
  79. void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm)
  80. {
  81. Update = true;
  82. };
  83. /*}}}*/
  84. // AcqTextStatus::Fail - Called when an item fails to download /*{{{*/
  85. // ---------------------------------------------------------------------
  86. /* We print out the error text */
  87. void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
  88. {
  89. if (Quiet > 1)
  90. return;
  91. // Ignore certain kinds of transient failures (bad code)
  92. if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
  93. return;
  94. if (Quiet <= 0)
  95. cout << '\r' << BlankLine << '\r';
  96. if (Itm.Owner->Status == pkgAcquire::Item::StatDone)
  97. {
  98. cout << _("Ign ") << Itm.Description << endl;
  99. }
  100. else
  101. {
  102. cout << _("Err ") << Itm.Description << endl;
  103. cout << " " << Itm.Owner->ErrorText << endl;
  104. }
  105. Update = true;
  106. };
  107. /*}}}*/
  108. // AcqTextStatus::Stop - Finished downloading /*{{{*/
  109. // ---------------------------------------------------------------------
  110. /* This prints out the bytes downloaded and the overall average line
  111. speed */
  112. void AcqTextStatus::Stop()
  113. {
  114. pkgAcquireStatus::Stop();
  115. if (Quiet > 1)
  116. return;
  117. if (Quiet <= 0)
  118. cout << '\r' << BlankLine << '\r' << flush;
  119. if (FetchedBytes != 0 && _error->PendingError() == false)
  120. ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"),
  121. SizeToStr(FetchedBytes).c_str(),
  122. TimeToStr(ElapsedTime).c_str(),
  123. SizeToStr(CurrentCPS).c_str());
  124. }
  125. /*}}}*/
  126. // AcqTextStatus::Pulse - Regular event pulse /*{{{*/
  127. // ---------------------------------------------------------------------
  128. /* This draws the current progress. Each line has an overall percent
  129. meter and a per active item status meter along with an overall
  130. bandwidth and ETA indicator. */
  131. bool AcqTextStatus::Pulse(pkgAcquire *Owner)
  132. {
  133. pkgAcquireStatus::Pulse(Owner);
  134. if (Quiet > 0)
  135. return true;
  136. enum {Long = 0,Medium,Short} Mode = Medium;
  137. char Buffer[sizeof(BlankLine)];
  138. char *End = Buffer + sizeof(Buffer);
  139. char *S = Buffer;
  140. if (ScreenWidth >= sizeof(Buffer))
  141. ScreenWidth = sizeof(Buffer)-1;
  142. // Put in the percent done
  143. sprintf(S,"%.0f%%",((CurrentBytes + CurrentItems)*100.0)/(TotalBytes+TotalItems));
  144. bool Shown = false;
  145. for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
  146. I = Owner->WorkerStep(I))
  147. {
  148. S += strlen(S);
  149. // There is no item running
  150. if (I->CurrentItem == 0)
  151. {
  152. if (I->Status.empty() == false)
  153. {
  154. snprintf(S,End-S," [%s]",I->Status.c_str());
  155. Shown = true;
  156. }
  157. continue;
  158. }
  159. Shown = true;
  160. // Add in the short description
  161. if (I->CurrentItem->Owner->ID != 0)
  162. snprintf(S,End-S," [%lu %s",I->CurrentItem->Owner->ID,
  163. I->CurrentItem->ShortDesc.c_str());
  164. else
  165. snprintf(S,End-S," [%s",I->CurrentItem->ShortDesc.c_str());
  166. S += strlen(S);
  167. // Show the short mode string
  168. if (I->CurrentItem->Owner->Mode != 0)
  169. {
  170. snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode);
  171. S += strlen(S);
  172. }
  173. // Add the current progress
  174. if (Mode == Long)
  175. snprintf(S,End-S," %llu",I->CurrentSize);
  176. else
  177. {
  178. if (Mode == Medium || I->TotalSize == 0)
  179. snprintf(S,End-S," %sB",SizeToStr(I->CurrentSize).c_str());
  180. }
  181. S += strlen(S);
  182. // Add the total size and percent
  183. if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
  184. {
  185. if (Mode == Short)
  186. snprintf(S,End-S," %.0f%%",
  187. (I->CurrentSize*100.0)/I->TotalSize);
  188. else
  189. snprintf(S,End-S,"/%sB %.0f%%",SizeToStr(I->TotalSize).c_str(),
  190. (I->CurrentSize*100.0)/I->TotalSize);
  191. }
  192. S += strlen(S);
  193. snprintf(S,End-S,"]");
  194. }
  195. // Show something..
  196. if (Shown == false)
  197. snprintf(S,End-S,_(" [Working]"));
  198. /* Put in the ETA and cps meter, block off signals to prevent strangeness
  199. during resizing */
  200. sigset_t Sigs,OldSigs;
  201. sigemptyset(&Sigs);
  202. sigaddset(&Sigs,SIGWINCH);
  203. sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
  204. if (CurrentCPS != 0)
  205. {
  206. char Tmp[300];
  207. unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
  208. sprintf(Tmp," %sB/s %s",SizeToStr(CurrentCPS).c_str(),TimeToStr(ETA).c_str());
  209. unsigned int Len = strlen(Buffer);
  210. unsigned int LenT = strlen(Tmp);
  211. if (Len + LenT < ScreenWidth)
  212. {
  213. memset(Buffer + Len,' ',ScreenWidth - Len);
  214. strcpy(Buffer + ScreenWidth - LenT,Tmp);
  215. }
  216. }
  217. Buffer[ScreenWidth] = 0;
  218. BlankLine[ScreenWidth] = 0;
  219. sigprocmask(SIG_SETMASK,&OldSigs,0);
  220. // Draw the current status
  221. if (strlen(Buffer) == strlen(BlankLine))
  222. cout << '\r' << Buffer << flush;
  223. else
  224. cout << '\r' << BlankLine << '\r' << Buffer << flush;
  225. memset(BlankLine,' ',strlen(Buffer));
  226. BlankLine[strlen(Buffer)] = 0;
  227. Update = false;
  228. return true;
  229. }
  230. /*}}}*/
  231. // AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/
  232. // ---------------------------------------------------------------------
  233. /* Prompt for a media swap */
  234. bool AcqTextStatus::MediaChange(string Media,string Drive)
  235. {
  236. // If we do not output on a terminal and one of the options to avoid user
  237. // interaction is given, we assume that no user is present who could react
  238. // on your media change request
  239. if (isatty(STDOUT_FILENO) != 1 && Quiet >= 2 &&
  240. (_config->FindB("APT::Get::Assume-Yes",false) == true ||
  241. _config->FindB("APT::Get::Force-Yes",false) == true ||
  242. _config->FindB("APT::Get::Trivial-Only",false) == true))
  243. return false;
  244. if (Quiet <= 0)
  245. cout << '\r' << BlankLine << '\r';
  246. ioprintf(cout,_("Media change: please insert the disc labeled\n"
  247. " '%s'\n"
  248. "in the drive '%s' and press enter\n"),
  249. Media.c_str(),Drive.c_str());
  250. char C = 0;
  251. bool bStatus = true;
  252. while (C != '\n' && C != '\r')
  253. {
  254. int len = read(STDIN_FILENO,&C,1);
  255. if(C == 'c' || len <= 0)
  256. bStatus = false;
  257. }
  258. if(bStatus)
  259. Update = true;
  260. return bStatus;
  261. }
  262. /*}}}*/