File Coverage

blib/lib/Acme/Archive/Mbox.pm
Criterion Covered Total %
statement 68 68 100.0
branch 5 10 50.0
condition 2 3 66.6
subroutine 11 11 100.0
pod 6 6 100.0
total 92 98 93.8


line stmt bran cond sub pod time code
1             package Acme::Archive::Mbox;
2              
3 2     2   61887 use warnings;
  2         6  
  2         65  
4 2     2   13 use strict;
  2         4  
  2         61  
5              
6 2     2   1066 use Acme::Archive::Mbox::File;
  2         4  
  2         50  
7 2     2   2011 use File::Slurp;
  2         49763  
  2         804  
8 2     2   2832 use Mail::Box::Manager;
  2         462709  
  2         1661  
9              
10             =head1 NAME
11              
12             Acme::Archive::Mbox - Mbox as an archive format.
13              
14             =head1 VERSION
15              
16             Version 0.01
17              
18             =cut
19              
20             our $VERSION = '0.01';
21              
22              
23             =head1 SYNOPSIS
24              
25             Uses Mbox as an archive format, like tar or zip but silly. Creates an mbox
26             with one message per file or directory. File contents are stored as an
27             attachment, metadata goes in mail headers.
28              
29             use Acme::Archive::Mbox;
30              
31             my $archive = Acme::Archive::Mbox->new();
32             $archive->add_file('filename');
33             $archive->add_data('file/name', $contents);
34             $archive->write('foo.mbox');
35              
36             ...
37              
38             $archive->read('foo.mbox');
39             $archive->extract();
40              
41             =head1 FUNCTIONS
42              
43             =head2 new ()
44              
45             Create an Acme::Archive::Mbox object.
46              
47             =cut
48              
49             sub new {
50 2     2 1 9928 my $class = shift;
51 2         11 my $self = { files => [] };
52 2         12 return bless $self,$class;
53             }
54              
55             =head2 add_data ($name, $contents, %attr)
56              
57             Add a file given a filename and contents. (File need not exist on disk)
58              
59             =cut
60              
61             sub add_data {
62 4     4 1 999 my $self = shift;
63 4         12 my $name = shift;
64 4         9 my $contents = shift;
65 4         20 my %attr = @_;
66              
67 4         33 my $file = Acme::Archive::Mbox::File->new($name, $contents, %attr);
68 4 50       21 push @{$self->{files}}, $file if $file;
  4         15  
69              
70 4         25 return $file;
71             }
72              
73             =head2 add_file ($name, [$archive_name])
74              
75             Add a file given a filename. File will be read from disk, leading
76             slashes will be stripped. Will accept an optional alternative filename
77             to be used in the archive.
78              
79             =cut
80              
81             sub add_file {
82 2     2 1 3 my $self = shift;
83 2         4 my $name = shift;
84 2   66     11 my $altname = shift || $name;
85 2         4 my %attr;
86              
87 2         12 my $contents = read_file($name, err_mode => 'carp', binmode => ':raw');
88 2 50       331 return unless $contents;
89              
90 2         31 my (undef, undef, $mode, undef, $uid, $gid, undef, undef, undef, $mtime) = stat $name;
91 2         7 $attr{mode} = $mode & 0777;
92 2         5 $attr{uid} = $uid;
93 2         4 $attr{gid} = $gid;
94 2         5 $attr{mtime} = $mtime;
95              
96 2         17 my $file = Acme::Archive::Mbox::File->new($altname, $contents, %attr);
97 2 50       8 push @{$self->{files}}, $file if $file;
  2         5  
98              
99 2         38 return $file;
100             }
101              
102             =head2 get_files ()
103              
104             Returns a list of AAM::File objects.
105              
106             =cut
107              
108             sub get_files {
109 2     2 1 1100 my $self = shift;
110 2         5 return @{$self->{files}};
  2         11  
111             }
112              
113             =head2 write (filename)
114              
115             Write archive to a file
116              
117             =cut
118              
119             sub write {
120 1     1 1 554 my $self = shift;
121 1         3 my $mboxname = shift;
122            
123 1         18 my $mgr = Mail::Box::Manager->new;
124 1 50       141 my $folder = $mgr->open($mboxname, type => 'mbox', create => 1, access => 'rw') or die "Could not create $mboxname";
125              
126 1         31708 for my $file (@{$self->{files}}) {
  1         6  
127 3         941 my $attach = Mail::Message::Body->new( mime_type => 'application/octet-stream',
128             data => $file->contents,
129             );
130              
131 3         1043 my $message = Mail::Message->build( From => '"Acme::Archive::Mbox" ',
132             To => '"Anyone, really" ',
133             Subject => $file->name,
134             'X-AAM-uid' => $file->uid,
135             'X-AAM-gid' => $file->gid,
136             'X-AAM-mode' => $file->mode,
137             'X-AAM-mtime' => $file->mtime,
138              
139             data => 'attached',
140             attach => $attach, );
141 3         153119 $folder->addMessage($message);
142             }
143 1         371 $folder->write();
144 1         25440 $mgr->close($folder);
145             }
146              
147             =head2 read (filename)
148              
149             Read archive from a file.
150              
151             =cut
152              
153             sub read {
154 1     1 1 8 my $self = shift;
155 1         5 my $mboxname = shift;
156              
157 1         12 my $mgr = Mail::Box::Manager->new;
158 1 50       1297 my $folder = $mgr->open($mboxname, type => 'mbox') or die "Could not open $mboxname";
159 1         48461 my @messages = $folder->messages;
160 1         12 for my $message (@messages) {
161 3         4 my %attr;
162 3         10 my $name = $message->get('Subject');
163 3         203 for (qw/uid gid mode mtime/) {
164 12         512 $attr{$_} = $message->get("X-AAM-$_");
165             }
166 3         163 my $contents = ($message->parts())[1]->decoded();
167              
168 3         2090 $self->add_data($name, $contents, %attr);
169             }
170 1         6 $mgr->close($folder);
171             }
172              
173             =head1 AUTHOR
174              
175             Ian Kilgore, C<< >>
176              
177             =head1 BUGS
178              
179             =over 4
180              
181             =item Undefined behavior in spades. Anyone using this probably deserves it.
182              
183             =item Fails to overwrite or truncate when creating archives
184              
185             =item As Acme::Archive::Mbox does not store directories, directory
186             mode and ownership will not be preserved.
187              
188             =back
189              
190             =head1 SUPPORT
191              
192             You can find documentation for this module with the perldoc command.
193              
194             perldoc Acme::Archive::Mbox
195              
196              
197             You can also look for information at:
198              
199             =over 4
200              
201             =item * RT: CPAN's request tracker
202              
203             L
204              
205             =item * AnnoCPAN: Annotated CPAN documentation
206              
207             L
208              
209             =item * CPAN Ratings
210              
211             L
212              
213             =item * Search CPAN
214              
215             L
216              
217             =back
218              
219              
220             =head1 ACKNOWLEDGEMENTS
221              
222              
223             =head1 COPYRIGHT & LICENSE
224              
225             Copyright 2008 Ian Kilgore, all rights reserved.
226              
227             This program is free software; you can redistribute it and/or modify it
228             under the same terms as Perl itself.
229              
230              
231             =cut
232              
233             1; # End of Acme::Archive::Mbox