File Coverage

blib/lib/Catmandu/Store/File/BagIt/Bag.pm
Criterion Covered Total %
statement 66 67 98.5
branch 4 6 66.6
condition n/a
subroutine 19 20 95.0
pod 0 5 0.0
total 89 98 90.8


line stmt bran cond sub pod time code
1             package Catmandu::Store::File::BagIt::Bag;
2              
3 3     3   23 use Catmandu::Sane;
  3         8  
  3         20  
4              
5             our $VERSION = '0.260';
6              
7 3     3   599 use Moo;
  3         6  
  3         23  
8 3     3   1060 use Carp;
  3         9  
  3         186  
9 3     3   77 use IO::File;
  3         8  
  3         513  
10 3     3   20 use Path::Tiny;
  3         7  
  3         241  
11 3     3   28 use File::Spec;
  3         6  
  3         101  
12 3     3   16 use Catmandu::Sane;
  3         5  
  3         16  
13 3     3   2242 use Catmandu::BagIt;
  3         10  
  3         165  
14 3     3   21 use Catmandu::Util qw(content_type);
  3         8  
  3         153  
15 3     3   26 use URI::Escape;
  3         73  
  3         173  
16 3     3   20 use POSIX qw(strftime);
  3         5  
  3         34  
17 3     3   211 use namespace::clean;
  3         80  
  3         20  
