]>
git.saurik.com Git - apt.git/blob - apt-private/acqprogress.cc
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
5 Acquire Progress - Command line progress meter
7 ##################################################################### */
9 // Include files /*{{{*/
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>
19 #include <apt-private/acqprogress.h>
31 // AcqTextStatus::AcqTextStatus - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
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
)
37 // testcases use it to disable pulses without disabling other user messages
38 if (Quiet
== 0 && _config
->FindB("quiet::NoUpdate", false) == true)
40 if (Quiet
< 2 && _config
->FindB("quiet::NoProgress", false) == true)
44 // AcqTextStatus::Start - Downloading has started /*{{{*/
45 // ---------------------------------------------------------------------
47 void AcqTextStatus::Start()
49 pkgAcquireStatus::Start();
54 void AcqTextStatus::AssignItemID(pkgAcquire::ItemDesc
&Itm
) /*{{{*/
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)
64 // AcqTextStatus::IMSHit - Called when an item got a HIT response /*{{{*/
65 // ---------------------------------------------------------------------
67 void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc
&Itm
)
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());
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
)
87 if (Itm
.Owner
->Complete
== true)
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]";
104 // AcqTextStatus::Done - Completed a download /*{{{*/
105 // ---------------------------------------------------------------------
106 /* We don't display anything... */
107 void AcqTextStatus::Done(pkgAcquire::ItemDesc
&Itm
)
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
)
124 bool ShowErrorText
= true;
125 if (Itm
.Owner
->Status
== pkgAcquire::Item::StatDone
|| Itm
.Owner
->Status
== pkgAcquire::Item::StatIdle
)
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());
130 if (Itm
.Owner
->ErrorText
.empty() ||
131 _config
->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == false)
132 ShowErrorText
= false;
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());
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
)
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
);
161 // AcqTextStatus::Stop - Finished downloading /*{{{*/
162 // ---------------------------------------------------------------------
163 /* This prints out the bytes downloaded and the overall average line
165 void AcqTextStatus::Stop()
167 pkgAcquireStatus::Stop();
173 if (_config
->FindB("quiet::NoStatistic", false) == true)
176 if (FetchedBytes
!= 0 && _error
->PendingError() == false)
177 ioprintf(out
,_("Fetched %sB in %s (%sB/s)\n"),
178 SizeToStr(FetchedBytes
).c_str(),
179 TimeToStr(ElapsedTime
).c_str(),
180 SizeToStr(CurrentCPS
).c_str());
183 // AcqTextStatus::Pulse - Regular event pulse /*{{{*/
184 // ---------------------------------------------------------------------
185 /* This draws the current progress. Each line has an overall percent
186 meter and a per active item status meter along with an overall
187 bandwidth and ETA indicator. */
188 bool AcqTextStatus::Pulse(pkgAcquire
*Owner
)
190 pkgAcquireStatus::Pulse(Owner
);
198 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
199 I
= Owner
->WorkerStep(I
))
201 // There is no item running
202 if (I
->CurrentItem
== 0)
204 if (I
->Status
.empty() == false)
205 S
<< " [" << I
->Status
<< "]";
210 // Add in the short description
212 if (I
->CurrentItem
->Owner
->ID
!= 0)
213 S
<< std::to_string(I
->CurrentItem
->Owner
->ID
) << " ";
214 S
<< I
->CurrentItem
->ShortDesc
;
216 // Show the short mode string
217 if (I
->CurrentItem
->Owner
->ActiveSubprocess
.empty() == false)
218 S
<< " " << I
->CurrentItem
->Owner
->ActiveSubprocess
;
220 enum {Long
= 0,Medium
,Short
} Mode
= Medium
;
221 // Add the current progress
223 S
<< " " << std::to_string(I
->CurrentSize
);
226 if (Mode
== Medium
|| I
->TotalSize
== 0)
227 S
<< " " << SizeToStr(I
->CurrentSize
) << "B";
230 // Add the total size and percent
231 if (I
->TotalSize
> 0 && I
->CurrentItem
->Owner
->Complete
== false)
234 ioprintf(S
, " %.0f%%", (I
->CurrentSize
*100.0)/I
->TotalSize
);
236 ioprintf(S
, "/%sB %.0f%%", SizeToStr(I
->TotalSize
).c_str(),
237 (I
->CurrentSize
*100.0)/I
->TotalSize
);
242 // Show at least something
245 if (Line
.empty() == true)
246 Line
= _(" [Working]");
248 // Put in the percent done
251 ioprintf(S
, "%.0f%%", Percent
);
257 /* Put in the ETA and cps meter, block off signals to prevent strangeness
259 sigset_t Sigs
,OldSigs
;
261 sigaddset(&Sigs
,SIGWINCH
);
262 sigprocmask(SIG_BLOCK
,&Sigs
,&OldSigs
);
266 unsigned long long ETA
= (TotalBytes
- CurrentBytes
)/CurrentCPS
;
267 std::string Tmp
= " " + SizeToStr(CurrentCPS
) + "B/s " + TimeToStr(ETA
);
268 size_t alignment
= Line
.length() + Tmp
.length();
269 if (alignment
< ScreenWidth
)
271 alignment
= ScreenWidth
- alignment
;
272 for (size_t i
= 0; i
< alignment
; ++i
)
277 if (Line
.length() > ScreenWidth
)
278 Line
.erase(ScreenWidth
);
279 sigprocmask(SIG_SETMASK
,&OldSigs
,0);
281 // Draw the current status
282 if (_config
->FindB("Apt::Color", false) == true)
283 out
<< _config
->Find("APT::Color::Yellow");
284 if (LastLineLength
> Line
.length())
288 out
<< Line
<< std::flush
;
289 if (_config
->FindB("Apt::Color", false) == true)
290 out
<< _config
->Find("APT::Color::Neutral") << std::flush
;
292 LastLineLength
= Line
.length();
298 // AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/
299 // ---------------------------------------------------------------------
300 /* Prompt for a media swap */
301 bool AcqTextStatus::MediaChange(std::string Media
, std::string Drive
)
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))
314 ioprintf(out
,_("Media change: please insert the disc labeled\n"
316 "in the drive '%s' and press [Enter]\n"),
317 Media
.c_str(),Drive
.c_str());
321 while (C
!= '\n' && C
!= '\r')
323 int len
= read(STDIN_FILENO
,&C
,1);
324 if(C
== 'c' || len
<= 0)
333 void AcqTextStatus::clearLastLine() { /*{{{*/
334 if (Quiet
> 0 || LastLineLength
== 0)
337 // do not try to clear more than the (now smaller) screen
338 if (LastLineLength
> ScreenWidth
)
339 LastLineLength
= ScreenWidth
;
342 for (size_t i
= 0; i
< LastLineLength
; ++i
)
344 out
<< '\r' << std::flush
;