File Coverage

blib/lib/OrePAN2/Repository/Cache.pm
Criterion Covered Total %
statement 51 79 64.5
branch 5 24 20.8
condition 0 12 0.0
subroutine 15 18 83.3
pod 0 6 0.0
total 71 139 51.0


line stmt bran cond sub pod time code
1             package OrePAN2::Repository::Cache;
2              
3 2     2   19 use strict;
  2         4  
  2         79  
4 2     2   12 use warnings;
  2         4  
  2         63  
5 2     2   48 use utf8;
  2         8  
  2         15  
6 2     2   101 use 5.008_001;
  2         8  
7              
8 2     2   13 use Carp;
  2         5  
  2         183  
9             use Class::Accessor::Lite 0.05 (
10 2         20 rw => [qw(is_dirty directory)],
11 2     2   16 );
  2         53  
12 2     2   226 use Digest::MD5;
  2         5  
  2         93  
13 2     2   14 use File::Path;
  2         4  
  2         108  
14 2     2   12 use File::Spec;
  2         34  
  2         56  
15 2     2   551 use File::stat;
  2         6981  
  2         15  
16 2     2   1184 use IO::File::AtomicChange;
  2         3102  
  2         104  
17 2     2   16 use JSON::PP;
  2         5  
  2         1533  
18              
19             sub new {
20 2     2 0 11 my $class = shift;
21 2 50       17 my %args = @_ == 1 ? %{ $_[0] } : @_;
  0         0  
22              
23 2         12 for my $key (qw(directory)) {
24 2 50       10 unless ( exists $args{$key} ) {
25 0         0 Carp::croak("Missing mandatory parameter: $key");
26             }
27             }
28 2         11 my $self = bless {
29             %args,
30             }, $class;
31             $self->{filename}
32 2         33 = File::Spec->catfile( $self->{directory}, 'orepan2-cache.json' );
33 2         12 return $self;
34             }
35              
36             sub data {
37 0     0 0 0 my $self = shift;
38 0   0     0 $self->{data} ||= do {
39 0 0       0 if ( open my $fh, '<', $self->{filename} ) {
40             JSON::PP::decode_json(
41 0         0 do { local $/; <$fh> }
  0         0  
  0         0  
42             );
43             }
44             else {
45 0         0 +{};
46             }
47             };
48             }
49              
50             sub is_hit {
51 0     0 0 0 my ( $self, $stuff ) = @_;
52              
53 0         0 my $entry = $self->data->{$stuff};
54              
55 0 0 0     0 return 0 unless $entry && $entry->{filename} && $entry->{md5};
      0        
56              
57             my $fullpath
58 0         0 = File::Spec->catfile( $self->directory, $entry->{filename} );
59 0 0       0 return 0 unless -f $fullpath;
60              
61 0 0 0     0 if ( my $stat = stat($stuff) && defined( $entry->{mtime} ) ) {
62 0 0       0 return 0 if $stat->mtime ne $entry->{mtime};
63             }
64              
65 0         0 my $md5 = $self->calc_md5($fullpath);
66 0 0       0 return 0 unless $md5;
67 0 0       0 return 0 if $md5 ne $entry->{md5};
68 0         0 return 1;
69             }
70              
71             sub calc_md5 {
72 2     2 0 38 my ( $self, $filename ) = @_;
73              
74             open my $fh, '<', $filename
75 2 50       107 or do {
76 0         0 return;
77             };
78              
79 2         44 my $md5 = Digest::MD5->new();
80 2         118 $md5->addfile($fh);
81 2         49 return $md5->hexdigest;
82             }
83              
84             sub set {
85 2     2 0 21 my ( $self, $stuff, $filename ) = @_;
86              
87 2 50       17 my $md5
88             = $self->calc_md5(
89             File::Spec->catfile( $self->directory, $filename ) )
90             or Carp::croak("Cannot calcurate MD5 for '$filename'");
91 2 50       58 $self->{data}->{$stuff} = +{
92             filename => $filename,
93             md5 => $md5,
94             ( -f $filename ? ( mtime => stat($filename)->mtime ) : () ),
95             };
96 2         16 $self->is_dirty(1);
97             }
98              
99             sub save {
100 0     0 0   my ($self) = @_;
101              
102 0           my $filename = $self->{filename};
103             my $json
104 0           = JSON::PP->new->pretty(1)->canonical(1)->encode( $self->{data} );
105              
106 0           File::Path::mkpath( File::Basename::dirname($filename) );
107              
108 0           my $fh = IO::File::AtomicChange->new( $filename, 'w' );
109 0           $fh->print($json);
110 0           $fh->close(); # MUST CALL close EXPLICITLY
111             }
112              
113             1;
114