File Coverage

blib/lib/Beam/Make/Cache.pm
Criterion Covered Total %
statement 58 58 100.0
branch 5 6 83.3
condition 7 9 77.7
subroutine 12 12 100.0
pod 2 2 100.0
total 84 87 96.5


line stmt bran cond sub pod time code
1             package Beam::Make::Cache;
2             our $VERSION = '0.003';
3             # ABSTRACT: Store information about recipes performed
4              
5             #pod =head1 SYNOPSIS
6             #pod
7             #pod my $cache = Beam::Make::Cache->new;
8             #pod
9             #pod # Update the cache and track what the content should be
10             #pod $cache->set( 'recipe', 'content hash' );
11             #pod
12             #pod # Set the last modified time to a specific time by passing
13             #pod # a Time::Piece object
14             #pod $cache->set( 'recipe', 'content hash', $timestamp );
15             #pod
16             #pod # Get a Time::Piece object if the content hashes match
17             #pod # Otherwise returns 0
18             #pod my $time = $cache->last_modified( 'recipe', 'content hash' );
19             #pod
20             #pod =head1 DESCRIPTION
21             #pod
22             #pod This class provides an API to access timestamps and content hashes to validate
23             #pod recipes and determine which recipes are out-of-date and should be re-run.
24             #pod
25             #pod =head2 Limitations
26             #pod
27             #pod The cache file cannot be accessed by more than one process. This limitation may
28             #pod be fixed in the future. Other cache modules that use distributed databases may
29             #pod also be created in the future.
30             #pod
31             #pod =head1 SEE ALSO
32             #pod
33             #pod L<Beam::Make>
34             #pod
35             #pod =cut
36              
37 4     4   105471 use v5.20;
  4         20  
38 4     4   32 use warnings;
  4         12  
  4         103  
39 4     4   563 use Moo;
  4         9999  
  4         27  
40 4     4   3232 use experimental qw( signatures postderef );
  4         3568  
  4         33  
41 4     4   3165 use File::stat;
  4         28898  
  4         23  
42 4     4   273 use Time::Piece;
  4         10  
  4         60  
43 4     4   360 use Scalar::Util qw( blessed );
  4         9  
  4         157  
44 4     4   516 use YAML ();
  4         7069  
  4         2287  
