add new pid_t ExecFork(std::set<int> KeepFDs) to get rid of the super ugly APT::Keep...
[ntk/apt.git] / apt-pkg / install-progress.cc
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
13 namespace APT {
14 namespace Progress {
15
16 PackageManager* PackageManagerProgressFactory()
17 {
18 // select the right progress
19 int status_fd = _config->FindI("APT::Status-Fd", -1);
20 int status_deb822_fd = _config->FindI("APT::Status-deb822-Fd", -1);
21
22 APT::Progress::PackageManager *progress = NULL;
23 if (status_deb822_fd > 0)
24 progress = new APT::Progress::PackageManagerProgressDeb822Fd(
25 status_deb822_fd);
26 else if (status_fd > 0)
27 progress = new APT::Progress::PackageManagerProgressFd(status_fd);
28 else if(_config->FindB("Dpkg::Progress-Fancy", false) == true)
29 progress = new APT::Progress::PackageManagerFancy();
30 else if (_config->FindB("Dpkg::Progress",
31 _config->FindB("DpkgPM::Progress", false)) == true)
32 progress = new APT::Progress::PackageManagerText();
33 else
34 progress = new APT::Progress::PackageManager();
35 return progress;
36 }
37
38 bool PackageManager::StatusChanged(std::string PackageName,
39 unsigned int StepsDone,
40 unsigned int TotalSteps,
41 std::string HumanReadableAction)
42 {
43 int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1);
44 percentage = StepsDone/(float)TotalSteps * 100.0;
45 strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage);
46
47 if(percentage < (last_reported_progress + reporting_steps))
48 return false;
49
50 return true;
51 }
52
53 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd)
54 : StepsDone(0), StepsTotal(1)
55 {
56 OutStatusFd = progress_fd;
57 }
58
59 void PackageManagerProgressFd::WriteToStatusFd(std::string s)
60 {
61 if(OutStatusFd <= 0)
62 return;
63 FileFd::Write(OutStatusFd, s.c_str(), s.size());
64 }
65
66 void PackageManagerProgressFd::StartDpkg()
67 {
68 if(OutStatusFd <= 0)
69 return;
70
71 // FIXME: use SetCloseExec here once it taught about throwing
72 // exceptions instead of doing _exit(100) on failure
73 fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC);
74
75 // send status information that we are about to fork dpkg
76 std::ostringstream status;
77 status << "pmstatus:dpkg-exec:"
78 << (StepsDone/float(StepsTotal)*100.0)
79 << ":" << _("Running dpkg")
80 << std::endl;
81 WriteToStatusFd(status.str());
82 }
83
84 void PackageManagerProgressFd::Stop()
85 {
86 }
87
88 void PackageManagerProgressFd::Error(std::string PackageName,
89 unsigned int StepsDone,
90 unsigned int TotalSteps,
91 std::string ErrorMessage)
92 {
93 std::ostringstream status;
94 status << "pmerror:" << PackageName
95 << ":" << (StepsDone/float(TotalSteps)*100.0)
96 << ":" << ErrorMessage
97 << std::endl;
98 WriteToStatusFd(status.str());
99 }
100
101 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName,
102 unsigned int StepsDone,
103 unsigned int TotalSteps,
104 std::string ConfMessage)
105 {
106 std::ostringstream status;
107 status << "pmconffile:" << PackageName
108 << ":" << (StepsDone/float(TotalSteps)*100.0)
109 << ":" << ConfMessage
110 << std::endl;
111 WriteToStatusFd(status.str());
112 }
113
114
115 bool PackageManagerProgressFd::StatusChanged(std::string PackageName,
116 unsigned int xStepsDone,
117 unsigned int xTotalSteps,
118 std::string pkg_action)
119 {
120 StepsDone = xStepsDone;
121 StepsTotal = xTotalSteps;
122
123 // build the status str
124 std::ostringstream status;
125 status << "pmstatus:" << StringSplit(PackageName, ":")[0]
126 << ":" << (StepsDone/float(StepsTotal)*100.0)
127 << ":" << pkg_action
128 << std::endl;
129 WriteToStatusFd(status.str());
130
131 if(_config->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
132 std::cerr << "progress: " << PackageName << " " << xStepsDone
133 << " " << xTotalSteps << " " << pkg_action
134 << std::endl;
135
136
137 return true;
138 }
139
140
141 PackageManagerProgressDeb822Fd::PackageManagerProgressDeb822Fd(int progress_fd)
142 : StepsDone(0), StepsTotal(1)
143 {
144 OutStatusFd = progress_fd;
145 }
146
147 void PackageManagerProgressDeb822Fd::WriteToStatusFd(std::string s)
148 {
149 FileFd::Write(OutStatusFd, s.c_str(), s.size());
150 }
151
152 void PackageManagerProgressDeb822Fd::Start()
153 {
154 // FIXME: use SetCloseExec here once it taught about throwing
155 // exceptions instead of doing _exit(100) on failure
156 fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC);
157
158 // send status information that we are about to fork dpkg
159 std::ostringstream status;
160 status << "Status: " << "progress" << std::endl
161 << "Percent: " << (StepsDone/float(StepsTotal)*100.0) << std::endl
162 << "Message: " << _("Running dpkg") << std::endl
163 << std::endl;
164 WriteToStatusFd(status.str());
165 }
166
167 void PackageManagerProgressDeb822Fd::Stop()
168 {
169 }
170
171 void PackageManagerProgressDeb822Fd::Error(std::string PackageName,
172 unsigned int StepsDone,
173 unsigned int TotalSteps,
174 std::string ErrorMessage)
175 {
176 std::ostringstream status;
177 status << "Status: " << "Error" << std::endl
178 << "Package:" << PackageName << std::endl
179 << "Percent: " << (StepsDone/float(TotalSteps)*100.0) << std::endl
180 << "Message: " << ErrorMessage << std::endl
181 << std::endl;
182 WriteToStatusFd(status.str());
183 }
184
185 void PackageManagerProgressDeb822Fd::ConffilePrompt(std::string PackageName,
186 unsigned int StepsDone,
187 unsigned int TotalSteps,
188 std::string ConfMessage)
189 {
190 std::ostringstream status;
191 status << "Status: " << "ConfFile" << std::endl
192 << "Package:" << PackageName << std::endl
193 << "Percent: " << (StepsDone/float(TotalSteps)*100.0) << std::endl
194 << "Message: " << ConfMessage << std::endl
195 << std::endl;
196 WriteToStatusFd(status.str());
197 }
198
199
200 bool PackageManagerProgressDeb822Fd::StatusChanged(std::string PackageName,
201 unsigned int xStepsDone,
202 unsigned int xTotalSteps,
203 std::string message)
204 {
205 StepsDone = xStepsDone;
206 StepsTotal = xTotalSteps;
207
208 // build the status str
209 std::ostringstream status;
210 status << "Status: " << "progress" << std::endl
211 << "Package: " << PackageName << std::endl
212 << "Percent: " << (StepsDone/float(StepsTotal)*100.0) << std::endl
213 << "Message: " << message << std::endl
214 << std::endl;
215 WriteToStatusFd(status.str());
216
217 return true;
218 }
219
220
221 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
222 {
223 // scroll down a bit to avoid visual glitch when the screen
224 // area shrinks by one row
225 std::cout << "\n";
226
227 // save cursor
228 std::cout << "\033[s";
229
230 // set scroll region (this will place the cursor in the top left)
231 std::cout << "\033[1;" << nr_rows - 1 << "r";
232
233 // restore cursor but ensure its inside the scrolling area
234 std::cout << "\033[u";
235 static const char *move_cursor_up = "\033[1A";
236 std::cout << move_cursor_up;
237
238 std::flush(std::cout);
239 }
240
241 PackageManagerFancy::PackageManagerFancy()
242 : nr_terminal_rows(-1)
243 {
244 struct winsize win;
245 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) == 0)
246 {
247 nr_terminal_rows = win.ws_row;
248 }
249 }
250
251 void PackageManagerFancy::Start()
252 {
253 if (nr_terminal_rows > 0)
254 SetupTerminalScrollArea(nr_terminal_rows);
255 }
256
257 void PackageManagerFancy::Stop()
258 {
259 if (nr_terminal_rows > 0)
260 {
261 SetupTerminalScrollArea(nr_terminal_rows + 1);
262
263 // override the progress line (sledgehammer)
264 static const char* clear_screen_below_cursor = "\033[J";
265 std::cout << clear_screen_below_cursor;
266 }
267 }
268
269 bool PackageManagerFancy::StatusChanged(std::string PackageName,
270 unsigned int StepsDone,
271 unsigned int TotalSteps,
272 std::string HumanReadableAction)
273 {
274 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps,
275 HumanReadableAction))
276 return false;
277
278 int row = nr_terminal_rows;
279
280 static string save_cursor = "\033[s";
281 static string restore_cursor = "\033[u";
282
283 static string set_bg_color = "\033[42m"; // green
284 static string set_fg_color = "\033[30m"; // black
285
286 static string restore_bg = "\033[49m";
287 static string restore_fg = "\033[39m";
288
289 std::cout << save_cursor
290 // move cursor position to last row
291 << "\033[" << row << ";0f"
292 << set_bg_color
293 << set_fg_color
294 << progress_str
295 << restore_cursor
296 << restore_bg
297 << restore_fg;
298 std::flush(std::cout);
299 last_reported_progress = percentage;
300
301 return true;
302 }
303
304 bool PackageManagerText::StatusChanged(std::string PackageName,
305 unsigned int StepsDone,
306 unsigned int TotalSteps,
307 std::string HumanReadableAction)
308 {
309 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction))
310 return false;
311
312 std::cout << progress_str << "\r\n";
313 std::flush(std::cout);
314
315 last_reported_progress = percentage;
316
317 return true;
318 }
319
320
321
322 }; // namespace progress
323 }; // namespace apt