18              
19             with 'Catmandu::Bag';
20             with 'Catmandu::FileBag';
21             with 'Catmandu::Droppable';
22              
23             has _path => (is => 'lazy');
24             has _bagit => (is => 'lazy');
25              
26             sub _build__path {
27 1     1   11 my $self = shift;
28 1         8 $self->store->path_string($self->name);
29             }
30              
31             sub _build__bagit {
32 1     1   11 my $self = shift;
33 1         17 my $bag = Catmandu::BagIt->read($self->_path);
34 1 50       5 $bag->{escape} = 0 if $bag; # This implementation does its own file escaping...
35 1         10 $bag;
36             }
37              
38             sub generator {
39 4     4 0 1477 my ($self) = @_;
40 4         92 my $path = $self->_path;
41 4         98 my $bagit = $self->_bagit;
42              
43             sub {
44 11     11   127 state $children = [$bagit->list_files];
45              
46 11         25 my $child = shift @$children;
47              
48 11 100       35 return undef unless $child;
49              
50 7         19 my $file = $child->filename;
51              
52 7         18 my $unpacked_key = $self->unpack_key($file);
53              
54 7         158 return $self->get($unpacked_key);
55 4         42 };
56             }
57              
58             sub exists {
59 3     3 0 1980 my ($self, $id) = @_;
60 3         75 my $path = $self->_path;
61 3         83 my $bagit = $self->_bagit;
62              
63 3         26 my $packed_key = $self->pack_key($id);
64              
65 3 50       44 $bagit->get_checksum($packed_key) ? 1 : 0;
66             }
67              
68             sub get {
69             my ($self, $id) = @_;
70              
71             my $path = $self->_path;
72             my $bagit = $self->_bagit;
73              
74             my $packed_key = $self->pack_key($id);
75              
76             my $file = $bagit->get_file($packed_key);
77              
78             return undef unless $file;
79              
80             my $stat = [stat $file->path];
81              
82             my $size = $stat->[7];
83             my $modified = $stat->[9];
84             my $created = $stat->[10]; # no real creation time exists on Unix
85              
86             my $content_type = content_type($id);
87              
88             return {
89             _id => $id,
90             size => $size,
91             md5 => $bagit->get_checksum($packed_key) // undef,
92             content_type => $content_type,
93             created => $created,
94             modified => $modified,
95             _stream => sub {
96             $self->file_streamer($file->path,shift);
97             }
98             };
99             }
100              
101             sub add {
102             my ($self, $data) = @_;
103             my $path = $self->_path;
104             my $bagit = $self->_bagit;
105              
106             my $update = 1;
107              
108             unless ($bagit) {
109             $update = 0;
110             $bagit = Catmandu::BagIt->new(algorithm => 'md5', escape => 0);
111             $self->{_bagit} = $bagit;
112             }
113              
114             my $id = $data->{_id};
115             my $io = $data->{_stream};
116              
117             return $self->get($id) unless $io;
118              
119             my $packed_key = $self->pack_key($id);
120              
121             $bagit->add_file($packed_key,$io,overwrite => 1);
122              
123             unless ($update) {
124             $bagit->remove_info('Bagging-Date');
125             $bagit->add_info('Bagging-Date', strftime("%Y-%M-%D", gmtime));
126             }
127              
128             $bagit->remove_info('Bagging-Update');
129             $bagit->add_info('Bagging-Update', strftime("%Y-%m-%d", gmtime));
130              
131             $bagit->write($path, overwrite => 1);
132              
133             my $new_data = $self->get($id);
134              
135             $data->{$_} = $new_data->{$_} for keys %$new_data;
136              
137             1;
138             }
139              
140             sub delete {
141             my ($self, $id) = @_;
142             my $path = $self->_path;
143             my $bagit = $self->_bagit;
144              
145             my $packed_key = $self->pack_key($id);
146              
147             my $file = $bagit->get_file($packed_key);
148              
149             return undef unless $file;
150              
151             $bagit->remove_file($packed_key);
152              
153             $bagit->write($path, overwrite => 1);
154             }
155              
156             sub delete_all {
157             my ($self) = @_;
158              
159             $self->each(
160             sub {
161             my $key = shift->{_id};
162             $self->delete($key);
163             }
164             );
165              
166             1;
167             }
168              
169             sub drop {
170 0     0 0 0 $_[0]->delete_all;
171             }
172              
173             sub commit {
174             return 1;
175             }
176              
177             sub pack_key {
178 26     26 0 45 my $self = shift;
179 26         48 my $key = shift;
180 26         80 utf8::encode($key);
181 26         75 uri_escape($key);
182             }
183              
184             sub unpack_key {
185 7     7 0 13 my $self = shift;
186 7         10 my $key = shift;
187 7         21 my $str = uri_unescape($key);
188 7         106 utf8::decode($str);
189 7         15 $str;
190             }
191              
192             1;
193              
194             __END__
195              
196             =pod
197              
198             =head1 NAME
199              
200             Catmandu::Store::File::BagIt::Bag - Index of all "files" in a Catmandu::Store::File::BagIt "folder"
201              
202             =head1 SYNOPSIS
203              
204             use Catmandu;
205              
206             my $store = Catmandu->store('File::BagIt' , root => 't/data');
207              
208             my $index = $store->index;
209              
210             # List all containers
211             $index->each(sub {
212             my $container = shift;
213              
214             print "%s\n" , $container->{_id};
215             });
216              
217             # Add a new folder
218             $index->add({_id => '1234'});
219              
220             # Delete a folder
221             $index->delete(1234);
222              
223             # Get a folder
224             my $folder = $index->get(1234);
225              
226             # Get the files in an folder
227             my $files = $index->files(1234);
228              
229             $files->each(sub {
230             my $file = shift;
231              
232             my $name = $file->_id;
233             my $size = $file->size;
234             my $content_type = $file->content_type;
235             my $created = $file->created;
236             my $modified = $file->modified;
237              
238             $file->stream(IO::File->new(">/tmp/$name"), file);
239             });
240              
241             # Add a file
242             $files->upload(IO::File->new("<data.dat"),"data.dat");
243              
244             # Retrieve a file
245             my $file = $files->get("data.dat");
246              
247             # Stream a file to an IO::Handle
248             $files->stream(IO::File->new(">data.dat"),$file);
249              
250             # Delete a file
251             $files->delete("data.dat");
252              
253             # Delete a folders
254             $index->delete("1234");
255              
256             =head1 INHERITED METHODS
257              
258             This Catmandu::Bag implements:
259              
260             =over 3
261              
262             =item L<Catmandu::Bag>
263              
264             =item L<Catmandu::FileBag>
265              
266             =item L<Catmandu::Droppable>
267              
268             =back
269              
270             =cut