45              
46             #pod =attr file
47             #pod
48             #pod The path to a file to use for the cache. Defaults to C<.Beamfile.cache> in
49             #pod the current directory.
50             #pod
51             #pod =cut
52              
53             has file => ( is => 'ro', default => sub { '.Beamfile.cache' } );
54             has _last_read => ( is => 'rw', default => 0 );
55             has _cache => ( is => 'rw', default => sub { {} } );
56              
57             #pod =method set
58             #pod
59             #pod $cache->set( $name, $hash, $time );
60             #pod
61             #pod # Update modified time to now
62             #pod $cache->set( $name, $hash );
63             #pod
64             #pod Set an entry in the cache. C<$name> is the recipe name. C<$hash> is an identifier
65             #pod for the content (usually a base64 SHA-1 hash from L<Digest::SHA>). C<$time> is a
66             #pod L<Time::Piece> object to save as the last modified time. If C<$time> is not provided,
67             #pod defaults to now.
68             #pod
69             #pod =cut
70              
71 10     10 1 2447 sub set( $self, $name, $hash, $time=Time::Piece->new ) {
  10         88  
  10         119  
  10         59  
  10         229  
  10         1509  
72 10         51 my $cache = $self->_fetch_cache;
73 10 50       204 $cache->{ $name } = {
74             hash => $hash,
75             time => blessed $time eq 'Time::Piece' ? $time->epoch : $time,
76             };
77 10         430 $self->_write_cache( $cache );
78             }
79              
80             #pod =method last_modified
81             #pod
82             #pod my $time = $cache->last_modified( $name, $hash );
83             #pod
84             #pod Get the last modified timestamp (as a L<Time::Piece> object) for the
85             #pod given recipe C<$name>. If the C<$hash> does not match what was given to
86             #pod L</set>, or if the recipe has never been made, returns C<0>.
87             #pod
88             #pod =cut
89              
90 39     39 1 4348 sub last_modified( $self, $name, $hash ) {
  39         104  
  39         107  
  39         83  
  39         56  
91 39         129 my $cache = $self->_fetch_cache;
92             return Time::Piece->new( $cache->{ $name }{ time } )
93             if $cache->{ $name }
94 39 100 100     467 && $cache->{ $name }{ hash } eq $hash
95             ;
96 6         45 return 0;
97             }
98              
99 59     59   125 sub _fetch_cache( $self ) {
  59         113  
  59         108  
100 59         216 my $last_read = $self->_last_read;
101 59 100 66     1348 if ( -e $self->file && ( !$last_read || stat( $self->file )->mtime > $last_read ) ) {
      66        
102 5         137 $self->_last_read( stat( $self->file )->mtime );
103 5         1583 $self->_cache( YAML::LoadFile( $self->file ) );
104             }
105 59         62121 return $self->_cache;
106             }
107              
108 10     10   32 sub _write_cache( $self, $cache ) {
  10         45  
  10         32  
  10         24  
109 10         41 my $old_cache = $self->_fetch_cache;
110 10         106 $cache = { %$old_cache, %$cache };
111 10         176 YAML::DumpFile( $self->file, $cache );
112 10         71668 $self->_cache( $cache );
113 10         106 $self->_last_read( stat( $self->file )->mtime );
114 10         2309 return;
115             }
116              
117             1;
118              
119             __END__
120              
121             =pod
122              
123             =head1 NAME
124              
125             Beam::Make::Cache - Store information about recipes performed
126              
127             =head1 VERSION
128              
129             version 0.003
130              
131             =head1 SYNOPSIS
132              
133             my $cache = Beam::Make::Cache->new;
134              
135             # Update the cache and track what the content should be
136             $cache->set( 'recipe', 'content hash' );
137              
138             # Set the last modified time to a specific time by passing
139             # a Time::Piece object
140             $cache->set( 'recipe', 'content hash', $timestamp );
141              
142             # Get a Time::Piece object if the content hashes match
143             # Otherwise returns 0
144             my $time = $cache->last_modified( 'recipe', 'content hash' );
145              
146             =head1 DESCRIPTION
147              
148             This class provides an API to access timestamps and content hashes to validate
149             recipes and determine which recipes are out-of-date and should be re-run.
150              
151             =head2 Limitations
152              
153             The cache file cannot be accessed by more than one process. This limitation may
154             be fixed in the future. Other cache modules that use distributed databases may
155             also be created in the future.
156              
157             =head1 ATTRIBUTES
158              
159             =head2 file
160              
161             The path to a file to use for the cache. Defaults to C<.Beamfile.cache> in
162             the current directory.
163              
164             =head1 METHODS
165              
166             =head2 set
167              
168             $cache->set( $name, $hash, $time );
169              
170             # Update modified time to now
171             $cache->set( $name, $hash );
172              
173             Set an entry in the cache. C<$name> is the recipe name. C<$hash> is an identifier
174             for the content (usually a base64 SHA-1 hash from L<Digest::SHA>). C<$time> is a
175             L<Time::Piece> object to save as the last modified time. If C<$time> is not provided,
176             defaults to now.
177              
178             =head2 last_modified
179              
180             my $time = $cache->last_modified( $name, $hash );
181              
182             Get the last modified timestamp (as a L<Time::Piece> object) for the
183             given recipe C<$name>. If the C<$hash> does not match what was given to
184             L</set>, or if the recipe has never been made, returns C<0>.
185              
186             =head1 SEE ALSO
187              
188             L<Beam::Make>
189              
190             =head1 AUTHOR
191              
192             Doug Bell <preaction@cpan.org>
193              
194             =head1 COPYRIGHT AND LICENSE
195              
196             This software is copyright (c) 2020 by Doug Bell.
197              
198             This is free software; you can redistribute it and/or modify it under
199             the same terms as the Perl 5 programming language system itself.
200              
201             =cut