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