File Coverage

blib/lib/Catmandu/Store/File/BagIt.pm
Criterion Covered Total %
statement 46 49 93.8
branch 14 16 87.5
condition 2 3 66.6
subroutine 12 13 92.3
pod 0 2 0.0
total 74 83 89.1


line stmt bran cond sub pod time code
1             package Catmandu::Store::File::BagIt;
2              
3             our $VERSION = '0.260';
4              
5 3     3   246577 use Catmandu::Sane;
  3         601713  
  3         25  
6 3     3   940 use Moo;
  3         8  
  3         13  
7 3     3   1071 use Carp;
  3         6  
  3         176  
8 3     3   1586 use Catmandu;
  3         344116  
  3         16  
9 3     3   767 use Catmandu::Util;
  3         7  
  3         132  
10 3     3   1725 use Catmandu::Store::File::BagIt::Index;
  3         12  
  3         129  
11 3     3   1564 use Catmandu::Store::File::BagIt::Bag;
  3         14  
  3         107  
12 3     3   22 use namespace::clean;
  3         8  
  3         13  
13              
14             with 'Catmandu::FileStore';
15             with 'Catmandu::Droppable';
16              
17             has root => (is => 'ro', required => '1');
18             has uuid => (is => 'ro', trigger => 1);
19             has keysize => (is => 'ro', default => 9, trigger => 1);
20             has default_case => (is => 'ro', default => sub { 'upper'} , trigger => 1);
21              
22             sub _trigger_keysize {
23 6     6   521 my $self = shift;
24              
25 6 100       139 croak "keysize needs to be a multiple of 3"
26             unless $self->keysize % 3 == 0;
27             }
28              
29             sub _trigger_uuid {
30 2     2   156 my $self = shift;
31              
32 2         11 $self->{keysize} = 36;
33             }
34              
35             sub _trigger_default_case {
36 1     1   1162 my $self = shift;
37              
38 1 50       26 croak "default_case need to be `upper' or `lower`"
39             unless $self->default_case =~ /^(upper|lower)$/;
40             }
41              
42             sub path_string {
43 39     39 0 7563 my ($self, $key) = @_;
44              
45 39         94 my $keysize = $self->keysize;
46              
47 39         65 my $h;
48              
49 39 100       122 if ($self->default_case eq 'upper') {
    50          
50 35         62 $h = "[0-9A-F]";
51 35         83 $key = uc $key;
52             }
53             elsif ($self->default_case eq 'lower') {
54 4         7 $h = "[0-9a-f]";
55 4         11 $key = lc $key;
56             }
57             else {
58 0         0 croak "unkown default_case found";
59             }
60              
61             # If the key is a UUID then the matches need to be exact
62 39 100       299 if ($self->uuid) {
    100          
63 8 100       152 return undef unless $key =~ qr/\A${h}{8}-${h}{4}-${h}{4}-${h}{4}-${h}{12}\z/;
64             }
65             elsif ($key =~ qr/\A\d+\z/) {
66 30 100 66     175 return undef unless length($key) && length($key) <= $keysize;
67 27         66 $key =~ s/^0+//;
68 27         149 $key = sprintf "%-${keysize}.${keysize}d", $key;
69             }
70             else {
71 1         4 return undef;
72             }
73              
74 31         241 my $path = $self->root . "/" . join("/", unpack('(A3)*', $key));
75              
76 31         127 $path;
77             }
78              
79             sub drop {
80 0     0 0   my ($self) = @_;
81              
82 0           $self->index->delete_all;
83             }
84              
85             1;
86              
87             __END__
88              
89             =pod
90              
91             =head1 NAME
92              
93             Catmandu::Store::File::BagIt - A Catmandu::FileStore to store files on disk in the BagIt format
94              
95             =head1 SYNOPSIS
96              
97             # From the command line
98              
99             # Export a list of all file containers
100             $ catmandu export File::BagIt --root t/data to YAML
101              
102             # Export a list of all files in container '1234'
103             $ catmandu export File::BagIt --root t/data --bag 1234 to YAML
104              
105             # Add a file to the container '1234'
106             $ catmandu stream /tmp/myfile.txt to File::BagIt --root t/data --bag 1234 --id myfile.txt
107              
108             # Download the file 'myfile.txt' from the container '1234'
109             $ catmandu stream File::BagIt --root t/data --bag 1234 --id myfile.txt to /tmp/output.txt
110              
111             # Delete the file 'myfile.txt' from the container '1234'
112             $ catmandu delete File::BagIt --root t/data --bag 1234 --id myfile.txt
113              
114             # From Perl
115             use Catmandu;
116              
117             my $store = Catmandu->store('File::BagIt' , root => 't/data');
118              
119             my $index = $store->index;
120              
121             # List all folder
122             $index->bag->each(sub {
123             my $container = shift;
124              
125             print "%s\n" , $container->{_id};
126             });
127              
128             # Add a new folder
129             $index->add({ _id => '1234' });
130              
131             # Get the folder
132             my $files = $index->files('1234');
133              
134             # Add a file to the folder
135             $files->upload(IO::File->new('<foobar.txt'), 'foobar.txt');
136              
137             # Retrieve a file
138             my $file = $files->get('foobar.txt');
139              
140             # Stream the contents of a file
141             $files->stream(IO::File->new('>foobar.txt'), $file);
142              
143             # Delete a file
144             $files->delete('foobar.txt');
145              
146             # Delete a folder
147             $index->delete('1234');
148              
149             =head1 DESCRIPTION
150              
151             L<Catmandu::Store::File::BagIt> is a L<Catmandu::FileStore> implementation to
152             store files in a directory structure. Each L<Catmandu::FileBag> is
153             a deeply nested directory based on the numeric identifier of the bag. E.g.
154              
155             $store->bag(1234)
156              
157             is stored as
158              
159             ${ROOT}/000/001/234
160              
161             In this directory all the L<Catmandu::FileBag> items are stored as
162             flat files.
163              
164             =head1 METHODS
165              
166             =head2 new(root => $path , [ keysize => NUM , uuid => 1 , default_case => 'upper|lower'])
167              
168             Create a new Catmandu::Store::File::BagIt with the following configuration
169             parameters:
170              
171             =over
172              
173             =item root
174              
175             The root directory where to store all the files. Required.
176              
177             =item keysize
178              
179             By default the directory structure is 3 levels deep. With the keysize option
180             a deeper nesting can be created. The keysize needs to be a multiple of 3.
181             All the container keys of a L<Catmandu::Store::File::BagIt> must be integers.
182              
183             =item uuid
184              
185             If the to a true value, then the Simple store will require UUID-s as keys
186              
187             =item default_case
188              
189             When set to 'upper' all stored identifier paths will be translated to uppercase
190             (e.g. for UUID paths). When set to 'lower' all identifier paths will be
191             translated to lowercase. Default: 'upper'
192              
193             =back
194              
195             =head1 LARGE FILE SUPPORT
196              
197             Streaming large files into a BagIt requires a large /tmp directory. The location
198             of the temp directory can be set with the TMPDIR environmental variable.
199              
200             =head1 INHERITED METHODS
201              
202             This Catmandu::FileStore implements:
203              
204             =over 3
205              
206             =item L<Catmandu::FileStore>
207              
208             =item L<Catmandu::Droppable>
209              
210             =back
211              
212             The index Catmandu::Bag in this Catmandu::Store implements:
213              
214             =over 3
215              
216             =item L<Catmandu::Bag>
217              
218             =item L<Catmandu::FileBag::Index>
219              
220             =item L<Catmandu::Droppable>
221              
222             =back
223              
224             The file Catmandu::Bag in this Catmandu::Store implements:
225              
226             =over 3
227              
228             =item L<Catmandu::Bag>
229              
230             =item L<Catmandu::FileBag>
231              
232             =item L<Catmandu::Droppable>
233              
234             =back
235              
236             =head1 SEE ALSO
237              
238             L<Catmandu::Store::File::BagIt::Index>,
239             L<Catmandu::Store::File::BagIt::Bag>,
240             L<Catmandu::Plugin::SideCar>,
241             L<Catmandu::FileStore>
242              
243             =cut