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