]> git.saurik.com Git - apt.git/blob - apt-private/acqprogress.cc
dcc538a3969b4eb168b14244827c178b668df4fc
[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 enum {Long = 0,Medium,Short} Mode = Medium;
180
181 std::string Line;
182 {
183 std::stringstream S;
184 for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
185 I = Owner->WorkerStep(I))
186 {
187 // There is no item running
188 if (I->CurrentItem == 0)
189 {
190 if (I->Status.empty() == false)
191 S << " [" << I->Status << "]";
192
193 continue;
194 }
195
196 // Add in the short description
197 S << " [";
198 if (I->CurrentItem->Owner->ID != 0)
199 S << I->CurrentItem->Owner->ID << " ";
200 S << I->CurrentItem->ShortDesc;
201
202 // Show the short mode string
203 if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
204 S << " " << I->CurrentItem->Owner->ActiveSubprocess;
205
206 // Add the current progress
207 if (Mode == Long)
208 S << " " << I->CurrentSize;
209 else
210 {
211 if (Mode == Medium || I->TotalSize == 0)
212 S << " " << SizeToStr(I->CurrentSize) << "B";
213 }
214
215 // Add the total size and percent
216 if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
217 {
218 if (Mode == Short)
219 ioprintf(S, " %.0f%%", (I->CurrentSize*100.0)/I->TotalSize);
220 else
221 ioprintf(S, "/%sB %.0f%%", SizeToStr(I->TotalSize).c_str(),
222 (I->CurrentSize*100.0)/I->TotalSize);
223 }
224 S << "]";
225 }
226
227 // Show at least something
228 Line = S.str();
229 S.clear();
230 if (Line.empty() == true)
231 Line = _(" [Working]");
232 }
233 // Put in the percent done
234 {
235 std::stringstream S;
236 ioprintf(S, "%.0f%%", Percent);
237 S << Line;
238 Line = S.str();
239 S.clear();
240 }
241
242 /* Put in the ETA and cps meter, block off signals to prevent strangeness
243 during resizing */
244 sigset_t Sigs,OldSigs;
245 sigemptyset(&Sigs);
246 sigaddset(&Sigs,SIGWINCH);
247 sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
248
249 if (CurrentCPS != 0)
250 {
251 unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
252 std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA);
253 size_t alignment = Line.length() + Tmp.length();
254 if (alignment < ScreenWidth)
255 {
256 alignment = ScreenWidth - alignment;
257 for (size_t i = 0; i < alignment; ++i)
258 Line.append(" ");
259 Line.append(Tmp);
260 }
261 }
262 if (Line.length() > ScreenWidth)
263 Line.erase(ScreenWidth);
264 sigprocmask(SIG_SETMASK,&OldSigs,0);
265
266 // Draw the current status
267 if (_config->FindB("Apt::Color", false) == true)
268 out << _config->Find("APT::Color::Yellow");
269 if (LastLineLength > Line.length())
270 clearLastLine();
271 else
272 out << '\r';
273 out << Line << std::flush;
274 if (_config->FindB("Apt::Color", false) == true)
275 out << _config->Find("APT::Color::Neutral") << std::flush;
276
277 LastLineLength = Line.length();
278 Update = false;
279
280 return true;
281 }
282 /*}}}*/
283 // AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/
284 // ---------------------------------------------------------------------
285 /* Prompt for a media swap */
286 bool AcqTextStatus::MediaChange(std::string Media, std::string Drive)
287 {
288 // If we do not output on a terminal and one of the options to avoid user
289 // interaction is given, we assume that no user is present who could react
290 // on your media change request
291 if (isatty(STDOUT_FILENO) != 1 && Quiet >= 2 &&
292 (_config->FindB("APT::Get::Assume-Yes",false) == true ||
293 _config->FindB("APT::Get::Force-Yes",false) == true ||
294 _config->FindB("APT::Get::Trivial-Only",false) == true))
295
296 return false;
297
298 clearLastLine();
299 ioprintf(out,_("Media change: please insert the disc labeled\n"
300 " '%s'\n"
301 "in the drive '%s' and press [Enter]\n"),
302 Media.c_str(),Drive.c_str());
303
304 char C = 0;
305 bool bStatus = true;
306 while (C != '\n' && C != '\r')
307 {
308 int len = read(STDIN_FILENO,&C,1);
309 if(C == 'c' || len <= 0)
310 bStatus = false;
311 }
312
313 if(bStatus)
314 Update = true;
315 return bStatus;
316 }
317 /*}}}*/
318 void AcqTextStatus::clearLastLine() { /*{{{*/
319 if (Quiet > 0 || LastLineLength == 0)
320 return;
321
322 // do not try to clear more than the (now smaller) screen
323 if (LastLineLength > ScreenWidth)
324 LastLineLength = ScreenWidth;
325
326 out << '\r';
327 for (size_t i = 0; i < LastLineLength; ++i)
328 out << ' ';
329 out << '\r' << std::flush;
330 }
331 /*}}}*/