]> git.saurik.com Git - apt.git/blob - apt-pkg/install-progress.cc
b341fe6860302fc1a40fab341bf0c2d19c484952
[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::StartDpkg()
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 // setup env for (hopefully!) ncurses
239 string s;
240 strprintf(s, "%i", nr_rows);
241 setenv("LINES", s.c_str(), 1);
242
243 std::flush(std::cout);
244 }
245
246 PackageManagerFancy::PackageManagerFancy()
247 : nr_terminal_rows(-1)
248 {
249 struct winsize win;
250 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) == 0)
251 {
252 nr_terminal_rows = win.ws_row;
253 }
254 }
255
256 void PackageManagerFancy::Start()
257 {
258 if (nr_terminal_rows > 0)
259 SetupTerminalScrollArea(nr_terminal_rows);
260 }
261
262 void PackageManagerFancy::Stop()
263 {
264 if (nr_terminal_rows > 0)
265 {
266 SetupTerminalScrollArea(nr_terminal_rows + 1);
267
268 // override the progress line (sledgehammer)
269 static const char* clear_screen_below_cursor = "\033[J";
270 std::cout << clear_screen_below_cursor;
271 }
272 }
273
274 bool PackageManagerFancy::StatusChanged(std::string PackageName,
275 unsigned int StepsDone,
276 unsigned int TotalSteps,
277 std::string HumanReadableAction)
278 {
279 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps,
280 HumanReadableAction))
281 return false;
282
283 int row = nr_terminal_rows;
284
285 static string save_cursor = "\033[s";
286 static string restore_cursor = "\033[u";
287
288 static string set_bg_color = "\033[42m"; // green
289 static string set_fg_color = "\033[30m"; // black
290
291 static string restore_bg = "\033[49m";
292 static string restore_fg = "\033[39m";
293
294 std::cout << save_cursor
295 // move cursor position to last row
296 << "\033[" << row << ";0f"
297 << set_bg_color
298 << set_fg_color
299 << progress_str
300 << restore_cursor
301 << restore_bg
302 << restore_fg;
303 std::flush(std::cout);
304 last_reported_progress = percentage;
305
306 return true;
307 }
308
309 bool PackageManagerText::StatusChanged(std::string PackageName,
310 unsigned int StepsDone,
311 unsigned int TotalSteps,
312 std::string HumanReadableAction)
313 {
314 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction))
315 return false;
316
317 std::cout << progress_str << "\r\n";
318 std::flush(std::cout);
319
320 last_reported_progress = percentage;
321
322 return true;
323 }
324
325
326
327 }; // namespace progress
328 }; // namespace apt