]> git.saurik.com Git - apt.git/blob - apt-private/private-progress.cc
move iprogress.{cc,h} to private-progress.{cc,h} until its fully stable
[apt.git] / apt-private / private-progress.cc
1 #include <apt-pkg/configuration.h>
2 #include <apt-pkg/fileutl.h>
3 #include <apt-pkg/iprogress.h>
4 #include <apt-pkg/strutl.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 bool PackageManager::StatusChanged(std::string PackageName,
17 unsigned int StepsDone,
18 unsigned int TotalSteps,
19 std::string HumanReadableAction)
20 {
21 int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1);
22 percentage = StepsDone/(float)TotalSteps * 100.0;
23 strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage);
24
25 if(percentage < (last_reported_progress + reporting_steps))
26 return false;
27
28 return true;
29 }
30
31 PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd)
32 : StepsDone(0), StepsTotal(1)
33 {
34 OutStatusFd = progress_fd;
35 }
36
37 void PackageManagerProgressFd::WriteToStatusFd(std::string s)
38 {
39 if(OutStatusFd <= 0)
40 return;
41 FileFd::Write(OutStatusFd, s.c_str(), s.size());
42 }
43
44 void PackageManagerProgressFd::Start()
45 {
46 if(OutStatusFd <= 0)
47 return;
48
49 // FIXME: use SetCloseExec here once it taught about throwing
50 // exceptions instead of doing _exit(100) on failure
51 fcntl(OutStatusFd,F_SETFD,FD_CLOEXEC);
52
53 // send status information that we are about to fork dpkg
54 std::ostringstream status;
55 status << "pmstatus:dpkg-exec:"
56 << (StepsDone/float(StepsTotal)*100.0)
57 << ":" << _("Running dpkg")
58 << std::endl;
59 WriteToStatusFd(status.str());
60 }
61
62 void PackageManagerProgressFd::Stop()
63 {
64 // clear the Keep-Fd again
65 _config->Clear("APT::Keep-Fds", OutStatusFd);
66 }
67
68 void PackageManagerProgressFd::Error(std::string PackageName,
69 unsigned int StepsDone,
70 unsigned int TotalSteps,
71 std::string ErrorMessage)
72 {
73 std::ostringstream status;
74 status << "pmerror:" << PackageName
75 << ":" << (StepsDone/float(TotalSteps)*100.0)
76 << ":" << ErrorMessage
77 << std::endl;
78 WriteToStatusFd(status.str());
79 }
80
81 void PackageManagerProgressFd::ConffilePrompt(std::string PackageName,
82 unsigned int StepsDone,
83 unsigned int TotalSteps,
84 std::string ConfMessage)
85 {
86 std::ostringstream status;
87 status << "pmconffile:" << PackageName
88 << ":" << (StepsDone/float(TotalSteps)*100.0)
89 << ":" << ConfMessage
90 << std::endl;
91 WriteToStatusFd(status.str());
92 }
93
94
95 bool PackageManagerProgressFd::StatusChanged(std::string PackageName,
96 unsigned int xStepsDone,
97 unsigned int xTotalSteps,
98 std::string pkg_action)
99 {
100 StepsDone = xStepsDone;
101 StepsTotal = xTotalSteps;
102
103 // build the status str
104 std::ostringstream status;
105 status << "pmstatus:" << StringSplit(PackageName, ":")[0]
106 << ":" << (StepsDone/float(StepsTotal)*100.0)
107 << ":" << pkg_action
108 << std::endl;
109 WriteToStatusFd(status.str());
110
111 if(_config->FindB("Debug::APT::Progress::PackageManagerFd", false) == true)
112 std::cerr << "progress: " << PackageName << " " << xStepsDone
113 << " " << xTotalSteps << " " << pkg_action
114 << std::endl;
115
116
117 return true;
118 }
119
120 void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
121 {
122 // scroll down a bit to avoid visual glitch when the screen
123 // area shrinks by one row
124 std::cout << "\n";
125
126 // save cursor
127 std::cout << "\033[s";
128
129 // set scroll region (this will place the cursor in the top left)
130 std::cout << "\033[1;" << nr_rows - 1 << "r";
131
132 // restore cursor but ensure its inside the scrolling area
133 std::cout << "\033[u";
134 static const char *move_cursor_up = "\033[1A";
135 std::cout << move_cursor_up;
136
137 std::flush(std::cout);
138 }
139
140 PackageManagerFancy::PackageManagerFancy()
141 : nr_terminal_rows(-1)
142 {
143 struct winsize win;
144 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) == 0)
145 {
146 nr_terminal_rows = win.ws_row;
147 }
148 }
149
150 void PackageManagerFancy::Start()
151 {
152 if (nr_terminal_rows > 0)
153 SetupTerminalScrollArea(nr_terminal_rows);
154 }
155
156 void PackageManagerFancy::Stop()
157 {
158 if (nr_terminal_rows > 0)
159 {
160 SetupTerminalScrollArea(nr_terminal_rows + 1);
161
162 // override the progress line (sledgehammer)
163 static const char* clear_screen_below_cursor = "\033[J";
164 std::cout << clear_screen_below_cursor;
165 }
166 }
167
168 bool PackageManagerFancy::StatusChanged(std::string PackageName,
169 unsigned int StepsDone,
170 unsigned int TotalSteps,
171 std::string HumanReadableAction)
172 {
173 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps,
174 HumanReadableAction))
175 return false;
176
177 int row = nr_terminal_rows;
178
179 static string save_cursor = "\033[s";
180 static string restore_cursor = "\033[u";
181
182 static string set_bg_color = "\033[42m"; // green
183 static string set_fg_color = "\033[30m"; // black
184
185 static string restore_bg = "\033[49m";
186 static string restore_fg = "\033[39m";
187
188 std::cout << save_cursor
189 // move cursor position to last row
190 << "\033[" << row << ";0f"
191 << set_bg_color
192 << set_fg_color
193 << progress_str
194 << restore_cursor
195 << restore_bg
196 << restore_fg;
197 std::flush(std::cout);
198 last_reported_progress = percentage;
199
200 return true;
201 }
202
203 bool PackageManagerText::StatusChanged(std::string PackageName,
204 unsigned int StepsDone,
205 unsigned int TotalSteps,
206 std::string HumanReadableAction)
207 {
208 if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction))
209 return false;
210
211 std::cout << progress_str << "\r\n";
212 std::flush(std::cout);
213
214 last_reported_progress = percentage;
215
216 return true;
217 }
218
219
220 }; // namespace progress
221 }; // namespace apt