File Coverage

blib/lib/Test/File/Cleaner/State.pm
Criterion Covered Total %
statement 46 55 83.6
branch 22 46 47.8
condition 1 3 33.3
subroutine 10 12 83.3
pod 7 7 100.0
total 86 123 69.9


line stmt bran cond sub pod time code
1             package Test::File::Cleaner::State;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Test::File::Cleaner::State - State information for Test::File::Cleaner
8              
9             =head1 DESCRIPTION
10              
11             A Test::File::Cleaner::State object stores the state information for a single
12             file or directory, and performs tasks to restore old states.
13              
14             =head1 METHODS
15              
16             =cut
17              
18 2     2   50 use 5.005;
  2         7  
  2         73  
19 2     2   19 use strict;
  2         3  
  2         54  
20 2     2   866 use File::stat ();
  2         7138  
  2         45  
21              
22 2     2   12 use vars qw{$VERSION $DEBUG};
  2         4  
  2         115  
23             BEGIN {
24 2     2   5 $VERSION = '0.03';
25 2         1225 *DEBUG = *Test::File::Cleaner::DEBUG;
26             }
27              
28             =pod
29              
30             =head2 new $file
31              
32             Creates a new State object for a given file name. The file or directory must
33             exist.
34              
35             Returns a new Test::File::Cleaner::State object, or dies on error.
36              
37             =cut
38              
39             sub new {
40 19   33 19 1 74 my $class = ref $_[0] || $_[0];
41 19 50       281 my $path = -e $_[1] ? $_[1]
42             : die "Tried to create $class object for non-existant file '$_[1]'";
43 19 50       71 my $Stat = File::stat::stat( $path )
44             or die "Failed to get a stat on '$path'";
45              
46             # Create the basic object
47 19         2769 return bless {
48             path => $path,
49             dir => -d $path,
50             Stat => $Stat,
51             }, $class;
52             }
53              
54              
55              
56              
57              
58             #####################################################################
59             # Accessors
60              
61             =pod
62              
63             =head2 path
64              
65             Returns the path of the file
66              
67             =cut
68              
69             sub path {
70 0     0 1 0 $_[0]->{path};
71             }
72              
73             =pod
74              
75             =head2 dir
76              
77             Returns true if the state object is a directory
78              
79             =cut
80              
81             sub dir {
82 50     50 1 297 $_[0]->{dir};
83             }
84              
85             =pod
86              
87             =head2 Stat
88              
89             Returns the L object for the file
90              
91             =cut
92              
93             sub Stat {
94 0     0 1 0 $_[0]->{Stat};
95             }
96              
97             =pod
98              
99             =head2 mode
100              
101             Returns the permissions mode for the file/directory
102              
103             =cut
104              
105             sub mode {
106 10     10 1 404 my $mode = $_[0]->{Stat}->mode;
107 10 50       92 return undef unless defined $mode;
108 10         21 $mode & 07777;
109             }
110              
111              
112              
113              
114              
115             #####################################################################
116             # Action Methods
117              
118             =pod
119              
120             =head2 clean
121              
122             Cleans the state object, by examining the new state of the file, and
123             reverting it to the old one if possible.
124              
125             =cut
126              
127             sub clean {
128 10     10 1 23 my $self = shift;
129 10 100       29 my $term = $self->dir ? "directory" : "file";
130 10         27 my $path = $self->{path};
131              
132             # Does the file/dir still exist
133 10 50       179 unless ( -e $path ) {
134 0         0 Carp::croak("The original $term '$path' no longer exists");
135             }
136              
137             # Is it still a file/directory?
138 10         123 my $dir = -d $path;
139 10 50       33 unless ( $dir eq $self->dir ) {
140 0         0 die "File/directory mismatch for '$path'";
141             }
142              
143             # Do we care about modes
144 10         31 my $mode = $self->mode;
145 10 50       32 return 1 unless defined $mode;
146              
147             # Yes, has the mode changed?
148 10         41 my $mode2 = File::stat::stat($path)->mode & 07777;
149 10 100       1814 unless ( $mode == $mode2 ) {
150             # Revert the permissions to match the old one
151 1 50       6 printf( "# chmod 0%lo %s\n", $mode, $path ) if $DEBUG;
152 1 50       53 chmod $mode, $path or die "Failed to correct permissions mode for $term '$path'";
153             }
154              
155 10         32 1;
156             }
157              
158             =pod
159              
160             =head2 remove
161              
162             The C method deletes a file for which we are holding a state. The
163             reason we provide a special method for this is that in some situations, a
164             file permissions may not allow us to remove it, and thus we may need to
165             correct it's permissions first.
166              
167             =cut
168              
169             sub remove {
170 15     15 1 19 my $self = shift;
171 15 100       30 my $term = $self->dir ? "directory" : "file";
172 15         24 my $path = $self->{path};
173              
174             # Already removed?
175 15 50       241 return 1 unless -e $path;
176              
177             # Write permissions means delete permissions
178 15 50       215 unless ( -w $path ) {
179             # Try to give ourself write permissions
180 0 0       0 if ( $self->dir ) {
181 0 0       0 print( "# chmod 0777 $path\n" ) if $DEBUG;
182 0 0       0 chmod 0777, $path or die "Failed to get enough permissions to delete $term '$path'";
183             } else {
184 0 0       0 print( "# chmod 0666 $path\n" ) if $DEBUG;
185 0 0       0 chmod 0666, $path or die "Failed to get enough permissions to delete $term '$path'";
186             }
187             }
188              
189             # Now attempt to delete it
190 15 100       32 if ( $self->dir ) {
191 2 50       6 print( "# rmdir $path\n" ) if $DEBUG;
192 2 50       262 rmdir $path or die "Failed to delete $term '$path'";
193             } else {
194 13 50       29 print( "# rm $path\n" ) if $DEBUG;
195 13 50       5632892 unlink $path or die "Failed to delete $term '$path'";
196             }
197              
198 15         135 1;
199             }
200              
201             1;
202              
203             =pod
204              
205             =head1 SUPPORT
206              
207             Bugs should be submitted via the CPAN bug tracker, located at
208              
209             L
210              
211             For other issues, or commercial enhancement or support, contact the author.
212              
213             =head1 AUTHOR
214              
215             Adam Kennedy Eadamk@cpan.orgE
216              
217             =head1 ACKNOWLEDGEMENTS
218              
219             Thank you to Phase N Australia ( L ) for permitting
220             the open sourcing and release of this distribution as a spin-off from a
221             commercial project.
222              
223             =head1 COPYRIGHT
224              
225             Copyright 2004 - 2007 Adam Kennedy.
226              
227             This program is free software; you can redistribute
228             it and/or modify it under the same terms as Perl itself.
229              
230             The full text of the license can be found in the
231             LICENSE file included with this module.
232              
233             =cut