]> git.saurik.com Git - apt.git/blame - apt-private/acqprogress.cc
CMake: Add unit tests
[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
65633900 124 bool ShowErrorText = true;
9d2a8a73 125 if (Itm.Owner->Status == pkgAcquire::Item::StatDone || Itm.Owner->Status == pkgAcquire::Item::StatIdle)
b9179170 126 {
1eb1836f
DK
127 // TRANSLATOR: Very short word to be displayed for files in 'apt-get update'
128 // which failed to download, but the error is ignored (compare "Err:")
129 ioprintf(out, _("Ign:%lu %s"), Itm.Owner->ID, Itm.Description.c_str());
65633900
DK
130 if (Itm.Owner->ErrorText.empty() ||
131 _config->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == false)
132 ShowErrorText = false;
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());
b9179170 139 }
d3e8fbb3 140
65633900
DK
141 if (ShowErrorText)
142 {
143 std::string::size_type line_start = 0;
144 std::string::size_type line_end;
145 while ((line_end = Itm.Owner->ErrorText.find_first_of("\n\r", line_start)) != std::string::npos) {
146 out << std::endl << " " << Itm.Owner->ErrorText.substr(line_start, line_end - line_start);
147 line_start = Itm.Owner->ErrorText.find_first_not_of("\n\r", line_end + 1);
148 if (line_start == std::string::npos)
149 break;
150 }
151 if (line_start == 0)
152 out << std::endl << " " << Itm.Owner->ErrorText;
153 else if (line_start != std::string::npos)
154 out << std::endl << " " << Itm.Owner->ErrorText.substr(line_start);
155 }
156 out << std::endl;
157
b9179170 158 Update = true;
d3e8fbb3 159}
b9179170
MV
160 /*}}}*/
161// AcqTextStatus::Stop - Finished downloading /*{{{*/
162// ---------------------------------------------------------------------
163/* This prints out the bytes downloaded and the overall average line
164 speed */
165void AcqTextStatus::Stop()
166{
167 pkgAcquireStatus::Stop();
168 if (Quiet > 1)
169 return;
170
b8eba208 171 clearLastLine();
b9179170 172
0c8171d7
DK
173 if (_config->FindB("quiet::NoStatistic", false) == true)
174 return;
175
b9179170 176 if (FetchedBytes != 0 && _error->PendingError() == false)
dfad5bee 177 ioprintf(out,_("Fetched %sB in %s (%sB/s)\n"),
b9179170
MV
178 SizeToStr(FetchedBytes).c_str(),
179 TimeToStr(ElapsedTime).c_str(),
180 SizeToStr(CurrentCPS).c_str());
181}
182 /*}}}*/
183// AcqTextStatus::Pulse - Regular event pulse /*{{{*/
184// ---------------------------------------------------------------------
185/* This draws the current progress. Each line has an overall percent
dfad5bee 186 meter and a per active item status meter along with an overall
b9179170
MV
187 bandwidth and ETA indicator. */
188bool AcqTextStatus::Pulse(pkgAcquire *Owner)
189{
190 pkgAcquireStatus::Pulse(Owner);
d3e8fbb3 191
b9179170
MV
192 if (Quiet > 0)
193 return true;
d3e8fbb3 194
b8eba208 195 std::string Line;
b9179170 196 {
b8eba208
DK
197 std::stringstream S;
198 for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
199 I = Owner->WorkerStep(I))
b9179170 200 {
b8eba208
DK
201 // There is no item running
202 if (I->CurrentItem == 0)
b9179170 203 {
b8eba208
DK
204 if (I->Status.empty() == false)
205 S << " [" << I->Status << "]";
d3e8fbb3 206
b8eba208
DK
207 continue;
208 }
b9179170 209
b8eba208
DK
210 // Add in the short description
211 S << " [";
212 if (I->CurrentItem->Owner->ID != 0)
7303e11f 213 S << std::to_string(I->CurrentItem->Owner->ID) << " ";
b8eba208 214 S << I->CurrentItem->ShortDesc;
d3e8fbb3 215
b8eba208
DK
216 // Show the short mode string
217 if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false)
218 S << " " << I->CurrentItem->Owner->ActiveSubprocess;
d3e8fbb3 219
258b9e51 220 enum {Long = 0,Medium,Short} Mode = Medium;
b8eba208
DK
221 // Add the current progress
222 if (Mode == Long)
7303e11f 223 S << " " << std::to_string(I->CurrentSize);
b9179170 224 else
b8eba208
DK
225 {
226 if (Mode == Medium || I->TotalSize == 0)
227 S << " " << SizeToStr(I->CurrentSize) << "B";
228 }
229
230 // Add the total size and percent
231 if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
232 {
233 if (Mode == Short)
234 ioprintf(S, " %.0f%%", (I->CurrentSize*100.0)/I->TotalSize);
235 else
236 ioprintf(S, "/%sB %.0f%%", SizeToStr(I->TotalSize).c_str(),
b9179170 237 (I->CurrentSize*100.0)/I->TotalSize);
b8eba208
DK
238 }
239 S << "]";
d3e8fbb3 240 }
b9179170 241
b8eba208
DK
242 // Show at least something
243 Line = S.str();
244 S.clear();
245 if (Line.empty() == true)
246 Line = _(" [Working]");
247 }
248 // Put in the percent done
249 {
250 std::stringstream S;
251 ioprintf(S, "%.0f%%", Percent);
252 S << Line;
253 Line = S.str();
254 S.clear();
255 }
d3e8fbb3 256
b9179170
MV
257 /* Put in the ETA and cps meter, block off signals to prevent strangeness
258 during resizing */
259 sigset_t Sigs,OldSigs;
260 sigemptyset(&Sigs);
261 sigaddset(&Sigs,SIGWINCH);
262 sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
d3e8fbb3 263
b9179170 264 if (CurrentCPS != 0)
d3e8fbb3 265 {
b9179170 266 unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS;
b8eba208
DK
267 std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA);
268 size_t alignment = Line.length() + Tmp.length();
269 if (alignment < ScreenWidth)
d3e8fbb3 270 {
b8eba208
DK
271 alignment = ScreenWidth - alignment;
272 for (size_t i = 0; i < alignment; ++i)
273 Line.append(" ");
274 Line.append(Tmp);
d3e8fbb3 275 }
b9179170 276 }
b8eba208
DK
277 if (Line.length() > ScreenWidth)
278 Line.erase(ScreenWidth);
b9179170
MV
279 sigprocmask(SIG_SETMASK,&OldSigs,0);
280
281 // Draw the current status
282 if (_config->FindB("Apt::Color", false) == true)
dfad5bee 283 out << _config->Find("APT::Color::Yellow");
b8eba208
DK
284 if (LastLineLength > Line.length())
285 clearLastLine();
b9179170 286 else
dfad5bee
DK
287 out << '\r';
288 out << Line << std::flush;
b9179170 289 if (_config->FindB("Apt::Color", false) == true)
dfad5bee 290 out << _config->Find("APT::Color::Neutral") << std::flush;
b9179170 291
b8eba208 292 LastLineLength = Line.length();
b9179170
MV
293 Update = false;
294
295 return true;
296}
297 /*}}}*/
298// AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/
299// ---------------------------------------------------------------------
300/* Prompt for a media swap */
dfad5bee 301bool AcqTextStatus::MediaChange(std::string Media, std::string Drive)
b9179170
MV
302{
303 // If we do not output on a terminal and one of the options to avoid user
304 // interaction is given, we assume that no user is present who could react
305 // on your media change request
306 if (isatty(STDOUT_FILENO) != 1 && Quiet >= 2 &&
307 (_config->FindB("APT::Get::Assume-Yes",false) == true ||
308 _config->FindB("APT::Get::Force-Yes",false) == true ||
309 _config->FindB("APT::Get::Trivial-Only",false) == true))
310
311 return false;
312
b8eba208 313 clearLastLine();
dfad5bee 314 ioprintf(out,_("Media change: please insert the disc labeled\n"
b9179170 315 " '%s'\n"
94171725 316 "in the drive '%s' and press [Enter]\n"),
b9179170
MV
317 Media.c_str(),Drive.c_str());
318
319 char C = 0;
320 bool bStatus = true;
321 while (C != '\n' && C != '\r')
322 {
323 int len = read(STDIN_FILENO,&C,1);
324 if(C == 'c' || len <= 0)
325 bStatus = false;
326 }
327
328 if(bStatus)
329 Update = true;
330 return bStatus;
331}
332 /*}}}*/
b8eba208 333void AcqTextStatus::clearLastLine() { /*{{{*/
dfad5bee 334 if (Quiet > 0 || LastLineLength == 0)
b8eba208
DK
335 return;
336
337 // do not try to clear more than the (now smaller) screen
338 if (LastLineLength > ScreenWidth)
339 LastLineLength = ScreenWidth;
340
dfad5bee 341 out << '\r';
b8eba208 342 for (size_t i = 0; i < LastLineLength; ++i)
dfad5bee
DK
343 out << ' ';
344 out << '\r' << std::flush;
b8eba208
DK
345}
346 /*}}}*/