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>
18 /* Return a APT::Progress::PackageManager based on the global
19 * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)
21 PackageManager
* PackageManagerProgressFactory()
23 // select the right progress
24 int status_fd
= _config
->FindI("APT::Status-Fd", -1);
25 int status_deb822_fd
= _config
->FindI("APT::Status-deb822-Fd", -1);
27 APT::Progress::PackageManager
*progress
= NULL
;
28 if (status_deb822_fd
> 0)
29 progress
= new APT::Progress::PackageManagerProgressDeb822Fd(
31 else if (status_fd
> 0)
32 progress
= new APT::Progress::PackageManagerProgressFd(status_fd
);
33 else if(_config
->FindB("Dpkg::Progress-Fancy", false) == true)
34 progress
= new APT::Progress::PackageManagerFancy();
35 else if (_config
->FindB("Dpkg::Progress",
36 _config
->FindB("DpkgPM::Progress", false)) == true)
37 progress
= new APT::Progress::PackageManagerText();
39 progress
= new APT::Progress::PackageManager();
43 bool PackageManager::StatusChanged(std::string PackageName
,
44 unsigned int StepsDone
,
45 unsigned int TotalSteps
,
46 std::string HumanReadableAction
)
48 int reporting_steps
= _config
->FindI("DpkgPM::Reporting-Steps", 1);
49 percentage
= StepsDone
/(float)TotalSteps
* 100.0;
50 strprintf(progress_str
, _("Progress: [%3i%%]"), (int)percentage
);
52 if(percentage
< (last_reported_progress
+ reporting_steps
))
58 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd
)
59 : StepsDone(0), StepsTotal(1)
61 OutStatusFd
= progress_fd
;
64 void PackageManagerProgressFd::WriteToStatusFd(std::string s
)
68 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
71 void PackageManagerProgressFd::StartDpkg()
76 // FIXME: use SetCloseExec here once it taught about throwing
77 // exceptions instead of doing _exit(100) on failure
78 fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);
80 // send status information that we are about to fork dpkg
81 std::ostringstream status
;
82 status
<< "pmstatus:dpkg-exec:"
83 << (StepsDone
/float(StepsTotal
)*100.0)
84 << ":" << _("Running dpkg")
86 WriteToStatusFd(status
.str());
89 void PackageManagerProgressFd::Stop()
93 void PackageManagerProgressFd::Error(std::string PackageName
,
94 unsigned int StepsDone
,
95 unsigned int TotalSteps
,
96 std::string ErrorMessage
)
98 std::ostringstream status
;
99 status
<< "pmerror:" << PackageName
100 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
101 << ":" << ErrorMessage
103 WriteToStatusFd(status
.str());
106 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName
,
107 unsigned int StepsDone
,
108 unsigned int TotalSteps
,
109 std::string ConfMessage
)
111 std::ostringstream status
;
112 status
<< "pmconffile:" << PackageName
113 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
114 << ":" << ConfMessage
116 WriteToStatusFd(status
.str());
120 bool PackageManagerProgressFd::StatusChanged(std::string PackageName
,
121 unsigned int xStepsDone
,
122 unsigned int xTotalSteps
,
123 std::string pkg_action
)
125 StepsDone
= xStepsDone
;
126 StepsTotal
= xTotalSteps
;
128 // build the status str
129 std::ostringstream status
;
130 status
<< "pmstatus:" << StringSplit(PackageName
, ":")[0]
131 << ":" << (StepsDone
/float(StepsTotal
)*100.0)
134 WriteToStatusFd(status
.str());
136 if(_config
->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
137 std::cerr
<< "progress: " << PackageName
<< " " << xStepsDone
138 << " " << xTotalSteps
<< " " << pkg_action
146 PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd
)
147 : StepsDone(0), StepsTotal(1)
149 OutStatusFd
= progress_fd
;
152 void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s
)
154 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
157 void PackageManagerProgressDeb822Fd::StartDpkg()
159 // FIXME: use SetCloseExec here once it taught about throwing
160 // exceptions instead of doing _exit(100) on failure
161 fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);
163 // send status information that we are about to fork dpkg
164 std::ostringstream status
;
165 status
<< "Status: " << "progress" << std::endl
166 << "Percent: " << (StepsDone
/float(StepsTotal
)*100.0) << std::endl
167 << "Message: " << _("Running dpkg") << std::endl
169 WriteToStatusFd(status
.str());
172 void PackageManagerProgressDeb822Fd::Stop()
176 void PackageManagerProgressDeb822Fd::Error(std::string PackageName
,
177 unsigned int StepsDone
,
178 unsigned int TotalSteps
,
179 std::string ErrorMessage
)
181 std::ostringstream status
;
182 status
<< "Status: " << "Error" << std::endl
183 << "Package:" << PackageName
<< std::endl
184 << "Percent: " << (StepsDone
/float(TotalSteps
)*100.0) << std::endl
185 << "Message: " << ErrorMessage
<< std::endl
187 WriteToStatusFd(status
.str());
190 void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName
,
191 unsigned int StepsDone
,
192 unsigned int TotalSteps
,
193 std::string ConfMessage
)
195 std::ostringstream status
;
196 status
<< "Status: " << "ConfFile" << std::endl
197 << "Package:" << PackageName
<< std::endl
198 << "Percent: " << (StepsDone
/float(TotalSteps
)*100.0) << std::endl
199 << "Message: " << ConfMessage
<< std::endl
201 WriteToStatusFd(status
.str());
205 bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName
,
206 unsigned int xStepsDone
,
207 unsigned int xTotalSteps
,
210 StepsDone
= xStepsDone
;
211 StepsTotal
= xTotalSteps
;
213 // build the status str
214 std::ostringstream status
;
215 status
<< "Status: " << "progress" << std::endl
216 << "Package: " << PackageName
<< std::endl
217 << "Percent: " << (StepsDone
/float(StepsTotal
)*100.0) << std::endl
218 << "Message: " << message
<< std::endl
220 WriteToStatusFd(status
.str());
225 int PackageManagerFancy::GetNumberTerminalRows()
228 if(ioctl(STDOUT_FILENO
, TIOCGWINSZ
, (char *)&win
) != 0)
234 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows
)
236 // scroll down a bit to avoid visual glitch when the screen
237 // area shrinks by one row
241 std::cout
<< "\033[s";
243 // set scroll region (this will place the cursor in the top left)
244 std::cout
<< "\033[1;" << nr_rows
- 1 << "r";
246 // restore cursor but ensure its inside the scrolling area
247 std::cout
<< "\033[u";
248 static const char *move_cursor_up
= "\033[1A";
249 std::cout
<< move_cursor_up
;
251 // setup env for (hopefully!) ncurses
253 strprintf(s
, "%i", nr_rows
);
254 setenv("LINES", s
.c_str(), 1);
256 std::flush(std::cout
);
259 PackageManagerFancy::PackageManagerFancy()
261 // setup terminal size
262 old_SIGWINCH
= signal(SIGWINCH
, HandleSIGWINCH
);
265 PackageManagerFancy::~PackageManagerFancy()
267 signal(SIGWINCH
, old_SIGWINCH
);
270 void PackageManagerFancy::HandleSIGWINCH(int)
272 int nr_terminal_rows
= GetNumberTerminalRows();
273 SetupTerminalScrollArea(nr_terminal_rows
);
276 void PackageManagerFancy::Start()
278 int nr_terminal_rows
= GetNumberTerminalRows();
279 if (nr_terminal_rows
> 0)
280 SetupTerminalScrollArea(nr_terminal_rows
);
283 void PackageManagerFancy::Stop()
285 int nr_terminal_rows
= GetNumberTerminalRows();
286 if (nr_terminal_rows
> 0)
288 SetupTerminalScrollArea(nr_terminal_rows
+ 1);
290 // override the progress line (sledgehammer)
291 static const char* clear_screen_below_cursor
= "\033[J";
292 std::cout
<< clear_screen_below_cursor
;
296 bool PackageManagerFancy::StatusChanged(std::string PackageName
,
297 unsigned int StepsDone
,
298 unsigned int TotalSteps
,
299 std::string HumanReadableAction
)
301 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
,
302 HumanReadableAction
))
305 int row
= GetNumberTerminalRows();
307 static string save_cursor
= "\033[s";
308 static string restore_cursor
= "\033[u";
310 static string set_bg_color
= "\033[42m"; // green
311 static string set_fg_color
= "\033[30m"; // black
313 static string restore_bg
= "\033[49m";
314 static string restore_fg
= "\033[39m";
316 std::cout
<< save_cursor
317 // move cursor position to last row
318 << "\033[" << row
<< ";0f"
325 std::flush(std::cout
);
326 last_reported_progress
= percentage
;
331 bool PackageManagerText::StatusChanged(std::string PackageName
,
332 unsigned int StepsDone
,
333 unsigned int TotalSteps
,
334 std::string HumanReadableAction
)
336 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
, HumanReadableAction
))
339 std::cout
<< progress_str
<< "\r\n";
340 std::flush(std::cout
);
342 last_reported_progress
= percentage
;
349 }; // namespace progress