File Coverage

blib/lib/Test/TempDir/Factory.pm
Criterion Covered Total %
statement 61 72 84.7
branch 17 30 56.6
condition 6 15 40.0
subroutine 15 16 93.7
pod 1 8 12.5
total 100 141 70.9


line stmt bran cond sub pod time code
1             package Test::TempDir::Factory;
2             # ABSTRACT: A factory for creating L<Test::TempDir::Handle> objects
3              
4             our $VERSION = '0.10';
5              
6 4     4   79638 use Moose;
  4         1305864  
  4         35  
7 4     4   28040 use Carp qw(croak carp);
  4         10  
  4         274  
8 4     4   21 use File::Spec;
  4         6  
  4         102  
9 4     4   18 use File::Temp;
  4         9  
  4         321  
10 4     4   880 use Path::Class;
  4         23186  
  4         229  
11              
12 4     4   2722 use MooseX::Types::Path::Class qw(Dir);
  4         1146210  
  4         84  
13              
14 4     4   6917 use Test::TempDir::Handle;
  4         16  
  4         172  
15              
16 4     4   32 use namespace::autoclean 0.08;
  4         127  
  4         35  
17              
18             has lock => (
19             isa => "Bool",
20             is => "rw",
21             default => 1,
22             );
23              
24             has lock_opts => (
25             isa => "HashRef",
26             is => "rw",
27             default => sub { { lock_type => "NONBLOCKING" } },
28             );
29              
30             has lock_attempts => (
31             isa => "Int",
32             is => "rw",
33             default => 2,
34             );
35              
36             has dir_name => (
37             isa => Dir,
38             is => "rw",
39             coerce => 1,
40             default => sub { dir($ENV{TEST_TEMPDIR} || $ENV{TEST_TMPDIR} || "tmp") },
41             );
42              
43             has cleanup_policy => (
44             isa => "Str",
45             is => "rw",
46             default => sub { $ENV{TEST_TEMPDIR_CLEANUP} || "success" },
47             );
48              
49             has t_dir => (
50             isa => Dir,
51             is => "rw",
52             coerce => 1,
53             default => sub { dir("t") },
54             );
55              
56             has options => (
57             isa => "HashRef",
58             is => "rw",
59             default => sub { {} },
60             );
61              
62             has use_subdir => (
63             isa => "Bool",
64             is => "rw",
65             default => sub { $ENV{TEST_TEMPDIR_USE_SUBDIR} ? 1 : 0 },
66             );
67              
68             has subdir_template => (
69             isa => "Str",
70             is => "rw",
71             default => File::Temp::TEMPXXX,
72             );
73              
74             has handle_class => (
75             isa => "ClassName",
76             is => "rw",
77             default => "Test::TempDir::Handle",
78             handles => { new_handle => "new" },
79             );
80              
81             has verbose => (
82             isa => "Bool",
83             is => "rw",
84             default => 0,
85             );
86              
87             sub create {
88 4     4 1 2340 my ( $self, @args ) = @_;
89              
90 4         20 my ( $path, $lock ) = $self->create_and_lock( $self->base_path(@args), @args );
91              
92 4 50       225 my $h = $self->new_handle(
93             dir => $path,
94             ( defined($lock) ? ( lock => $lock ) : () ),
95             cleanup_policy => $self->cleanup_policy,
96             @args,
97             );
98              
99 4         7972 $h->empty;
100              
101 4         1246 return $h;
102             }
103              
104             sub create_and_lock {
105 6     6 0 394 my ( $self, $preferred, @args ) = @_;
106              
107 6 100       213 if ( $self->use_subdir ) {
108 2         7 $preferred = $self->make_subdir($preferred);
109             } else {
110 4 100       15 $preferred->mkpath unless -d $preferred;
111             }
112              
113 6 50       39375 unless ( $self->lock ) {
114 0         0 return $preferred;
115             } else {
116 6 50       27 croak "When locking is enabled you must call create_and_lock in list context" unless wantarray;
117 6 50       35 if ( my $lock = $self->try_lock($preferred) ) {
118 6         9361 return ( $preferred, $lock );
119             }
120              
121 0         0 return $self->create_and_lock_fallback(@args);
122             }
123             }
124              
125             sub create_and_lock_fallback {
126 4     4 0 233 my ( $self, @args ) = @_;
127              
128 4         12 my $base = $self->fallback_base_path;
129              
130 4         308 for ( 1 .. $self->lock_attempts ) {
131 4         11 my $dir = $self->make_subdir($base);
132              
133 4 100       1688 if ( $self->lock ) {
134 2 50       7 if ( my $lock = $self->try_lock($dir) ) {
135 2         928 return ( $dir, $lock );
136             }
137              
138 0         0 rmdir $dir;
139             } else {
140 2         13 return $dir;
141             }
142             }
143              
144 0         0 croak "Unable to create locked tempdir";
145             }
146              
147             sub try_lock {
148 8     8 0 18 my ( $self, $path ) = @_;
149              
150 8 50       291 return 1 if !$self->lock;
151              
152 8         4023 require File::NFSLock;
153             File::NFSLock->new({
154             file => $path->stringify . ".lock", # FIXME $path->file ? make sure it's not zapped by empty
155 8         11115 %{ $self->lock_opts },
  8         540  
156             });
157             }
158              
159             sub make_subdir {
160 6     6 0 14 my ( $self, $dir ) = @_;
161 6 100       18 $dir->mkpath unless -d $dir;
162 6         600 dir( File::Temp::tempdir( $self->subdir_template, DIR => $dir->stringify ) );
163             }
164              
165             sub base_path {
166 16     16 0 6560 my ( $self, @args ) = @_;
167              
168 16         597 my $dir = $self->dir_name;
169              
170 16 50 33     70 return $dir if -d $dir and -w $dir;
171              
172 16         972 my $t = $self->t_dir;
173              
174 16 50 33     44 if ( -d $t and -w $t ) {
175 16         933 $dir = $t->subdir($dir);
176 16 50 66     816 return $dir if -d $dir && -w $dir or not -e $dir;
      66        
177             }
178              
179 0         0 $self->blurt("$t is not writable, using fallback");
180              
181 0         0 return $self->fallback_base_path(@args);
182             }
183              
184             sub blurt {
185 0     0 0 0 my ( $self, @blah ) = @_;
186 0 0 0     0 if ( $self->can("logger") and my $logger = $self->logger ) {
187 0         0 $logger->warn(@blah);
188             } else {
189 0 0       0 return unless $self->verbose;
190 0         0 carp(@blah);
191             }
192             }
193              
194             sub fallback_base_path {
195 4     4 0 68 return dir(File::Spec->tmpdir);
196             }
197              
198             __PACKAGE__
199              
200             __END__
201              
202             =pod
203              
204             =encoding UTF-8
205              
206             =head1 NAME
207              
208             Test::TempDir::Factory - A factory for creating L<Test::TempDir::Handle> objects
209              
210             =head1 VERSION
211              
212             version 0.10
213              
214             =head1 SYNOPSIS
215              
216             my $f = Test::TempDir::Factory->new;
217              
218             my $d = $f->create;
219              
220             $d->empty;
221              
222             # ...
223              
224             $d->cleanup
225              
226             =head1 DESCRIPTION
227              
228             This class creates L<Test::TempDir::Handle> objects with the right C<dir>
229             parameter, taking care of obtaining locks, creating directories, and handling
230             fallback logic.
231              
232             =head1 ATTRIBUTES
233              
234             =head2 C<lock>
235              
236             Whether or not to enable locking.
237              
238             Defaults to true.
239              
240             =head2 C<lock_opts>
241              
242             A hash reference to pass to L<File::NFSLock>.
243              
244             Defaults to C<NONBLOCKING>
245              
246             =head2 C<lock_attempts>
247              
248             How many times to try to create and lock a directory.
249              
250             Defaults to 2.
251              
252             =head2 C<dir_name>
253              
254             The directory under C<t_dir> to use.
255              
256             Defaults to C<tmp>
257              
258             =head2 C<t_dir>
259              
260             Defaults to C<t>
261              
262             =head2 C<use_subdir>
263              
264             Whether to always use a temporary subdirectory under the temporary root.
265              
266             This means that with a C<success> cleanup policy all failures are retained.
267              
268             When disabled, C<t/tmp> will be used directly as C<temp_root>.
269              
270             Defaults to true.
271              
272             =head2 C<subdir_template>
273              
274             The template to pass to C<tempdir>. Defaults to C<File::Temp::TEMPXXX>.
275              
276             =head2 C<handle_class>
277              
278             Defaults to L<Test::TempDir::Handle>.
279              
280             =head2 C<verbose>
281              
282             Whether or not to C<carp> diagnostics when falling back.
283              
284             If you subclass this factory and add a C<logger> method a la L<MooseX::Logger>
285             then this parameter is ignored and all messages will be C<warn>ed on the
286             logger.
287              
288             =head1 METHODS
289              
290             =head2 C<create>
291              
292             Create a L<Test::TempDir::Handle> object with a proper C<dir> attribute.
293              
294             =head1 AUTHOR
295              
296             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
297              
298             =head1 COPYRIGHT AND LICENSE
299              
300             This software is copyright (c) 2006 by יובל קוג'מן (Yuval Kogman).
301              
302             This is free software; you can redistribute it and/or modify it under
303             the same terms as the Perl 5 programming language system itself.
304              
305             =cut