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