File Coverage

blib/lib/Archive/Builder/Section.pm
Criterion Covered Total %
statement 92 107 85.9
branch 33 40 82.5
condition 2 4 50.0
subroutine 26 29 89.6
pod 0 17 0.0
total 153 197 77.6


line stmt bran cond sub pod time code
1             package Archive::Builder::Section;
2              
3             # A section is a tree of Archive::Builder::File's
4              
5 7     7   166 use 5.005;
  7         30  
  7         277  
6 7     7   35 use strict;
  7         15  
  7         241  
7 7     7   42 use Scalar::Util ('refaddr');
  7         15  
  7         479  
8 7     7   339 use Params::Util ('_INSTANCE');
  7         20  
  7         334  
9 7     7   117 use Archive::Builder ();
  7         16  
  7         151  
10              
11 7     7   35 use vars qw{$VERSION %_PARENT};
  7         14  
  7         448  
12             BEGIN {
13 7     7   20 $VERSION = '1.16';
14 7         11491 %_PARENT = ();
15             }
16              
17              
18              
19              
20              
21             #####################################################################
22             # Main interface methods
23              
24             # A Section's only creation property is its name
25             sub new {
26 25     25 0 2774 my $class = shift;
27 25 100       123 my $name = Archive::Builder->_check( 'name', $_[0] ) ? shift
28             : return $class->_error( 'Invalid section name format' );
29              
30             # Create the object
31 13         156 bless {
32             name => $name,
33             path => $name,
34             zfiles => {},
35             }, $class;
36             }
37              
38             # Get the name
39 19     19 0 1589 sub name { $_[0]->{name} }
40              
41             # Get or set the path
42             sub path {
43 46     46 0 2717 my $self = shift;
44 46 100       276 return $self->{path} unless @_;
45              
46             # Set the path
47 8 100       36 my $path = Archive::Builder->_relative_path($_[0]) ? shift : return undef;
48 3         10 $self->{path} = $path;
49              
50 3         15 1;
51             }
52              
53             # Test generate and cache all files
54             sub test {
55 0     0 0 0 my $self = shift;
56              
57             # Generate each file
58 0         0 foreach my $File ( $self->file_list ) {
59 0 0       0 unless ( defined $File->contents ) {
60 0         0 return $self->_error( "Generation failed for file '" . $File->path
61             . "' in section '$self->{name}': "
62             . $File->errstr );
63             }
64             }
65              
66 0         0 1;
67             }
68              
69             # Save the entire section
70             sub save {
71 4     4 0 7 my $self = shift;
72 4   50     15 my $base = shift || '.';
73              
74             # Can we write to the base location
75 4 50       20 unless ( File::Flat->canWrite( $base ) ) {
76 0         0 return $self->_error( "Insufficient permissions to write below $base" );
77             }
78              
79             # Save each of the files
80 4         1292 foreach my $File ( $self->file_list ) {
81 12         47 my $filename = File::Spec->catfile( $base, $File->path );
82 12 50       56 unless ( $File->save( $filename ) ) {
83 0         0 return $self->_error( "Failed to save file '$filename' in Section '$self->{name}'" );
84             }
85             }
86              
87 4         26 1;
88             }
89              
90             # Get the parent for the Section, if one exists
91             sub Builder {
92 3     3 0 25 $_PARENT{ refaddr $_[0] };
93             }
94              
95             # Delete this from from its parent, and remove all our children
96             sub delete {
97 0     0 0 0 my $self = shift;
98 0 0       0 if ( $self->Builder ) {
99             # Remove from our parent
100 0         0 $self->Builder->remove_section( $self->path );
101             }
102              
103             # Remove all our children
104 0         0 foreach ( $self->file_list ) {
105 0         0 delete $Archive::Builder::File::_PARENT{ refaddr $_ };
106             }
107 0         0 $self->{zfiles} = {};
108              
109 0         0 1;
110             }
111              
112             # If any files have been generated, flush the content cache
113             # so they will be generated again.
114             # Just pass the call down to the files.
115             sub reset {
116 3     3 0 14 foreach ( $_[0]->file_list ) {
117 3         29 $_->reset;
118             }
119 3         13 1;
120             }
121              
122             # Get an Archive for just this section
123             sub archive {
124 0     0 0 0 Archive::Builder::Archive->new( $_[1], $_[0] );
125             }
126              
127             # Get the archive content hash
128             sub _archive_content {
129 9     9   15 my $self = shift;
130              
131             # Add from each of the Files
132 9         17 my %tree = ();
133 9         47 foreach my $File ( $self->file_list ) {
134 35 50       113 my $contents = $File->contents or return undef;
135 35         105 $tree{$File->path} = $contents;
136             }
137              
138 9         60 \%tree;
139             }
140              
141             # Get the archive mode hash
142             sub _archive_mode {
143 9     9   12 my $self = shift;
144              
145             # Add for each file that needs an executable bit
146 9         14 my %tree = ();
147 9         24 foreach my $File ( $self->file_list ) {
148 35 100       144 $tree{$File->path} = $File->{executable} ? 0755 : 0644;
149             }
150              
151 9         49 \%tree;
152             }
153              
154              
155              
156              
157              
158             #####################################################################
159             # Working with files
160              
161             # Add a new file and return it
162             sub new_file {
163 37     37 0 39028 my $self = shift;
164              
165             # Create the File
166 37 100       231 my $File = Archive::Builder::File->new( @_ )
167             or return undef;
168              
169             # Add the file
170 26 100       166 $self->add_file( $File ) ? $File : undef;
171             }
172              
173             # Add a new file
174             sub add_file {
175 33     33 0 14230 my $self = shift;
176 33 100       425 my $File = _INSTANCE(shift, 'Archive::Builder::File' )
177             or return $self->_error( 'Did not pass a File as argument' );
178              
179             # Does the file clash with an existing one
180 28 100       115 unless ( $self->_no_path_clashes( $File->path ) ) {
181 5         15 return $self->_error( "Bad file path: " . $self->errstr );
182             }
183              
184             # Add the File
185 23         115 $self->{zfiles}->{$File->path} = $File;
186            
187             # Add its parent reference
188 23         106 $Archive::Builder::File::_PARENT{ refaddr $File } = $self;
189            
190 23         102 1;
191             }
192              
193             # Get a copy of the hash of files
194 2 100   2 0 2168 sub files { %{ $_[0]->{zfiles} } ? { %{ $_[0]->{zfiles} } } : 0 }
  2         17  
  1         12  
