File Coverage

blib/lib/Footprintless/Overlay.pm
Criterion Covered Total %
statement 110 110 100.0
branch 22 32 68.7
condition 1 2 50.0
subroutine 28 28 100.0
pod 3 3 100.0
total 164 175 93.7


line stmt bran cond sub pod time code
1 2     2   47300 use strict;
  2         3  
  2         51  
2 2     2   9 use warnings;
  2         3  
  2         83  
3              
4             package Footprintless::Overlay;
5             $Footprintless::Overlay::VERSION = '1.26';
6             # ABSTRACT: An overlay manager
7             # PODNAME: Footprintless::Overlay
8              
9 2     2   10 use parent qw(Footprintless::MixableBase);
  2         7  
  2         13  
10              
11 2     2   72 use Carp;
  2         5  
  2         108  
12 2         135 use Footprintless::Mixins qw (
13             _clean
14             _command_options
15             _entity
16             _extract_resource
17             _local_template
18             _push_to_destination
19             _sub_coordinate
20             _sub_entity
21 2     2   497 );
  2         5  
22 2         72 use Footprintless::Util qw(
23             dynamic_module_new
24             invalid_entity
25             temp_dir
26 2     2   12 );
  2         3  
27 2     2   9 use Log::Any;
  2         3  
  2         6  
28 2     2   57 use File::Find;
  2         3  
  2         87  
29 2     2   9 use File::Spec;
  2         3  
  2         32  
30 2     2   273 use Template::Resolver;
  2         34851  
  2         66  
31 2     2   577 use Template::Overlay;
  2         17912  
  2         1810  
