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