File Coverage

blib/lib/File/Digest.pm
Criterion Covered Total %
statement 59 62 95.1
branch 16 18 88.8
condition 3 6 50.0
subroutine 8 8 100.0
pod 2 2 100.0
total 88 96 91.6


line stmt bran cond sub pod time code
1             package File::Digest;
2              
3             our $DATE = '2019-09-12'; # DATE
4             our $VERSION = '0.010'; # VERSION
5              
6 1     1   71543 use 5.010001;
  1         10  
7 1     1   5 use strict;
  1         2  
  1         33  
8 1     1   6 use warnings;
  1         1  
  1         34  
9 1     1   1663 use Log::ger;
  1         48  
  1         5  
10              
11 1     1   253 use Exporter qw(import);
  1         2  
  1         52  
12             our @EXPORT_OK = qw(digest_files);
13              
14 1     1   462 use Perinci::Object;
  1         419  
  1         821  
15              
16             our %SPEC;
17              
18             my %arg_file = (
19             file => {
20             summary => 'Filename ("-" means stdin)',
21             schema => ['filename*'],
22             req => 1,
23             pos => 0,
24             cmdline_aliases => {f=>{}},
25             },
26             );
27              
28             my %arg_files = (
29             files => {
30             'x.name.is_plural' => 1,
31             'x.name.singular' => 'file',
32             summary => 'Array of filenames (filename "-" means stdin)',
33             schema => ['array*', of=>'filename*'],
34             req => 1,
35             pos => 0,
36             greedy => 1,
37             cmdline_aliases => {f=>{}},
38             },
39             );
40              
41             my %args_algorithm = (
42             algorithm => {
43             schema => ['str*', in=>[qw/crc32 md5 sha1 sha224 sha256 sha384 sha512 sha512224 sha512256 Digest/]],
44             default => 'md5',
45             cmdline_aliases => {a=>{}},
46             },
47             digest_args => {
48             schema => ['array*', of=>'str*', 'x.perl.coerce_rules'=>['str_comma_sep']],
49             cmdline_aliases => {A=>{}},
50             },
51             );
52              
53             $SPEC{digest_file} = {
54             v => 1.1,
55             summary => 'Calculate digest of file',
56             description => <<'_',
57              
58             Return 400 status when algorithm is unknown/unsupported.
59              
60             _
61             args => {
62             %arg_file,
63             %args_algorithm,
64             },
65             };
66             sub digest_file {
67 31     31 1 110 my %args = @_;
68              
69 31         64 my $file = $args{file};
70 31   50     68 my $algo = $args{algorithm} // 'md5';
71              
72 31         37 my $fh;
73 31 50       73 if ($file eq '-') {
74 0         0 $fh = \*STDIN;
75             } else {
76 31 100       455 unless (-f $file) {
77 10         43 log_warn("Can't open %s: no such file", $file);
78 10         67 return [404, "No such file '$file'"];
79             }
80 21 50       701 open $fh, "<", $file or do {
81 0         0 log_warn("Can't open %s: %s", $file, $!);
82 0         0 return [500, "Can't open '$file': $!"];
83             };
84             }
85              
86 21 100       141 if ($algo eq 'md5') {
    100          
    100          
    100          
87 2         12 require Digest::MD5;
88 2         17 my $ctx = Digest::MD5->new;
89 2         32 $ctx->addfile($fh);
90 2         41 return [200, "OK", $ctx->hexdigest];
91             } elsif ($algo =~ /\Asha(512224|512256|224|256|384|512|1)\z/) {
92 14         613 require Digest::SHA;
93 14         3194 my $ctx = Digest::SHA->new($1);
94 14         237 $ctx->addfile($fh);
95 14         772 return [200, "OK", $ctx->hexdigest];
96             } elsif ($algo eq 'crc32') {
97 2         472 require Digest::CRC;
98 2         2488 my $ctx = Digest::CRC->new(type=>'crc32');
99 2         164 $ctx->addfile($fh);
100 2         136 return [200, "OK", $ctx->hexdigest];
101             } elsif ($algo eq 'Digest') {
102 2         596 require Digest;
103 2   50     568 my $ctx = Digest->new(@{ $args{digest_args} // [] });
  2         18  
104 2         84 $ctx->addfile($fh);
105 2         39 return [200, "OK", $ctx->hexdigest];
106             } else {
107 1         18 return [400, "Invalid/unsupported algorithm '$algo'"];
108             }
109             }
110              
111             $SPEC{digest_files} = {
112             v => 1.1,
113             summary => 'Calculate digests of files',
114             description => <<'_',
115              
116             Dies when algorithm is unsupported/unknown.
117              
118             _
119             args => {
120             %arg_files,
121             %args_algorithm,
122             },
123             };
124             sub digest_files {
125 11     11 1 36591 my %args = @_;
126              
127 11         23 my $files = $args{files};
128 11   50     29 my $algo = $args{algorithm} // 'md5';
129              
130 11         32 my $envres = envresmulti();
131 11         2283 my @res;
132              
133 11         21 for my $file (@$files) {
134 31         97 my $itemres = digest_file(file => $file, algorithm=>$algo, digest_args=>$args{digest_args});
135 31 100       226 die $itemres->[1] if $itemres->[0] == 400;
136 30         145 $envres->add_result($itemres->[0], $itemres->[1], {item_id=>$file});
137 30 100       1567 push @res, {file=>$file, digest=>$itemres->[2]} if $itemres->[0] == 200;
138             }
139              
140 10         38 $envres = $envres->as_struct;
141 10         71 $envres->[2] = \@res;
142 10         23 $envres->[3]{'table.fields'} = [qw/file digest/];
143 10         34 $envres;
144             }
145              
146             1;
147             # ABSTRACT: Calculate digests of files
148              
149             __END__