File Coverage

lib/App/MtAws/Exceptions.pm
Criterion Covered Total %
statement 75 75 100.0
branch 39 40 97.5
condition 13 17 76.4
subroutine 15 15 100.0
pod 0 6 0.0
total 142 153 92.8


line stmt bran cond sub pod time code
1             # mt-aws-glacier - Amazon Glacier sync client
2             # Copyright (C) 2012-2014 Victor Efimov
3             # http://mt-aws.com (also http://vs-dev.com) vs@vs-dev.com
4             # License: GPLv3
5             #
6             # This file is part of "mt-aws-glacier"
7             #
8             # mt-aws-glacier is free software: you can redistribute it and/or modify
9             # it under the terms of the GNU General Public License as published by
10             # the Free Software Foundation, either version 3 of the License, or
11             # (at your option) any later version.
12             #
13             # mt-aws-glacier is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program. If not, see <http://www.gnu.org/licenses/>.
20              
21             package App::MtAws::Exceptions;
22              
23             our $VERSION = '1.114_2';
24              
25 113     113   537 use strict;
  113         162  
  113         3253  
26 113     113   465 use warnings;
  113         141  
  113         2659  
27 113     113   1209 use utf8;
  113         155  
  113         470  
28 113     113   2915 use Encode;
  113         12502  
  113         8424  
29 113     113   553 use constant BINARY_ENCODING => "MT_BINARY";
  113         184  
  113         8533  
30 113     113   1211 use App::MtAws::Utils;
  113         150  
  113         17844  
31              
32 113     113   581 use Carp;
  113         132  
  113         8390  
33             eval { require I18N::Langinfo; }; # TODO: test that it's loaded compile time, test that it wont break if failed
34              
35 113     113   563 use Exporter 'import';
  113         177  
  113         113497  
36              
37              
38             our @EXPORT = qw/exception get_exception is_exception exception_message dump_error get_errno/;
39              
40             our $_errno_encoding = undef;
41              
42             sub get_errno
43             {
44 32     32 0 42590 my $err = "$_[0]";
45 32         95 local ($@, $!);
46              
47             # some code in this scope copied from Encode::Locale
48             # http://search.cpan.org/perldoc?Encode%3A%3ALocale
49             # by Gisle Aas <gisle@aas.no>.
50 32   100     95 $_errno_encoding ||= eval {
      66        
51             require I18N::Langinfo;
52             my $enc = I18N::Langinfo::langinfo(I18N::Langinfo::CODESET());
53             # copy-paste workaround from Encode::Locale
54             # https://rt.cpan.org/Ticket/Display.html?id=66373
55             $enc = "hp-roman8" if $^O eq "hpux" && $enc eq "roman8";
56              
57             defined (find_encoding($enc)) ? $enc : undef;
58             } || BINARY_ENCODING();
59              
60 32         1749 my $res;
61 32 100       67 if ($_errno_encoding eq BINARY_ENCODING) {
62 4         17 $res = hex_dump_string($err);
63             } else {
64             eval {
65             # workaround issue https://rt.perl.org/rt3/Ticket/Display.html?id=119499
66             # perhaps Encode::decode_utf8 can be used here too
67 28 100       214 $res = utf8::is_utf8($err) ? $err : decode($_errno_encoding, $err, Encode::DIE_ON_ERR|Encode::LEAVE_SRC);
68 26         814 1;
69 28 100       34 } or do {
70 2         88 $res = hex_dump_string($err);
71             }
72             }
73 32         165 $res;
74             }
75              
76             # Does not work with directory names
77              
78             # exception [$previous] { $msg | $code => $msg } name1 => value1, name2 => value2 ...
79             # exception [$previous] { $msg | $code => $msg } name1 => value1, 'ERRNO', name2 => value2 ...
80             sub exception
81             {
82 554     554 0 61066 my %data;
83 554 100       1499 %data = %{shift()} if (ref $_[0] eq ref {});
  6         30  
84 554 100       1241 if (scalar @_ == 1) {
85 4         12 $data{message} = shift;
86             } else {
87 550         1558 @data{qw/code message/} = (shift, shift);
88 550         1039 while (@_) {
89 623         523 my $key = shift;
90 623 100       781 if ($key eq 'ERRNO') {
91 14 100       376 confess "ERRNO already used" if exists $data{'errno'};
92 12         20 $data{'errno'} = get_errno($!);
93 12         99 $data{'errno_code'} = $!+0; # numify
94             } else {
95 609 100       55153 $data{$key} = shift or confess "Malformed exception"
96             }
97             }
98             }
99 247         3272 return { 'MTEXCEPTION' => 1, %data };
100             }
101              
102             # get_exception -> TRUE|FALSE
103             # get_exception($@)
104             # get_exception->{code}
105             sub get_exception
106             {
107 250 100   250 0 1769 my $e = @_ ? $_[0] : $@;
108 250 100 66     1868 ref $e eq ref {} && $e->{MTEXCEPTION} && $e;
109             }
110              
111             # is_exception()
112             # is_exception($code)
113             # is_exception($code, $@)
114             sub is_exception
115             {
116 28     28 0 480 my ($code, $e) = @_;
117 28 100       66 $e = $@ unless defined $e;
118             get_exception($e) &&
119 28 100 100     49 (!defined($code) || ( defined(get_exception($e)->{code}) && get_exception($e)->{code} eq $code ));
      66        
120             }
121              
122              
123             sub exception_message
124             {
125 39     39 0 50 my ($e) = @_;
126 39         158 my %data = %$e;
127 39         73 my $spec = delete $data{message};
128             my $rep = sub {
129 65     65   110 my ($match) = @_;
130 65 100       261 if (my ($format, $name) = $match =~ /^([\w]+)\s+([\w]+)$/) {
131 15         20 my $value = $data{$name};
132 15 100       33 if (defined($value)) {
133 13 100       32 if (lc $format eq lc 'string') {
134 7         41 qq{"$value"};
135             } else {
136 6         38 sprintf("%$format", $value);
137             }
138             } else {
139 2         7 ':NULL:'
140             }
141             } else {
142 50 100       191 defined($data{$match}) ? $data{$match} : ':NULL:';
143             }
144 39         184 };
145              
146 39 50       302 $spec =~ s{%([\w\s]+)%} {$rep->($1)}ge if %data; # in new perl versions \w also means unicode chars..
  65         97  
147 39         378 $spec;
148             }
149              
150              
151              
152             sub dump_error
153             {
154 7     7 0 2312 my ($where) = (@_, '');
155 7 100 66     44 $where = defined($where) && length($where) ? " ($where)" : '';
156 7 100       15 if (is_exception('cmd_error')) {
    100          
157             # no additional output
158             } elsif (is_exception) {
159 3         9 print STDERR "ERROR$where: ".exception_message($@)."\n";
160             } else {
161 2         19 print STDERR "UNEXPECTED ERROR$where: $@\n";
162             }
163             }
164             1;
165              
166             __END__