File Coverage

blib/lib/Template/Overlay.pm
Criterion Covered Total %
statement 80 82 97.5
branch 20 24 83.3
condition 9 12 75.0
subroutine 18 18 100.0
pod 2 2 100.0
total 129 138 93.4


line stmt bran cond sub pod time code
1 1     1   46138 use strict;
  1         3  
  1         39  
2 1     1   8 use warnings;
  1         4  
  1         61  
3              
4             package Template::Overlay;
5             $Template::Overlay::VERSION = '1.14';
6             # ABSTRACT: A powerful, and simple, library for resolving placeholders in templated files
7             # PODNAME: Template::Resolver
8              
9 1     1   9 use Carp;
  1         9  
  1         86  
10 1     1   493 use File::Copy qw(copy);
  1         3288  
  1         78  
11 1     1   9 use File::Find;
  1         4  
  1         70  
12 1     1   9 use File::Path qw(make_path);
  1         2  
  1         61  
13 1     1   9 use File::Spec;
  1         3  
  1         26  
14 1     1   536 use File::stat;
  1         9709  
  1         9  
15 1     1   87 use Fcntl;
  1         3  
  1         283  
16 1     1   137 use Log::Any;
  1         3  
  1         9  
17              
18             my $logger = Log::Any->get_logger();
19              
20             sub new {
21 8     8 1 45 return bless( {}, shift )->_init(@_);
22             }
23              
24             sub _init {
25 8     8   30 my ( $self, $base, $resolver, %options ) = @_;
26              
27 8         94 $self->{base} = File::Spec->rel2abs($base);
28 8         66 $self->{resolver} = $resolver;
29 8         17 $self->{key} = $options{key};
30              
31 8         27 $logger->debug( 'new overlay [', $self->{base}, ']' );
32              
33 8         398 return $self;
34             }
35              
36             sub _overlay_files {
37 8     8   20 my ( $self, $overlays ) = @_;
38              
39 8         15 my %overlay_files = ();
40 8 100       30 foreach my $overlay ( ref($overlays) eq 'ARRAY' ? @$overlays : ($overlays) ) {
41 10         93 $overlay = File::Spec->rel2abs($overlay);
42 10         26 my $base_path_length = length($overlay);
43             find(
44             sub {
45 26 50 66 26   1178 if ( -f $File::Find::name && $_ !~ /~$/ && $_ !~ /^\..+\.swp$/ ) {
      66        
46 10         31 my $relative = _relative_path( $File::Find::name, $base_path_length );
47 10         257 $overlay_files{$relative} = $File::Find::name;
48             }
49             },
50 10         604 $overlay
51             );
52             }
53              
54 8         43 return %overlay_files;
55             }
56              
57             sub overlay {
58 8     8 1 25 my ( $self, $overlays, %options ) = @_;
59              
60 8         26 my %overlay_files = $self->_overlay_files($overlays);
61 8         24 my $destination = $self->{base};
62 8 100 66     68 if ( $options{to} && $options{to} ne $self->{base} ) {
63 5         149 $destination = File::Spec->rel2abs( $options{to} );
64 5         116 my $base_path_length = length( File::Spec->rel2abs( $self->{base} ) );
65             find(
66             sub {
67 22     22   1277 my $relative = _relative_path( $File::Find::name, $base_path_length );
68 22 100       221 if ( -d $File::Find::name ) {
69 9         823 make_path( File::Spec->catdir( $destination, $relative ) );
70             }
71 22 100       534 if ( -f $File::Find::name ) {
72 13         37 my $template = delete( $overlay_files{$relative} );
73 13         144 my $file = File::Spec->catfile( $destination, $relative );
74 13 100       41 if ($template) {
75 7         31 $self->_resolve( $template, $file, $options{resolver} );
76             }
77             else {
78 6         22 copy( $_, $file );
79             }
80             }
81             },
82             $self->{base}
83 5         212 );
84             }
85 8         280 foreach my $relative ( keys(%overlay_files) ) {
86 3         33 my $file = File::Spec->catfile( $destination, $relative );
87 3         377 make_path( ( File::Spec->splitpath($file) )[1] );
88 3         18 $self->_resolve( $overlay_files{$relative}, $file, $options{resolver} );
89             }
90             }
91              
92             sub _relative_path {
93 32     32   72 my ( $path, $base_path_length ) = @_;
94             return
95 32 100       130 length($path) == $base_path_length
96             ? ''
97             : substr( $File::Find::name, $base_path_length + 1 );
98             }
99              
100             sub _resolve {
101 10     10   38 my ( $self, $template, $file, $resolver ) = @_;
102              
103 10 100 100     35 return if ( $resolver && &$resolver( $template, $file ) );
104              
105 9 50       116 if ( -f $file ) {
106 0         0 $logger->debugf(
107             '[%s] already exists, deleting to ensure creation with proper permissions', $file );
108 0         0 unlink($file);
109             }
110              
111 9         40 my $mode = stat($template)->mode() & 07777; ## no critic
112 9         1635 $logger->infof( 'processing [%s] -> [%04o] [%s]', $template, $mode, $file );
113 9 50       1121 sysopen( my $handle, $file, O_CREAT | O_TRUNC | O_WRONLY, $mode )
114             || croak("open $file failed: $!");
115 9         29 eval {
116             print( $handle $self->{resolver}->resolve(
117             filename => $template,
118 9 100       53 ( $self->{key} ? ( key => $self->{key} ) : () )
119             )
120             );
121             };
122 9         18 my $error = $@;
123 9         251 close($handle);
124 9 50       202 croak($error) if ($error);
125             }
126              
127             1;
128              
129             __END__