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