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   30621 use strict;
  1         1  
  1         23  
2 1     1   3 use warnings;
  1         1  
  1         33  
3              
4             package Template::Overlay;
5             $Template::Overlay::VERSION = '1.13';
6             # ABSTRACT: A powerful, and simple, library for resolving placeholders in templated files
7             # PODNAME: Template::Resolver
8              
9 1     1   3 use Carp;
  1         1  
  1         48  
10 1     1   443 use File::Copy qw(copy);
  1         1732  
  1         44  
11 1     1   4 use File::Find;
  1         1  
  1         39  
12 1     1   3 use File::Path qw(make_path);
  1         1  
  1         29  
13 1     1   3 use File::Spec;
  1         1  
  1         11  
14 1     1   460 use File::stat;
  1         4701  
  1         4  
15 1     1   44 use Fcntl;
  1         1  
  1         161  
16 1     1   10 use Log::Any;
  1         1  
  1         7  
17              
18             my $logger = Log::Any->get_logger();
19              
20             sub new {
21 8     8 1 26 return bless( {}, shift )->_init(@_);
22             }
23              
24             sub _init {
25 8     8   16 my ( $self, $base, $resolver, %options ) = @_;
26              
27 8         67 $self->{base} = File::Spec->rel2abs($base);
28 8         44 $self->{resolver} = $resolver;
29 8         30 $self->{key} = $options{key};
30              
31 8         23 $logger->debug( 'new overlay [', $self->{base}, ']' );
32              
33 8         823 return $self;
34             }
35              
36             sub _overlay_files {
37 8     8   11 my ( $self, $overlays ) = @_;
38              
39 8         9 my %overlay_files = ();
40 8 100       26 foreach my $overlay ( ref($overlays) eq 'ARRAY' ? @$overlays : ($overlays) ) {
41 10         85 $overlay = File::Spec->rel2abs($overlay);
42 10         12 my $base_path_length = length($overlay);
43             find(
44             sub {
45 26 50 66 26   870 if ( -f $File::Find::name && $_ !~ /~$/ && $_ !~ /^\..+\.swp$/ ) {
      66        
46 10         18 my $relative = _relative_path( $File::Find::name, $base_path_length );
47 10         217 $overlay_files{$relative} = $File::Find::name;
48             }
49             },
50 10         527 $overlay
51             );
52             }
53              
54 8         33 return %overlay_files;
55             }
56              
57             sub overlay {
58 8     8 1 18 my ( $self, $overlays, %options ) = @_;
59              
60 8         17 my %overlay_files = $self->_overlay_files($overlays);
61 8         14 my $destination = $self->{base};
62 8 100 66     55 if ( $options{to} && $options{to} ne $self->{base} ) {
63 5         86 $destination = File::Spec->rel2abs( $options{to} );
64 5         58 my $base_path_length = length( File::Spec->rel2abs( $self->{base} ) );
65             find(
66             sub {
67 22     22   1077 my $relative = _relative_path( $File::Find::name, $base_path_length );
68 22 100       247 if ( -d $File::Find::name ) {
69 9         578 make_path( File::Spec->catdir( $destination, $relative ) );
70             }
71 22 100       473 if ( -f $File::Find::name ) {
72 13         20 my $template = delete( $overlay_files{$relative} );
73 13         108 my $file = File::Spec->catfile( $destination, $relative );
74 13 100       27 if ($template) {
75 7         23 $self->_resolve( $template, $file, $options{resolver} );
76             }
77             else {
78 6         14 copy( $_, $file );
79             }
80             }
81             },
82             $self->{base}
83 5         199 );
84             }
85 8         253 foreach my $relative ( keys(%overlay_files) ) {
86 3         29 my $file = File::Spec->catfile( $destination, $relative );
87 3         408 make_path( ( File::Spec->splitpath($file) )[1] );
88 3         43 $self->_resolve( $overlay_files{$relative}, $file, $options{resolver} );
89             }
90             }
91              
92             sub _relative_path {
93 32     32   31 my ( $path, $base_path_length ) = @_;
94             return
95 32 100       90 length($path) == $base_path_length
96             ? ''
97             : substr( $File::Find::name, $base_path_length + 1 );
98             }
99              
100             sub _resolve {
101 10     10   20 my ( $self, $template, $file, $resolver ) = @_;
102              
103 10 100 100     28 return if ( $resolver && &$resolver( $template, $file ) );
104              
105 9 50       149 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         30 my $mode = stat($template)->mode() & 07777; ## no critic
112 9         1048 $logger->infof( 'processing [%s] -> [%04o] [%s]', $template, $mode, $file );
113 9 50       1527 sysopen( my $handle, $file, O_CREAT | O_TRUNC | O_WRONLY, $mode )
114             || croak("open $file failed: $!");
115 9         15 eval {
116             print( $handle $self->{resolver}->resolve(
117             filename => $template,
118 9 100       59 ( $self->{key} ? ( key => $self->{key} ) : () )
119             )
120             );
121             };
122 9         11 my $error = $@;
123 9         219 close($handle);
124 9 50       189 croak($error) if ($error);
125             }
126              
127             1;
128              
129             __END__