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>
17 /* Return a APT::Progress::PackageManager based on the global
18 * apt configuration (i.e. APT::Status-Fd and APT::Status-deb822-Fd)
20 PackageManager
* PackageManagerProgressFactory()
22 // select the right progress
23 int status_fd
= _config
->FindI("APT::Status-Fd", -1);
24 int status_deb822_fd
= _config
->FindI("APT::Status-deb822-Fd", -1);
26 APT::Progress::PackageManager
*progress
= NULL
;
27 if (status_deb822_fd
> 0)
28 progress
= new APT::Progress::PackageManagerProgressDeb822Fd(
30 else if (status_fd
> 0)
31 progress
= new APT::Progress::PackageManagerProgressFd(status_fd
);
32 else if(_config
->FindB("Dpkg::Progress-Fancy", false) == true)
33 progress
= new APT::Progress::PackageManagerFancy();
34 else if (_config
->FindB("Dpkg::Progress",
35 _config
->FindB("DpkgPM::Progress", false)) == true)
36 progress
= new APT::Progress::PackageManagerText();
38 progress
= new APT::Progress::PackageManager();
42 bool PackageManager::StatusChanged(std::string PackageName
,
43 unsigned int StepsDone
,
44 unsigned int TotalSteps
,
45 std::string HumanReadableAction
)
47 int reporting_steps
= _config
->FindI("DpkgPM::Reporting-Steps", 1);
48 percentage
= StepsDone
/(float)TotalSteps
* 100.0;
49 strprintf(progress_str
, _("Progress: [%3i%%]"), (int)percentage
);
51 if(percentage
< (last_reported_progress
+ reporting_steps
))
57 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd
)
58 : StepsDone(0), StepsTotal(1)
60 OutStatusFd
= progress_fd
;
63 void PackageManagerProgressFd::WriteToStatusFd(std::string s
)
67 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
70 void PackageManagerProgressFd::StartDpkg()
75 // FIXME: use SetCloseExec here once it taught about throwing
76 // exceptions instead of doing _exit(100) on failure
77 fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);
79 // send status information that we are about to fork dpkg
80 std::ostringstream status
;
81 status
<< "pmstatus:dpkg-exec:"
82 << (StepsDone
/float(StepsTotal
)*100.0)
83 << ":" << _("Running dpkg")
85 WriteToStatusFd(status
.str());
88 void PackageManagerProgressFd::Stop()
92 void PackageManagerProgressFd::Error(std::string PackageName
,
93 unsigned int StepsDone
,
94 unsigned int TotalSteps
,
95 std::string ErrorMessage
)
97 std::ostringstream status
;
98 status
<< "pmerror:" << PackageName
99 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
100 << ":" << ErrorMessage
102 WriteToStatusFd(status
.str());
105 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName
,
106 unsigned int StepsDone
,
107 unsigned int TotalSteps
,
108 std::string ConfMessage
)
110 std::ostringstream status
;
111 status
<< "pmconffile:" << PackageName
112 << ":" << (StepsDone
/float(TotalSteps
)*100.0)
113 << ":" << ConfMessage
115 WriteToStatusFd(status
.str());
119 bool PackageManagerProgressFd::StatusChanged(std::string PackageName
,
120 unsigned int xStepsDone
,
121 unsigned int xTotalSteps
,
122 std::string pkg_action
)
124 StepsDone
= xStepsDone
;
125 StepsTotal
= xTotalSteps
;
127 // build the status str
128 std::ostringstream status
;
129 status
<< "pmstatus:" << StringSplit(PackageName
, ":")[0]
130 << ":" << (StepsDone
/float(StepsTotal
)*100.0)
133 WriteToStatusFd(status
.str());
135 if(_config
->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
136 std::cerr
<< "progress: " << PackageName
<< " " << xStepsDone
137 << " " << xTotalSteps
<< " " << pkg_action
145 PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd
)
146 : StepsDone(0), StepsTotal(1)
148 OutStatusFd
= progress_fd
;
151 void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s
)
153 FileFd::Write(OutStatusFd
, s
.c_str(), s
.size());
156 void PackageManagerProgressDeb822Fd::StartDpkg()
158 // FIXME: use SetCloseExec here once it taught about throwing
159 // exceptions instead of doing _exit(100) on failure
160 fcntl(OutStatusFd
,F_SETFD
,FD_CLOEXEC
);
162 // send status information that we are about to fork dpkg
163 std::ostringstream status
;
164 status
<< "Status: " << "progress" << std::endl
165 << "Percent: " << (StepsDone
/float(StepsTotal
)*100.0) << std::endl
166 << "Message: " << _("Running dpkg") << std::endl
168 WriteToStatusFd(status
.str());
171 void PackageManagerProgressDeb822Fd::Stop()
175 void PackageManagerProgressDeb822Fd::Error(std::string PackageName
,
176 unsigned int StepsDone
,
177 unsigned int TotalSteps
,
178 std::string ErrorMessage
)
180 std::ostringstream status
;
181 status
<< "Status: " << "Error" << std::endl
182 << "Package:" << PackageName
<< std::endl
183 << "Percent: " << (StepsDone
/float(TotalSteps
)*100.0) << std::endl
184 << "Message: " << ErrorMessage
<< std::endl
186 WriteToStatusFd(status
.str());
189 void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName
,
190 unsigned int StepsDone
,
191 unsigned int TotalSteps
,
192 std::string ConfMessage
)
194 std::ostringstream status
;
195 status
<< "Status: " << "ConfFile" << std::endl
196 << "Package:" << PackageName
<< std::endl
197 << "Percent: " << (StepsDone
/float(TotalSteps
)*100.0) << std::endl
198 << "Message: " << ConfMessage
<< std::endl
200 WriteToStatusFd(status
.str());
204 bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName
,
205 unsigned int xStepsDone
,
206 unsigned int xTotalSteps
,
209 StepsDone
= xStepsDone
;
210 StepsTotal
= xTotalSteps
;
212 // build the status str
213 std::ostringstream status
;
214 status
<< "Status: " << "progress" << std::endl
215 << "Package: " << PackageName
<< std::endl
216 << "Percent: " << (StepsDone
/float(StepsTotal
)*100.0) << std::endl
217 << "Message: " << message
<< std::endl
219 WriteToStatusFd(status
.str());
225 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows
)
227 // scroll down a bit to avoid visual glitch when the screen
228 // area shrinks by one row
232 std::cout
<< "\033[s";
234 // set scroll region (this will place the cursor in the top left)
235 std::cout
<< "\033[1;" << nr_rows
- 1 << "r";
237 // restore cursor but ensure its inside the scrolling area
238 std::cout
<< "\033[u";
239 static const char *move_cursor_up
= "\033[1A";
240 std::cout
<< move_cursor_up
;
242 // setup env for (hopefully!) ncurses
244 strprintf(s
, "%i", nr_rows
);
245 setenv("LINES", s
.c_str(), 1);
247 std::flush(std::cout
);
250 PackageManagerFancy::PackageManagerFancy()
251 : nr_terminal_rows(-1)
254 if(ioctl(STDOUT_FILENO
, TIOCGWINSZ
, (char *)&win
) == 0)
256 nr_terminal_rows
= win
.ws_row
;
260 void PackageManagerFancy::Start()
262 if (nr_terminal_rows
> 0)
263 SetupTerminalScrollArea(nr_terminal_rows
);
266 void PackageManagerFancy::Stop()
268 if (nr_terminal_rows
> 0)
270 SetupTerminalScrollArea(nr_terminal_rows
+ 1);
272 // override the progress line (sledgehammer)
273 static const char* clear_screen_below_cursor
= "\033[J";
274 std::cout
<< clear_screen_below_cursor
;
278 bool PackageManagerFancy::StatusChanged(std::string PackageName
,
279 unsigned int StepsDone
,
280 unsigned int TotalSteps
,
281 std::string HumanReadableAction
)
283 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
,
284 HumanReadableAction
))
287 int row
= nr_terminal_rows
;
289 static string save_cursor
= "\033[s";
290 static string restore_cursor
= "\033[u";
292 static string set_bg_color
= "\033[42m"; // green
293 static string set_fg_color
= "\033[30m"; // black
295 static string restore_bg
= "\033[49m";
296 static string restore_fg
= "\033[39m";
298 std::cout
<< save_cursor
299 // move cursor position to last row
300 << "\033[" << row
<< ";0f"
307 std::flush(std::cout
);
308 last_reported_progress
= percentage
;
313 bool PackageManagerText::StatusChanged(std::string PackageName
,
314 unsigned int StepsDone
,
315 unsigned int TotalSteps
,
316 std::string HumanReadableAction
)
318 if (!PackageManager::StatusChanged(PackageName
, StepsDone
, TotalSteps
, HumanReadableAction
))
321 std::cout
<< progress_str
<< "\r\n";
322 std::flush(std::cout
);
324 last_reported_progress
= percentage
;
331 }; // namespace progress