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>
19 /* Return a APT::Progress::PackageManager based on the global
20 * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)
22 PackageManager
* PackageManagerProgressFactory()
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);
28 APT::Progress::PackageManager
*progress
= NULL
;
29 if (status_deb822_fd
> 0)
30 progress
= new APT::Progress::PackageManagerProgressDeb822Fd(
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();
40 progress
= new APT::Progress::PackageManager();
44 bool PackageManager::StatusChanged(std::string PackageName
,
45 unsigned int StepsDone
,
46 unsigned int TotalSteps
,
47 std::string HumanReadableAction
)
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
);
53 if(percentage
< (last_reported_progress
+ reporting_steps
))
59 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd
)
60 : StepsDone(0), StepsTotal(1)
62 OutStatusFd
= progress_fd
;
65 void PackageManagerProgressFd::WriteToStatusFd(std::string s
)
69 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
72 void PackageManagerProgressFd::StartDpkg()
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
);
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")
87 WriteToStatusFd(status
.str());
90 void PackageManagerProgressFd::Stop()
94 void PackageManagerProgressFd::Error(std::string PackageName
,
95 unsigned int StepsDone
,
96 unsigned int TotalSteps
,
97 std::string ErrorMessage
)
99 std::ostringstream status
;
100 status
<< "pmerror:" << PackageName
101 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
102 << ":" << ErrorMessage
104 WriteToStatusFd(status
.str());
107 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName
,
108 unsigned int StepsDone
,
109 unsigned int TotalSteps
,
110 std::string ConfMessage
)
112 std::ostringstream status
;
113 status
<< "pmconffile:" << PackageName
114 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
115 << ":" << ConfMessage
117 WriteToStatusFd(status
.str());
121 bool PackageManagerProgressFd::StatusChanged(std::string PackageName
,
122 unsigned int xStepsDone
,
123 unsigned int xTotalSteps
,
124 std::string pkg_action
)
126 StepsDone
= xStepsDone
;
127 StepsTotal
= xTotalSteps
;
129 // build the status str
130 std::ostringstream status
;
131 status
<< "pmstatus:" << StringSplit(PackageName
, ":")[0]
132 << ":" << (StepsDone
/float(StepsTotal
)*100.0)
135 WriteToStatusFd(status
.str());
137 if(_config
->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
138 std::cerr
<< "progress: " << PackageName
<< " " << xStepsDone
139 << " " << xTotalSteps
<< " " << pkg_action
147 PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd
)
148 : StepsDone(0), StepsTotal(1)
150 OutStatusFd
= progress_fd
;
153 void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s
)
155 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
158 void PackageManagerProgressDeb822Fd::StartDpkg()
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
);
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
170 WriteToStatusFd(status
.str());
173 void PackageManagerProgressDeb822Fd::Stop()
177 void PackageManagerProgressDeb822Fd::Error(std::string PackageName
,
178 unsigned int StepsDone
,
179 unsigned int TotalSteps
,
180 std::string ErrorMessage
)
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
188 WriteToStatusFd(status
.str());
191 void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName
,
192 unsigned int StepsDone
,
193 unsigned int TotalSteps
,
194 std::string ConfMessage
)
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
202 WriteToStatusFd(status
.str());
206 bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName
,
207 unsigned int xStepsDone
,
208 unsigned int xTotalSteps
,
211 StepsDone
= xStepsDone
;
212 StepsTotal
= xTotalSteps
;
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
221 WriteToStatusFd(status
.str());
227 PackageManagerFancy::PackageManagerFancy()
230 // setup terminal size
231 old_SIGWINCH
= signal(SIGWINCH
, PackageManagerFancy::staticSIGWINCH
);
232 instances
.push_back(this);
234 std::vector
<PackageManagerFancy
*> PackageManagerFancy::instances
;
236 PackageManagerFancy::~PackageManagerFancy()
238 instances
.erase(find(instances
.begin(), instances
.end(), this));
239 signal(SIGWINCH
, old_SIGWINCH
);
242 void PackageManagerFancy::staticSIGWINCH(int signum
)
244 std::vector
<PackageManagerFancy
*>::const_iterator I
;
245 for(I
= instances
.begin(); I
!= instances
.end(); I
++)
246 (*I
)->HandleSIGWINCH(signum
);
249 int PackageManagerFancy::GetNumberTerminalRows()
252 // FIXME: get from "child_pty" instead?
253 if(ioctl(STDOUT_FILENO
, TIOCGWINSZ
, (char *)&win
) != 0)
256 if(_config
->FindB("Debug::InstallProgress::Fancy", false) == true)
257 std::cerr
<< "GetNumberTerminalRows: " << win
.ws_row
<< std::endl
;
262 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows
)
264 if(_config
->FindB("Debug::InstallProgress::Fancy", false) == true)
265 std::cerr
<< "SetupTerminalScrollArea: " << nr_rows
<< std::endl
;
267 // scroll down a bit to avoid visual glitch when the screen
268 // area shrinks by one row
272 std::cout
<< "\033[s";
274 // set scroll region (this will place the cursor in the top left)
275 std::cout
<< "\033[0;" << nr_rows
- 1 << "r";
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
;
282 // ensure its flushed
283 std::flush(std::cout
);
285 // setup tty size to ensure xterm/linux console are working properly too
288 ioctl(child_pty
, TIOCGWINSZ
, (char *)&win
);
289 win
.ws_row
= nr_rows
- 1;
290 ioctl(child_pty
, TIOCSWINSZ
, (char *)&win
);
293 void PackageManagerFancy::HandleSIGWINCH(int)
295 int nr_terminal_rows
= GetNumberTerminalRows();
296 SetupTerminalScrollArea(nr_terminal_rows
);
299 void PackageManagerFancy::Start(int a_child_pty
)
301 child_pty
= a_child_pty
;
302 int nr_terminal_rows
= GetNumberTerminalRows();
303 if (nr_terminal_rows
> 0)
304 SetupTerminalScrollArea(nr_terminal_rows
);
307 void PackageManagerFancy::Stop()
309 int nr_terminal_rows
= GetNumberTerminalRows();
310 if (nr_terminal_rows
> 0)
312 SetupTerminalScrollArea(nr_terminal_rows
+ 1);
314 // override the progress line (sledgehammer)
315 static const char* clear_screen_below_cursor
= "\033[J";
316 std::cout
<< clear_screen_below_cursor
;
321 bool PackageManagerFancy::StatusChanged(std::string PackageName
,
322 unsigned int StepsDone
,
323 unsigned int TotalSteps
,
324 std::string HumanReadableAction
)
326 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
,
327 HumanReadableAction
))
330 int row
= GetNumberTerminalRows();
332 static string save_cursor
= "\033[s";
333 static string restore_cursor
= "\033[u";
335 static string set_bg_color
= "\033[42m"; // green
336 static string set_fg_color
= "\033[30m"; // black
338 static string restore_bg
= "\033[49m";
339 static string restore_fg
= "\033[39m";
341 std::cout
<< save_cursor
342 // move cursor position to last row
343 << "\033[" << row
<< ";0f"
350 std::flush(std::cout
);
351 last_reported_progress
= percentage
;
356 bool PackageManagerText::StatusChanged(std::string PackageName
,
357 unsigned int StepsDone
,
358 unsigned int TotalSteps
,
359 std::string HumanReadableAction
)
361 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
, HumanReadableAction
))
364 std::cout
<< progress_str
<< "\r\n";
365 std::flush(std::cout
);
367 last_reported_progress
= percentage
;
374 }; // namespace progress