]> git.saurik.com Git - apt.git/blame - apt-private/acqprogress.cc
Merge remote-tracking branch 'donkult/debian/experimental' into debian/experimental
[apt.git] / apt-private / acqprogress.cc
CommitLineData
b9179170
MV
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b9179170
MV
3/* ######################################################################
4
dfad5bee
DK
5 Acquire Progress - Command line progress meter
6
b9179170
MV
7 ##################################################################### */
8 /*}}}*/
9// Include files /*{{{*/
10#include<config.h>
11
453b82a3 12#include <apt-pkg/acquire.h>
b9179170
MV
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
453b82a3
DK
19#include <apt-private/acqprogress.h>
20
21#include <string.h>
b9179170
MV
22#include <stdio.h>
23#include <signal.h>
24#include <iostream>
b8eba208 25#include <sstream>
b9179170
MV
26#include <unistd.h>
27
b9179170
MV
28#include <apti18n.h>
29 /*}}}*/
30
b9179170
MV
31// AcqTextStatus::AcqTextStatus - Constructor /*{{{*/
32// ---------------------------------------------------------------------
33/* */
dfad5bee
DK
34AcqTextStatus::AcqTextStatus(std::ostream &out, unsigned int &ScreenWidth,unsigned int const Quiet) :
35 pkgAcquireStatus(), out(out), ScreenWidth(ScreenWidth), LastLineLength(0), ID(0), Quiet(Quiet)
b9179170 36{
18cce398
DK
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;
2b0660b5
DK
40 if (Quiet < 2 && _config->FindB("quiet::NoProgress", false) == true)
41 this->Quiet = 2;
b9179170
MV
42}
43 /*}}}*/
44// AcqTextStatus::Start - Downloading has started /*{{{*/
45// ---------------------------------------------------------------------
46/* */
d3e8fbb3 47void AcqTextStatus::Start()
b9179170 48{
d3e8fbb3 49 pkgAcquireStatus::Start();
b8eba208 50 LastLineLength = 0;
b9179170 51 ID = 1;
d3e8fbb3 52}
b9179170 53 /*}}}*/
1eb1836f
DK
54void 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 /*}}}*/
b9179170
MV
64// AcqTextStatus::IMSHit - Called when an item got a HIT response /*{{{*/
65// ---------------------------------------------------------------------
66/* */
67void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
68{
69 if (Quiet > 1)
70 return;
71
1eb1836f 72 AssignItemID(Itm);
b8eba208 73 clearLastLine();
d3e8fbb3 74
1eb1836f
DK
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());
dfad5bee 77 out << std::endl;
b9179170 78 Update = true;
d3e8fbb3 79}
b9179170
MV
80 /*}}}*/
81// AcqTextStatus::Fetch - An item has started to download /*{{{*/
82// ---------------------------------------------------------------------
83/* This prints out the short description and the expected size */
84void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
85{
86 Update = true;
87 if (Itm.Owner->Complete == true)
88 return;
1eb1836f 89 AssignItemID(Itm);
d3e8fbb3 90
b9179170
MV
91 if (Quiet > 1)
92 return;
93
b8eba208 94 clearLastLine();
d3e8fbb3 95
1eb1836f
DK
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());
b9179170 99 if (Itm.Owner->FileSize != 0)
dfad5bee
DK
100 out << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
101 out << std::endl;
d3e8fbb3 102}
b9179170
MV
103 /*}}}*/
104// AcqTextStatus::Done - Completed a download /*{{{*/
105// ---------------------------------------------------------------------
106/* We don't display anything... */
1eb1836f 107void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm)
b9179170
MV
108{
109 Update = true;
1eb1836f 110 AssignItemID(Itm);
d3e8fbb3 111}
b9179170
MV
112 /*}}}*/
113// AcqTextStatus::Fail - Called when an item fails to download /*{{{*/
114// ---------------------------------------------------------------------
115/* We print out the error text */
116void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
117{
118 if (Quiet > 1)
119 return;
120
1eb1836f 121 AssignItemID(Itm);
b8eba208 122 clearLastLine();
d3e8fbb3 123
9d2a8a73 124 if (Itm.Owner->Status == pkgAcquire::Item::StatDone || Itm.Owner->Status == pkgAcquire::Item::StatIdle)
b9179170 125 {
1eb1836f
DK
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());
d6cf2345
DK
129 if (Itm.Owner->ErrorText.empty() == false &&
130 _config->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == true)
1eb1836f
DK
131 out << std::endl << " " << Itm.Owner->ErrorText;
132 out << std::endl;
b9179170
MV
133 }
134 else
135 {
1eb1836f
DK
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;
b9179170 140 }
d3e8fbb3 141
b9179170 142 Update = true;
d3e8fbb3 143}
b9179170
MV
144 /*}}}*/
145// AcqTextStatus::Stop - Finished downloading /*{{{*/
146// ---------------------------------------------------------------------
147/* This prints out the bytes downloaded and the overall average line
148 speed */
149void AcqTextStatus::Stop()
150{
151 pkgAcquireStatus::Stop();
152 if (Quiet > 1)
153 return;
154
b8eba208 155 clearLastLine();
b9179170 156
0c8171d7
DK
157 if (_config->FindB("quiet::NoStatistic", false) == true)
158 return;
159
b9179170 160 if (FetchedBytes != 0 && _error->PendingError() == false)
dfad5bee 161 ioprintf(out,_("Fetched %sB in %s (%sB/s)\n"),
b9179170
MV
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
dfad5bee 170 meter and a per active item status meter along with an overall
b9179170
MV
171 bandwidth and ETA indicator. */
172bool AcqTextStatus::Pulse(pkgAcquire *Owner)
173{
174 pkgAcquireStatus::Pulse(Owner);
d3e8fbb3 175
b9179170
MV
176 if (Quiet > 0)
177 return true;
d3e8fbb3 178
b8eba208 179 std::string Line;
b9179170 180 {
b8eba208
DK
181 std::stringstream S;
182 for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
183 I = Owner->WorkerStep(I))
b9179170 184 {
b8eba208
DK
185 // There is no item running
186 if (I->CurrentItem == 0)
b9179170 187 {
b8eba208
DK
188 if (I->Status.empty() == false)
189 S << " [" << I->Status << "]";
d3e8fbb3 190
b8eba208
DK
191 continue;
192 }
b9179170 193
b8eba208
DK
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;
d3e8fbb3 199
b8eba208
DK
200 // Show the short mode string
201 if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
202 S << " " << I->CurrentItem->Owner->ActiveSubprocess;
d3e8fbb3 203
258b9e51 204 enum {Long = 0,Medium,Short} Mode = Medium;
b8eba208
DK
205 // Add the current progress
206 if (Mode == Long)
207 S << " " << I->CurrentSize;
b9179170 208 else
b8eba208
DK
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(),
b9179170 221 (I->CurrentSize*100.0)/I->TotalSize);
b8eba208
DK
222 }
223 S << "]";
d3e8fbb3 224 }
b9179170 225
b8eba208
DK
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 }
d3e8fbb3 240
b9179170
MV
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);
d3e8fbb3 247
b9179170 248 if (CurrentCPS != 0)
d3e8fbb3 249 {
b9179170 250 unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
b8eba208
DK
251 std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA);
252 size_t alignment = Line.length() + Tmp.length();
253 if (alignment < ScreenWidth)
d3e8fbb3 254 {
b8eba208
DK
255 alignment = ScreenWidth - alignment;
256 for (size_t i = 0; i < alignment; ++i)
257 Line.append(" ");
258 Line.append(Tmp);
d3e8fbb3 259 }
b9179170 260 }
b8eba208
DK
261 if (Line.length() > ScreenWidth)
262 Line.erase(ScreenWidth);
b9179170
MV
263 sigprocmask(SIG_SETMASK,&OldSigs,0);
264
265 // Draw the current status
266 if (_config->FindB("Apt::Color", false) == true)
dfad5bee 267 out << _config->Find("APT::Color::Yellow");
b8eba208
DK
268 if (LastLineLength > Line.length())
269 clearLastLine();
b9179170 270 else
dfad5bee
DK
271 out << '\r';
272 out << Line << std::flush;
b9179170 273 if (_config->FindB("Apt::Color", false) == true)
dfad5bee 274 out << _config->Find("APT::Color::Neutral") << std::flush;
b9179170 275
b8eba208 276 LastLineLength = Line.length();
b9179170
MV
277 Update = false;
278
279 return true;
280}
281 /*}}}*/
282// AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/
283// ---------------------------------------------------------------------
284/* Prompt for a media swap */
dfad5bee 285bool AcqTextStatus::MediaChange(std::string Media, std::string Drive)
b9179170
MV
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
b8eba208 297 clearLastLine();
dfad5bee 298 ioprintf(out,_("Media change: please insert the disc labeled\n"
b9179170 299 " '%s'\n"
94171725 300 "in the drive '%s' and press [Enter]\n"),
b9179170
MV
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 /*}}}*/
b8eba208 317void AcqTextStatus::clearLastLine() { /*{{{*/
dfad5bee 318 if (Quiet > 0 || LastLineLength == 0)
b8eba208
DK
319 return;
320
321 // do not try to clear more than the (now smaller) screen
322 if (LastLineLength > ScreenWidth)
323 LastLineLength = ScreenWidth;
324
dfad5bee 325 out << '\r';
b8eba208 326 for (size_t i = 0; i < LastLineLength; ++i)
dfad5bee
DK
327 out << ' ';
328 out << '\r' << std::flush;
b8eba208
DK
329}
330 /*}}}*/