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