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