32              
33             my $logger = Log::Any->get_logger();
34              
35             sub clean {
36 9     9 1 305 my ($self) = @_;
37 9         50 $self->_clean();
38             }
39              
40             sub _dirs_template {
41 13     13   45 my ( $self, $to_dir, $with_dirs_work ) = @_;
42              
43 13         58 my $base_dir = $self->_sub_entity('base_dir');
44 13         51 my $template_dir = $self->_sub_entity('template_dir');
45              
46 13         29 my $unpack_dir;
47 13         35 my $resource = $self->_sub_entity('resource');
48 13 100       53 if ($resource) {
49 4         34 $unpack_dir = temp_dir();
50 4         24 $self->_extract_resource( $resource, $unpack_dir );
51              
52 4 50       32 if ($base_dir) {
53 4         940 $base_dir = File::Spec->catdir( $unpack_dir, $base_dir );
54             }
55 4 50       58 if ($template_dir) {
56             $template_dir =
57             ref($template_dir) eq 'ARRAY'
58 4 100       25 ? [ map { File::Spec->catdir( $unpack_dir, $_ ) } @$template_dir ]
  4         32  
59             : File::Spec->catdir( $unpack_dir, $template_dir );
60             }
61             }
62              
63 13         80 &$with_dirs_work( $base_dir, $template_dir, $to_dir );
64             }
65              
66             sub _dot_footprintless_resolver {
67 13     13   1206 my ($self) = @_;
68             return sub {
69 23     23   23049 my ( $template, $destination ) = @_;
70 23 100       123 if ( $template =~ /\/\.footprintless$/ ) {
71 2         16 $self->_resolve_footprintless( $template, $destination );
72 2         51 return 1;
73             }
74 21         54 return 0;
75 13         138 };
76             }
77              
78             sub initialize {
79 6     6 1 915 my ( $self, %options ) = @_;
80              
81 6         37 $self->clean();
82              
83 6 100       157 if ( $options{to_dir} ) {
84             $self->_dirs_template(
85             $options{to_dir},
86             sub {
87 1     1   12 $self->_initialize(@_);
88             }
89 1         27 );
90             }
91             else {
92             $self->_local_with_dirs_template(
93             sub {
94 5     5   24 $self->_initialize(@_);
95             }
96 5         77 );
97             }
98             }
99              
100             sub _initialize {
101 6     6   27 my ( $self, $base_dir, $template_dir, $to_dir ) = @_;
102 6         32 $self->_overlay($base_dir)->overlay(
103             $template_dir,
104             resolver => $self->_dot_footprintless_resolver(),
105             to => $to_dir
106             );
107             }
108              
109             sub _local_with_dirs_template {
110 11     11   45 my ( $self, $local_work ) = @_;
111             $self->_local_template(
112             sub {
113 11     11   49 $self->_dirs_template( $_[0], $local_work );
114             }
115 11         104 );
116             }
117              
118             sub _overlay {
119 13     13   43 my ( $self, $base_dir ) = @_;
120              
121 13         27 my @overlay_opts = ();
122 13         70 my $key = $self->_sub_entity('key');
123 13 50       79 push( @overlay_opts, key => $key ) if ($key);
124              
125 13         61 return Template::Overlay->new( $base_dir, $self->_resolver(), @overlay_opts );
126             }
127              
128             sub _resolver {
129 13     13   35 my ($self) = @_;
130              
131 13         40 my @resolver_opts = ();
132 13         40 my $os = $self->_sub_entity('os');
133 13 50       51 push( @resolver_opts, os => $os ) if ($os);
134              
135 13         42 my $resolver_coordinate = $self->_sub_entity('resolver_coordinate');
136 13 50       74 my $resolver_spec =
137             $resolver_coordinate
138             ? $self->_entity($resolver_coordinate)
139             : $self->_entity();
140              
141 13         28 my $resolver;
142 13         37 my $resolver_factory = $self->_entity('footprintless.overlay.resolver_factory');
143 13 100       39 if ($resolver_factory) {
144 1         6 $logger->tracef( "using resolver_factory: %s", $resolver_factory );
145 1         10 $resolver =
146             dynamic_module_new($resolver_factory)->new_resolver( $resolver_spec, @resolver_opts );
147             }
148             else {
149 12         162 $resolver = Template::Resolver->new( $resolver_spec, @resolver_opts );
150             }
151 13         7328 return $resolver;
152             }
153              
154             sub _resolve_footprintless {
155 2     2   12 my ( $self, $template, $footprintless_path ) = @_;
156 2         45 my $destination = ( File::Spec->splitpath($footprintless_path) )[1];
157 2         23 $logger->debugf( "resolving [%s]->[%s]", $template, $destination );
158              
159 2   50     747 my $spec = do($template) || return;
160 2 50       12 croak("invalid $template") unless ( ref($spec) eq 'HASH' );
161              
162 2 50       9 if ( $spec->{clean} ) {
163             my @to_be_cleaned =
164 2 50       36 map { File::Spec->catdir( $destination, $_ ) . ( /\/$/ ? '/' : '' ); }
165 2 50       11 ref( $spec->{clean} ) ? @{ $spec->{clean} } : ( $spec->{clean} );
  2         9  
166              
167             Footprintless::Util::clean(
168             \@to_be_cleaned,
169 2         16 command_runner => $self->{factory}->command_runner(),
170             command_options => $self->_command_options()
171             );
172             }
173              
174 2 50       41 if ( $spec->{resources} ) {
175 2         22 my $resource_manager = $self->{factory}->resource_manager();
176 2         5 foreach my $resource ( keys( %{ $spec->{resources} } ) ) {
  2         16  
177 2         22 $resource_manager->download( $spec->{resources}{$resource}, to => $destination );
178             }
179             }
180             }
181              
182             sub update {
183 7     7 1 344 my ( $self, %options ) = @_;
184              
185 7 100       34 if ( $options{to_dir} ) {
186             $self->_dirs_template(
187             $options{to_dir},
188             sub {
189 1     1   7 $self->_update(@_);
190             }
191 1         19 );
192             }
193             else {
194             $self->_local_with_dirs_template(
195             sub {
196 6     6   60 $self->_update(@_);
197             }
198 6         67 );
199             }
200             }
201              
202             sub _update {
203 7     7   27 my ( $self, $base_dir, $template_dir, $to_dir ) = @_;
204 7         53 $logger->tracef( "update to=[%s], template=[%s]", $to_dir, $template_dir );
205 7         111 $self->_overlay($to_dir)
206             ->overlay( $template_dir, resolver => $self->_dot_footprintless_resolver() );
207             }
208              
209             1;
210              
211             __END__