ErrorHandling.pm 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. package Dpkg::ErrorHandling;
  14. use strict;
  15. use warnings;
  16. our $VERSION = '0.02';
  17. our @EXPORT_OK = qw(
  18. REPORT_PROGNAME
  19. REPORT_COMMAND
  20. REPORT_STATUS
  21. REPORT_INFO
  22. REPORT_NOTICE
  23. REPORT_WARN
  24. REPORT_ERROR
  25. report_pretty
  26. report_color
  27. report
  28. );
  29. our @EXPORT = qw(
  30. report_options
  31. info
  32. notice
  33. warning
  34. error
  35. errormsg
  36. syserr
  37. printcmd
  38. subprocerr
  39. usageerr
  40. );
  41. use Exporter qw(import);
  42. use Term::ANSIColor;
  43. use Dpkg ();
  44. use Dpkg::Gettext;
  45. my $quiet_warnings = 0;
  46. my $info_fh = \*STDOUT;
  47. my $use_color = 0;
  48. sub setup_color
  49. {
  50. my $mode = $ENV{'DPKG_COLORS'} // 'never';
  51. if ($mode eq 'auto') {
  52. ## no critic (InputOutput::ProhibitInteractiveTest)
  53. $use_color = 1 if -t *STDOUT or -t *STDERR;
  54. } elsif ($mode eq 'always') {
  55. $use_color = 1;
  56. } else {
  57. $use_color = 0;
  58. }
  59. }
  60. setup_color();
  61. use constant {
  62. REPORT_PROGNAME => 1,
  63. REPORT_COMMAND => 2,
  64. REPORT_STATUS => 3,
  65. REPORT_INFO => 4,
  66. REPORT_NOTICE => 5,
  67. REPORT_WARN => 6,
  68. REPORT_ERROR => 7,
  69. };
  70. my %report_mode = (
  71. REPORT_PROGNAME() => {
  72. color => 'bold',
  73. },
  74. REPORT_COMMAND() => {
  75. color => 'bold magenta',
  76. },
  77. REPORT_STATUS() => {
  78. color => 'clear',
  79. # We do not translate this name because the untranslated output is
  80. # part of the interface.
  81. name => 'status',
  82. },
  83. REPORT_INFO() => {
  84. color => 'green',
  85. name => g_('info'),
  86. },
  87. REPORT_NOTICE() => {
  88. color => 'yellow',
  89. name => g_('notice'),
  90. },
  91. REPORT_WARN() => {
  92. color => 'bold yellow',
  93. name => g_('warning'),
  94. },
  95. REPORT_ERROR() => {
  96. color => 'bold red',
  97. name => g_('error'),
  98. },
  99. );
  100. sub report_options
  101. {
  102. my (%options) = @_;
  103. if (exists $options{quiet_warnings}) {
  104. $quiet_warnings = $options{quiet_warnings};
  105. }
  106. if (exists $options{info_fh}) {
  107. $info_fh = $options{info_fh};
  108. }
  109. }
  110. sub report_name
  111. {
  112. my $type = shift;
  113. return $report_mode{$type}{name} // '';
  114. }
  115. sub report_color
  116. {
  117. my $type = shift;
  118. return $report_mode{$type}{color} // 'clear';
  119. }
  120. sub report_pretty
  121. {
  122. my ($msg, $color) = @_;
  123. if ($use_color) {
  124. return colored($msg, $color);
  125. } else {
  126. return $msg;
  127. }
  128. }
  129. sub _progname_prefix
  130. {
  131. return report_pretty("$Dpkg::PROGNAME: ", report_color(REPORT_PROGNAME));
  132. }
  133. sub _typename_prefix
  134. {
  135. my $type = shift;
  136. return report_pretty(report_name($type), report_color($type));
  137. }
  138. sub report(@)
  139. {
  140. my ($type, $msg) = (shift, shift);
  141. $msg = sprintf($msg, @_) if (@_);
  142. my $progname = _progname_prefix();
  143. my $typename = _typename_prefix($type);
  144. return "$progname$typename: $msg\n";
  145. }
  146. sub info($;@)
  147. {
  148. print { $info_fh } report(REPORT_INFO, @_) if not $quiet_warnings;
  149. }
  150. sub notice
  151. {
  152. warn report(REPORT_NOTICE, @_) if not $quiet_warnings;
  153. }
  154. sub warning($;@)
  155. {
  156. warn report(REPORT_WARN, @_) if not $quiet_warnings;
  157. }
  158. sub syserr($;@)
  159. {
  160. my $msg = shift;
  161. die report(REPORT_ERROR, "$msg: $!", @_);
  162. }
  163. sub error($;@)
  164. {
  165. die report(REPORT_ERROR, @_);
  166. }
  167. sub errormsg($;@)
  168. {
  169. print { *STDERR } report(REPORT_ERROR, @_);
  170. }
  171. sub printcmd
  172. {
  173. my (@cmd) = @_;
  174. print { *STDERR } report_pretty(" @cmd\n", report_color(REPORT_COMMAND));
  175. }
  176. sub subprocerr(@)
  177. {
  178. my ($p) = (shift);
  179. $p = sprintf($p, @_) if (@_);
  180. require POSIX;
  181. if (POSIX::WIFEXITED($?)) {
  182. error(g_('%s gave error exit status %s'), $p, POSIX::WEXITSTATUS($?));
  183. } elsif (POSIX::WIFSIGNALED($?)) {
  184. error(g_('%s died from signal %s'), $p, POSIX::WTERMSIG($?));
  185. } else {
  186. error(g_('%s failed with unknown exit code %d'), $p, $?);
  187. }
  188. }
  189. my $printforhelp = g_('Use --help for program usage information.');
  190. sub usageerr(@)
  191. {
  192. my ($msg) = (shift);
  193. $msg = sprintf($msg, @_) if (@_);
  194. warn report(REPORT_ERROR, $msg);
  195. warn "\n$printforhelp\n";
  196. exit(2);
  197. }
  198. 1;