195              
196             # Return the files as a List, sorted by file name
197             sub file_list {
198 28     28 0 101 my $files = $_[0]->{zfiles};
199 28         137 map { $files->{$_} } sort keys %$files;
  93         221  
200             }
201              
202             # Get a single file by name
203 13 100   13 0 3013 sub file { defined $_[1] ? $_[0]->{zfiles}->{$_[1]} : undef }
204              
205             # Remove a single file by name
206             sub remove_file {
207 4     4 0 14 my $self = shift;
208 4 100       16 my $name = defined $_[0] ? shift : return undef;
209 3 100       20 my $File = $self->{zfiles}->{$name} or return undef;
210              
211             # Delete from our files
212 2         8 delete $self->{zfiles}->{$name};
213              
214             # Remove the parent link
215 2         12 delete $Archive::Builder::File::_PARENT{ refaddr $File };
216              
217 2         8 1;
218             }
219              
220             # Get a count of the number of files
221 18     18 0 4982 sub file_count { scalar keys %{ $_[0]->{zfiles} } }
  18         233  
222              
223             # Does a path clash with an existing path.
224             # A clash occurs if two paths are exactly the same,
225             # or a situation will occur where a file and directory
226             # of the same will would exist, which will fail on writing out
227             # to disk.
228             sub _no_path_clashes {
229 28     28   222 my $self = shift;
230 28         87 my $path = shift;
231              
232             # Iterate over the file paths
233 28         40 foreach ( sort keys %{ $self->{zfiles} } ) {
  28         148  
234             # Are they the same.
235 32 100       91 if ( $path eq $_ ) {
236 3         17 return $self->_error( "The file '$path' already exists" );
237             }
238              
239             # Does our file already exist as a directory
240             ### THIS DOES NOT SUPPORT VMS...
241             ### I can't decifer File::Spec::VMS well enough
242 29   50     392 my $directory_seperator = {
243             MacOS => ':',
244             Win32 => '\\',
245             dos => '\\'
246             }->{$0} || '/';
247 29 100       510 if ( $_ =~ m!^$path$directory_seperator! ) {
248 1         7 return $self->_error( "The file '$path' would clash with a directory of the same name" );
249             }
250              
251             # Would the creation of our file involve a directory
252             # that already exists as a file
253 28 100       290 if ( $path =~ m!$_$directory_seperator! ) {
254 1         9 return $self->_error( "The file '$path' would create a directory that clash with an existing file '$_'" );
255             }
256             }
257              
258 23         93 1;
259             }
260              
261              
262              
263              
264             #####################################################################
265             # Utility methods
266              
267             # Pass through error
268 34     34 0 15725 sub errstr { Archive::Builder->errstr }
269 29     29   1219 sub _error { shift; Archive::Builder->_error(@_) }
  29         122  
270 2     2   1060 sub _clear { Archive::Builder->_clear }
271              
272             1;
273              
274             __END__