File: | Dpkg/ErrorHandling.pm |
Coverage: | 55.3% |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | # This program is free software; you can redistribute it and/or modify | ||||||
2 | # it under the terms of the GNU General Public License as published by | ||||||
3 | # the Free Software Foundation; either version 2 of the License, or | ||||||
4 | # (at your option) any later version. | ||||||
5 | # | ||||||
6 | # This program is distributed in the hope that it will be useful, | ||||||
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
9 | # GNU General Public License for more details. | ||||||
10 | # | ||||||
11 | # You should have received a copy of the GNU General Public License | ||||||
12 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
13 | |||||||
14 | =encoding utf8 | ||||||
15 | |||||||
16 - 26 | =head1 NAME Dpkg::ErrorHandling - handle error conditions =head1 DESCRIPTION This module provides functions to handle all reporting and error handling. B<Note>: This is a private module, its API can change at any time. =cut | ||||||
27 | |||||||
28 | package Dpkg::ErrorHandling 0.02; | ||||||
29 | |||||||
30 | 2013 2013 2013 | 4858 843 28825 | use strict; | ||||
31 | 2013 2013 2013 | 3269 2342 48767 | use warnings; | ||||
32 | 2013 2013 2013 | 3045 1942 147038 | use feature qw(state); | ||||
33 | |||||||
34 | our @EXPORT_OK = qw( | ||||||
35 | REPORT_PROGNAME | ||||||
36 | REPORT_COMMAND | ||||||
37 | REPORT_STATUS | ||||||
38 | REPORT_DEBUG | ||||||
39 | REPORT_INFO | ||||||
40 | REPORT_NOTICE | ||||||
41 | REPORT_WARN | ||||||
42 | REPORT_ERROR | ||||||
43 | report_pretty | ||||||
44 | report_color | ||||||
45 | report | ||||||
46 | ); | ||||||
47 | our @EXPORT = qw( | ||||||
48 | report_options | ||||||
49 | debug | ||||||
50 | info | ||||||
51 | notice | ||||||
52 | warning | ||||||
53 | error | ||||||
54 | errormsg | ||||||
55 | syserr | ||||||
56 | printcmd | ||||||
57 | subprocerr | ||||||
58 | usageerr | ||||||
59 | ); | ||||||
60 | |||||||
61 | 2013 2013 2013 | 4082 1295 29465 | use Exporter qw(import); | ||||
62 | |||||||
63 | 2013 2013 2013 | 233177 1464 23126 | use Dpkg (); | ||||
64 | 2013 2013 2013 | 224058 2446 215595 | use Dpkg::Gettext; | ||||
65 | |||||||
66 | my $quiet_warnings = 0; | ||||||
67 | my $debug_level = 0; | ||||||
68 | my $info_fh = \*STDOUT; | ||||||
69 | |||||||
70 | sub setup_color | ||||||
71 | { | ||||||
72 | 72 | 0 | 241 | my $mode = $ENV{'DPKG_COLORS'} // 'auto'; | |||
73 | 72 | 78 | my $use_color; | ||||
74 | |||||||
75 | 72 | 207 | if ($mode eq 'auto') { | ||||
76 | ## no critic (InputOutput::ProhibitInteractiveTest) | ||||||
77 | 0 | 0 | $use_color = 1 if -t *STDOUT or -t *STDERR; | ||||
78 | } elsif ($mode eq 'always') { | ||||||
79 | 0 | 0 | $use_color = 1; | ||||
80 | } else { | ||||||
81 | 72 | 89 | $use_color = 0; | ||||
82 | } | ||||||
83 | |||||||
84 | 72 | 161 | require Term::ANSIColor if $use_color; | ||||
85 | } | ||||||
86 | |||||||
87 | use constant { | ||||||
88 | 2013 | 1226650 | REPORT_PROGNAME => 1, | ||||
89 | REPORT_COMMAND => 2, | ||||||
90 | REPORT_STATUS => 3, | ||||||
91 | REPORT_INFO => 4, | ||||||
92 | REPORT_NOTICE => 5, | ||||||
93 | REPORT_WARN => 6, | ||||||
94 | REPORT_ERROR => 7, | ||||||
95 | REPORT_DEBUG => 8, | ||||||
96 | 2013 2013 | 6779 1989 | }; | ||||
97 | |||||||
98 | my %report_mode = ( | ||||||
99 | REPORT_PROGNAME() => { | ||||||
100 | color => 'bold', | ||||||
101 | }, | ||||||
102 | REPORT_COMMAND() => { | ||||||
103 | color => 'bold magenta', | ||||||
104 | }, | ||||||
105 | REPORT_STATUS() => { | ||||||
106 | color => 'clear', | ||||||
107 | # We do not translate this name because the untranslated output is | ||||||
108 | # part of the interface. | ||||||
109 | name => 'status', | ||||||
110 | }, | ||||||
111 | REPORT_DEBUG() => { | ||||||
112 | color => 'clear', | ||||||
113 | # We do not translate this name because it is a developer interface | ||||||
114 | # and all debug messages are untranslated anyway. | ||||||
115 | name => 'debug', | ||||||
116 | }, | ||||||
117 | REPORT_INFO() => { | ||||||
118 | color => 'green', | ||||||
119 | name => g_('info'), | ||||||
120 | }, | ||||||
121 | REPORT_NOTICE() => { | ||||||
122 | color => 'yellow', | ||||||
123 | name => g_('notice'), | ||||||
124 | }, | ||||||
125 | REPORT_WARN() => { | ||||||
126 | color => 'bold yellow', | ||||||
127 | name => g_('warning'), | ||||||
128 | }, | ||||||
129 | REPORT_ERROR() => { | ||||||
130 | color => 'bold red', | ||||||
131 | name => g_('error'), | ||||||
132 | }, | ||||||
133 | ); | ||||||
134 | |||||||
135 | sub report_options | ||||||
136 | { | ||||||
137 | 1770 | 0 | 5157 | my (%options) = @_; | |||
138 | |||||||
139 | 1770 | 4070 | if (exists $options{quiet_warnings}) { | ||||
140 | 1770 | 2874 | $quiet_warnings = $options{quiet_warnings}; | ||||
141 | } | ||||||
142 | 1770 | 4570 | if (exists $options{debug_level}) { | ||||
143 | 0 | 0 | $debug_level = $options{debug_level}; | ||||
144 | } | ||||||
145 | 1770 | 4275 | if (exists $options{info_fh}) { | ||||
146 | 0 | 0 | $info_fh = $options{info_fh}; | ||||
147 | } | ||||||
148 | } | ||||||
149 | |||||||
150 | sub report_name | ||||||
151 | { | ||||||
152 | 252 | 0 | 213 | my $type = shift; | |||
153 | |||||||
154 | 252 | 515 | return $report_mode{$type}{name} // ''; | ||||
155 | } | ||||||
156 | |||||||
157 | sub report_color | ||||||
158 | { | ||||||
159 | 504 | 0 | 391 | my $type = shift; | |||
160 | |||||||
161 | 504 | 1094 | return $report_mode{$type}{color} // 'clear'; | ||||
162 | } | ||||||
163 | |||||||
164 | sub report_pretty | ||||||
165 | { | ||||||
166 | 504 | 0 | 488 | my ($msg, $color) = @_; | |||
167 | |||||||
168 | 504 | 450 | state $use_color = setup_color(); | ||||
169 | |||||||
170 | 504 | 493 | if ($use_color) { | ||||
171 | 0 | 0 | return Term::ANSIColor::colored($msg, $color); | ||||
172 | } else { | ||||||
173 | 504 | 621 | return $msg; | ||||
174 | } | ||||||
175 | } | ||||||
176 | |||||||
177 | sub _progname_prefix | ||||||
178 | { | ||||||
179 | 252 | 524 | return report_pretty("$Dpkg::PROGNAME: ", report_color(REPORT_PROGNAME)); | ||||
180 | } | ||||||
181 | |||||||
182 | sub _typename_prefix | ||||||
183 | { | ||||||
184 | 252 | 200 | my $type = shift; | ||||
185 | |||||||
186 | 252 | 315 | return report_pretty(report_name($type), report_color($type)); | ||||
187 | } | ||||||
188 | |||||||
189 | sub report(@) | ||||||
190 | { | ||||||
191 | 252 | 0 | 395 | my ($type, $msg, @args) = @_; | |||
192 | |||||||
193 | 252 | 756 | $msg = sprintf $msg, @args if @args; | ||||
194 | |||||||
195 | 252 | 396 | my $progname = _progname_prefix(); | ||||
196 | 252 | 368 | my $typename = _typename_prefix($type); | ||||
197 | |||||||
198 | 252 | 2221 | return "$progname$typename: $msg\n"; | ||||
199 | } | ||||||
200 | |||||||
201 | sub debug | ||||||
202 | { | ||||||
203 | 0 | 0 | 0 | my ($level, @args) = @_; | |||
204 | |||||||
205 | 0 | 0 | print report(REPORT_DEBUG, @args) if $level <= $debug_level; | ||||
206 | } | ||||||
207 | |||||||
208 | sub info($;@) | ||||||
209 | { | ||||||
210 | 0 | 0 | 0 | my @args = @_; | |||
211 | |||||||
212 | 0 0 | 0 0 | print { $info_fh } report(REPORT_INFO, @args) if not $quiet_warnings; | ||||
213 | } | ||||||
214 | |||||||
215 | sub notice | ||||||
216 | { | ||||||
217 | 0 | 0 | 0 | my @args = @_; | |||
218 | |||||||
219 | 0 | 0 | warn report(REPORT_NOTICE, @args) if not $quiet_warnings; | ||||
220 | } | ||||||
221 | |||||||
222 | sub warning($;@) | ||||||
223 | { | ||||||
224 | 67278 | 0 | 181655 | my @args = @_; | |||
225 | |||||||
226 | 67278 | 136124 | warn report(REPORT_WARN, @args) if not $quiet_warnings; | ||||
227 | } | ||||||
228 | |||||||
229 | sub syserr($;@) | ||||||
230 | { | ||||||
231 | 6 | 0 | 12 | my ($msg, @args) = @_; | |||
232 | |||||||
233 | 6 | 37 | die report(REPORT_ERROR, "$msg: $!", @args); | ||||
234 | } | ||||||
235 | |||||||
236 | sub error($;@) | ||||||
237 | { | ||||||
238 | 186 | 0 | 314 | my @args = @_; | |||
239 | |||||||
240 | 186 | 348 | die report(REPORT_ERROR, @args); | ||||
241 | } | ||||||
242 | |||||||
243 | sub errormsg($;@) | ||||||
244 | { | ||||||
245 | 0 | 0 | 0 | my @args = @_; | |||
246 | |||||||
247 | 0 0 | 0 0 | print { *STDERR } report(REPORT_ERROR, @args); | ||||
248 | } | ||||||
249 | |||||||
250 | sub printcmd | ||||||
251 | { | ||||||
252 | 0 | 0 | 0 | my (@cmd) = @_; | |||
253 | |||||||
254 | 0 0 | 0 0 | print { *STDERR } report_pretty(" @cmd\n", report_color(REPORT_COMMAND)); | ||||
255 | } | ||||||
256 | |||||||
257 | sub subprocerr(@) | ||||||
258 | { | ||||||
259 | 3 | 0 | 5 | my ($p, @args) = @_; | |||
260 | |||||||
261 | 3 | 10 | $p = sprintf $p, @args if @args; | ||||
262 | |||||||
263 | 3 | 23 | require POSIX; | ||||
264 | |||||||
265 | 3 | 13 | if (POSIX::WIFEXITED($?)) { | ||||
266 | 3 | 5 | my $ret = POSIX::WEXITSTATUS($?); | ||||
267 | 3 | 14 | error(g_('%s subprocess returned exit status %d'), $p, $ret); | ||||
268 | } elsif (POSIX::WIFSIGNALED($?)) { | ||||||
269 | 0 | my $sig = POSIX::WTERMSIG($?); | |||||
270 | 0 | error(g_('%s subprocess was killed by signal %d'), $p, $sig); | |||||
271 | } else { | ||||||
272 | 0 | error(g_('%s subprocess failed with unknown status code %d'), $p, $?); | |||||
273 | } | ||||||
274 | } | ||||||
275 | |||||||
276 | sub usageerr(@) | ||||||
277 | { | ||||||
278 | 0 | 0 | my ($msg, @args) = @_; | ||||
279 | |||||||
280 | 0 | state $printforhelp = g_('Use --help for program usage information.'); | |||||
281 | |||||||
282 | 0 | $msg = sprintf $msg, @args if @args; | |||||
283 | 0 | warn report(REPORT_ERROR, $msg); | |||||
284 | 0 | warn "\n$printforhelp\n"; | |||||
285 | 0 | exit(2); | |||||
286 | } | ||||||
287 | |||||||
288 - 294 | =head1 CHANGES =head2 Version 0.xx This is a private module. =cut | ||||||
295 | |||||||
296 | 1; |