]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/install-progress.cc
warning: extra ‘;’ [-Wpedantic]
[apt.git] / apt-pkg / install-progress.cc
... / ...
CommitLineData
1#include <apt-pkg/configuration.h>
2#include <apt-pkg/fileutl.h>
3#include <apt-pkg/strutl.h>
4#include <apt-pkg/install-progress.h>
5
6#include <apti18n.h>
7
8#include <termios.h>
9#include <sys/ioctl.h>
10#include <sstream>
11#include <fcntl.h>
12#include <algorithm>
13#include <stdio.h>
14
15namespace APT {
16namespace Progress {
17
18
19/* Return a APT::Progress::PackageManager based on the global
20 * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)
21 */
22PackageManager* PackageManagerProgressFactory()
23{
24 // select the right progress
25 int status_fd = _config->FindI("APT::Status-Fd", -1);
26 int status_deb822_fd = _config->FindI("APT::Status-deb822-Fd", -1);
27
28 APT::Progress::PackageManager *progress = NULL;
29 if (status_deb822_fd > 0)
30 progress = new APT::Progress::PackageManagerProgressDeb822Fd(
31 status_deb822_fd);
32 else if (status_fd > 0)
33 progress = new APT::Progress::PackageManagerProgressFd(status_fd);
34 else if(_config->FindB("Dpkg::Progress-Fancy", false) == true)
35 progress = new APT::Progress::PackageManagerFancy();
36 else if (_config->FindB("Dpkg::Progress",
37 _config->FindB("DpkgPM::Progress", false)) == true)
38 progress = new APT::Progress::PackageManagerText();
39 else
40 progress = new APT::Progress::PackageManager();
41 return progress;
42}
43
44bool PackageManager::StatusChanged(std::string PackageName,
45 unsigned int StepsDone,
46 unsigned int TotalSteps,
47 std::string HumanReadableAction)
48{
49 int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1);
50 percentage = StepsDone/(float)TotalSteps * 100.0;
51 strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage);
52
53 if(percentage < (last_reported_progress + reporting_steps))
54 return false;
55
56 return true;
57}
58
59PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd)
60 : StepsDone(0), StepsTotal(1)
61{
62 OutStatusFd = progress_fd;
63}
64
65void PackageManagerProgressFd::WriteToStatusFd(std::string s)
66{
67 if(OutStatusFd <= 0)
68 return;
69 FileFd::Write(OutStatusFd, s.c_str(), s.size());
70}
71
72void PackageManagerProgressFd::StartDpkg()
73{
74 if(OutStatusFd <= 0)
75 return;
76
77 // FIXME: use SetCloseExec here once it taught about throwing
78 // exceptions instead of doing _exit(100) on failure
79 fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC);
80
81 // send status information that we are about to fork dpkg
82 std::ostringstream status;
83 status << "pmstatus:dpkg-exec:"
84 << (StepsDone/float(StepsTotal)*100.0)
85 << ":" << _("Running dpkg")
86 << std::endl;
87 WriteToStatusFd(status.str());
88}
89
90void PackageManagerProgressFd::Stop()
91{
92}
93
94void PackageManagerProgressFd::Error(std::string PackageName,
95 unsigned int StepsDone,
96 unsigned int TotalSteps,
97 std::string ErrorMessage)
98{
99 std::ostringstream status;
100 status << "pmerror:" << PackageName
101 << ":" << (StepsDone/float(TotalSteps)*100.0)
102 << ":" << ErrorMessage
103 << std::endl;
104 WriteToStatusFd(status.str());
105}
106
107void PackageManagerProgressFd::ConffilePrompt(std::string PackageName,
108 unsigned int StepsDone,
109 unsigned int TotalSteps,
110 std::string ConfMessage)
111{
112 std::ostringstream status;
113 status << "pmconffile:" << PackageName
114 << ":" << (StepsDone/float(TotalSteps)*100.0)
115 << ":" << ConfMessage
116 << std::endl;
117 WriteToStatusFd(status.str());
118}
119
120
121bool PackageManagerProgressFd::StatusChanged(std::string PackageName,
122 unsigned int xStepsDone,
123 unsigned int xTotalSteps,
124 std::string pkg_action)
125{
126 StepsDone = xStepsDone;
127 StepsTotal = xTotalSteps;
128
129 // build the status str
130 std::ostringstream status;
131 status << "pmstatus:" << StringSplit(PackageName, ":")[0]
132 << ":" << (StepsDone/float(StepsTotal)*100.0)
133 << ":" << pkg_action
134 << std::endl;
135 WriteToStatusFd(status.str());
136
137 if(_config->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
138 std::cerr << "progress: " << PackageName << " " << xStepsDone
139 << " " << xTotalSteps << " " << pkg_action
140 << std::endl;
141
142
143 return true;
144}
145
146
147PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd)
148 : StepsDone(0), StepsTotal(1)
149{
150 OutStatusFd = progress_fd;
151}
152
153void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s)
154{
155 FileFd::Write(OutStatusFd, s.c_str(), s.size());
156}
157
158void PackageManagerProgressDeb822Fd::StartDpkg()
159{
160 // FIXME: use SetCloseExec here once it taught about throwing
161 // exceptions instead of doing _exit(100) on failure
162 fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC);
163
164 // send status information that we are about to fork dpkg
165 std::ostringstream status;
166 status << "Status: " << "progress" << std::endl
167 << "Percent: " << (StepsDone/float(StepsTotal)*100.0) << std::endl
168 << "Message: " << _("Running dpkg") << std::endl
169 << std::endl;
170 WriteToStatusFd(status.str());
171}
172
173void PackageManagerProgressDeb822Fd::Stop()
174{
175}
176
177void PackageManagerProgressDeb822Fd::Error(std::string PackageName,
178 unsigned int StepsDone,
179 unsigned int TotalSteps,
180 std::string ErrorMessage)
181{
182 std::ostringstream status;
183 status << "Status: " << "Error" << std::endl
184 << "Package:" << PackageName << std::endl
185 << "Percent: " << (StepsDone/float(TotalSteps)*100.0) << std::endl
186 << "Message: " << ErrorMessage << std::endl
187 << std::endl;
188 WriteToStatusFd(status.str());
189}
190
191void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName,
192 unsigned int StepsDone,
193 unsigned int TotalSteps,
194 std::string ConfMessage)
195{
196 std::ostringstream status;
197 status << "Status: " << "ConfFile" << std::endl
198 << "Package:" << PackageName << std::endl
199 << "Percent: " << (StepsDone/float(TotalSteps)*100.0) << std::endl
200 << "Message: " << ConfMessage << std::endl
201 << std::endl;
202 WriteToStatusFd(status.str());
203}
204
205
206bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName,
207 unsigned int xStepsDone,
208 unsigned int xTotalSteps,
209 std::string message)
210{
211 StepsDone = xStepsDone;
212 StepsTotal = xTotalSteps;
213
214 // build the status str
215 std::ostringstream status;
216 status << "Status: " << "progress" << std::endl
217 << "Package: " << PackageName << std::endl
218 << "Percent: " << (StepsDone/float(StepsTotal)*100.0) << std::endl
219 << "Message: " << message << std::endl
220 << std::endl;
221 WriteToStatusFd(status.str());
222
223 return true;
224}
225
226
227PackageManagerFancy::PackageManagerFancy()
228 : child_pty(-1)
229{
230 // setup terminal size
231 old_SIGWINCH = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
232 instances.push_back(this);
233}
234std::vector<PackageManagerFancy*> PackageManagerFancy::instances;
235
236PackageManagerFancy::~PackageManagerFancy()
237{
238 instances.erase(find(instances.begin(), instances.end(), this));
239 signal(SIGWINCH, old_SIGWINCH);
240}
241
242void PackageManagerFancy::staticSIGWINCH(int signum)
243{
244 std::vector<PackageManagerFancy *>::const_iterator I;
245 for(I = instances.begin(); I != instances.end(); ++I)
246 (*I)->HandleSIGWINCH(signum);
247}
248
249int PackageManagerFancy::GetNumberTerminalRows()
250{
251 struct winsize win;
252 // FIXME: get from "child_pty" instead?
253 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) != 0)
254 return -1;
255
256 if(_config->FindB("Debug::InstallProgress::Fancy", false) == true)
257 std::cerr << "GetNumberTerminalRows: " << win.ws_row << std::endl;
258
259 return win.ws_row;
260}
261
262void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
263{
264 if(_config->FindB("Debug::InstallProgress::Fancy", false) == true)
265 std::cerr << "SetupTerminalScrollArea: " << nr_rows << std::endl;
266
267 // scroll down a bit to avoid visual glitch when the screen
268 // area shrinks by one row
269 std::cout << "\n";
270
271 // save cursor
272 std::cout << "\033[s";
273
274 // set scroll region (this will place the cursor in the top left)
275 std::cout << "\033[0;" << nr_rows - 1 << "r";
276
277 // restore cursor but ensure its inside the scrolling area
278 std::cout << "\033[u";
279 static const char *move_cursor_up = "\033[1A";
280 std::cout << move_cursor_up;
281
282 // ensure its flushed
283 std::flush(std::cout);
284
285 // setup tty size to ensure xterm/linux console are working properly too
286 // see bug #731738
287 struct winsize win;
288 ioctl(child_pty, TIOCGWINSZ, (char *)&win);
289 win.ws_row = nr_rows - 1;
290 ioctl(child_pty, TIOCSWINSZ, (char *)&win);
291}
292
293void PackageManagerFancy::HandleSIGWINCH(int)
294{
295 int nr_terminal_rows = GetNumberTerminalRows();
296 SetupTerminalScrollArea(nr_terminal_rows);
297}
298
299void PackageManagerFancy::Start(int a_child_pty)
300{
301 child_pty = a_child_pty;
302 int nr_terminal_rows = GetNumberTerminalRows();
303 if (nr_terminal_rows > 0)
304 SetupTerminalScrollArea(nr_terminal_rows);
305}
306
307void PackageManagerFancy::Stop()
308{
309 int nr_terminal_rows = GetNumberTerminalRows();
310 if (nr_terminal_rows > 0)
311 {
312 SetupTerminalScrollArea(nr_terminal_rows + 1);
313
314 // override the progress line (sledgehammer)
315 static const char* clear_screen_below_cursor = "\033[J";
316 std::cout << clear_screen_below_cursor;
317 }
318 child_pty = -1;
319}
320
321bool PackageManagerFancy::StatusChanged(std::string PackageName,
322 unsigned int StepsDone,
323 unsigned int TotalSteps,
324 std::string HumanReadableAction)
325{
326 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps,
327 HumanReadableAction))
328 return false;
329
330 int row = GetNumberTerminalRows();
331
332 static string save_cursor = "\033[s";
333 static string restore_cursor = "\033[u";
334
335 static string set_bg_color = "\033[42m"; // green
336 static string set_fg_color = "\033[30m"; // black
337
338 static string restore_bg = "\033[49m";
339 static string restore_fg = "\033[39m";
340
341 std::cout << save_cursor
342 // move cursor position to last row
343 << "\033[" << row << ";0f"
344 << set_bg_color
345 << set_fg_color
346 << progress_str
347 << restore_cursor
348 << restore_bg
349 << restore_fg;
350 std::flush(std::cout);
351 last_reported_progress = percentage;
352
353 return true;
354}
355
356bool PackageManagerText::StatusChanged(std::string PackageName,
357 unsigned int StepsDone,
358 unsigned int TotalSteps,
359 std::string HumanReadableAction)
360{
361 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction))
362 return false;
363
364 std::cout << progress_str << "\r\n";
365 std::flush(std::cout);
366
367 last_reported_progress = percentage;
368
369 return true;
370}
371
372
373
374} // namespace progress
375} // namespace apt