File Coverage

lib/Spoon/Installer.pm
Criterion Covered Total %
statement 80 156 51.2
branch 21 70 30.0
condition 4 14 28.5
subroutine 14 22 63.6
pod 0 16 0.0
total 119 278 42.8


line stmt bran cond sub pod time code
1             package Spoon::Installer;
2 3     3   5085 use Spiffy -Base;
  3         8  
  3         26  
3 3     3   4373 use IO::All;
  3     3   6  
  3     3   101  
  3         16  
  3         8  
  3         88  
  3         18  
  3         6  
  3         37  
4 3     3   207 use Spoon::Base -mixin => qw(hub);
  3         7  
  3         27  
5              
6             const extract_to => '.';
7             field quiet => 0;
8              
9 0     0 0 0 sub compress_from {
10 0         0 $self->extract_to;
11             }
12              
13 2     2 0 2154 sub extract_files {
14 2         14 my @files = $self->get_packed_files;
15 2         11 while (@files) {
16 8         3469 my ($file_name, $file_contents) = splice(@files, 0, 2);
17 8         22 my $locked = $file_name =~ s/^!//;
18 8         35 my $file_path = join '/', $self->extract_to, $file_name;
19 8         126 my $file = io->file($file_path)->assert;
20 8 50 33     1820 if ($locked and -f $file_path) {
21 0 0       0 warn " Skipping $file (already exists)\n" unless $self->quiet;
22 0         0 next;
23             }
24 8         28 my $content = $self->set_file_content($file_path, $file_contents);
25 8 50 33     26 if ($file->exists and $file->all eq $content) {
26 0 0       0 warn " Skipping $file (unchanged)\n" unless $self->quiet;
27 0         0 next;
28             }
29 8 50       545 warn " - $file\n" unless $self->quiet;
30 8 50       68 $file->binary if $self->file_is_binary($file_path);
31 8         27 $file->assert->print($content);
32             }
33             }
34              
35 8     8 0 15 sub set_file_content {
36 8         12 my $path = shift;
37 8         55 my $content = shift;
38 8 50       25 $content = $self->base64_decode($content)
39             if $self->file_is_binary($path);
40 8 50       28 $content = $self->fix_hashbang($content)
41             if $self->file_is_executable($path);
42 8 100       31 $content = $self->wrap_html($content, $path)
43             if $self->file_is_html($path);
44 8         21 return $content;
45             }
46              
47 16     16 0 20 sub file_is_binary {
48 16         23 my $path = shift;
49 16         91 $path =~ /\.(gif|jpg|png)$/;
50             }
51              
52 8     8 0 9 sub file_is_executable {
53 8         12 my $path = shift;
54 8         36 $path =~ /\.(pl|cgi)$/;
55             }
56              
57 8     8 0 10 sub file_is_html {
58 8         12 my $path = shift;
59 8         59 $path =~ /\.html$/;
60             }
61              
62 0     0 0 0 sub fix_hashbang {
63 0         0 require Config;
64 0         0 my $content = shift;
65 0         0 $content =~ s/^#!.*\n/$Config::Config{startperl} -w\n/;
66 0         0 return $content;
67             }
68              
69 5     5 0 14 sub wrap_html {
70 5         8 my ($content, $path) = @_;
71 5         28 $path =~ s/^.*\/(.*)$/$1/;
72 5         18 $path =~ s/\.html$//;
73 5         13 $content = $self->strip_html($content);
74 5 100       21 $content = "\n$content"
75             unless $content =~ /^\s/;
76 5 100       18 $content = "$content\n"
77             unless $content =~ /\s\n\z/;
78 5         11 return $content;
79             }
80              
81 2     2 0 4 sub get_packed_files {
82 2         4 my %seen;
83             my @return;
84 2         2 for my $class (@{Spiffy::all_my_bases(ref $self)}) {
  2         12  
85 7 100       101 next if $class =~ /-/;
86 5 100       18 last if $class =~ /^Spoon/;
87 3 50       15 my $data = $self->data($class)
88             or next;
89 3         34 my @files = split /^__(.+)__\n/m, $data;
90 3         6 shift @files;
91 3         11 while (@files) {
92 9         20 my ($name, $content) = splice(@files, 0, 2);
93 9 50       39 $name = $self->resolve_install_path($name)
94             if $self->can('resolve_install_path');
95 9         82 my $name2 = $name;
96 9         14 $name2 =~ s/^\!//;
97 9 100       35 next if $seen{$name2}++;
98 8   50     16 $content ||= '';
99 8 50       40 push @return, $name, $content
100             if length $content;
101             }
102             }
103 2         14 return @return;
104             }
105              
106 0     0 0 0 sub get_local_packed_files {
107 0         0 my @return;
108 0         0 my $class = ref $self;
109 0 0       0 my $data = $self->data($class)
110             or return;
111 0         0 my @files = split /^__(.+)__\n/m, $data;
112 0         0 shift @files;
113 0         0 while (@files) {
114 0         0 my ($name, $content) = splice(@files, 0, 2);
115 0 0       0 $name = $self->resolve_install_path($name)
116             if $self->can('resolve_install_path');
117 0         0 push @return, $name, $content;
118             }
119 0         0 return @return;
120             }
121              
122 3     3 0 4 sub data {
123 3   33     15 my $package = shift || ref($self);
124 3     0   23 local $SIG{__WARN__} = sub {};
  0         0  
125 3         13 local $/;
126 3         143 eval "package $package; ";
127             }
128              
129 0     0 0 0 sub compress_files {
130 0         0 require File::Spec;
131 0         0 my $source_dir = shift;
132 0         0 my $new_pack = '';
133 0         0 my @files = $self->get_local_packed_files;
134 0 0       0 my $first_file = $files[0]
135             or return;
136 0         0 my $directory = $self->compress_from;
137 0         0 while (@files) {
138 0         0 my ($file_name, $file_contents) = splice(@files, 0, 2);
139 0 0       0 my $locked = $file_name =~ s/^!// ? '!' : '';
140 0         0 my $source_path =
141             File::Spec->canonpath("$source_dir/$directory/$file_name");
142 0 0       0 die "$file_name does not exist as $source_path"
143             unless -f $source_path;
144 0 0       0 my $content = $locked
145             ? $file_contents
146             : $self->get_file_content($source_path);
147 0         0 $content =~ s/\r\n/\n/g;
148 0         0 $content =~ s/\r/\n/g;
149 0         0 $new_pack .= "__$locked${file_name}__\n$content";
150             }
151 0         0 my $module = ref($self) . '.pm';
152 0         0 $module =~ s/::/\//g;
153 0 0       0 my $module_path = $INC{$module} or die;
154 0         0 my $module_text = io($module_path)->all;
155 0         0 my ($module_code) = split /^__\Q$first_file\E__\n/m, $module_text;
156 0         0 ($module_code . $new_pack) > io($module_path);
157             }
158              
159 0     0 0 0 sub get_file_content {
160 0         0 my $path = shift;
161 0         0 my $content = io($path)->all;
162 0 0       0 $content = $self->base64_encode($content)
163             if $self->file_is_binary($path);
164 0 0       0 $content = $self->unfix_hashbang($content)
165             if $self->file_is_executable($path);
166 0 0       0 $content = $self->strip_html($content)
167             if $self->file_is_html($path);
168 0 0       0 $content .= "\n"
169             unless $content =~ /\n\z/;
170 0         0 return $content;
171             }
172              
173 0     0 0 0 sub unfix_hashbang {
174 0         0 my $content = shift;
175 0         0 $content =~ s/^#!.*\n/#!\/usr\/bin\/perl\n/;
176 0         0 return $content;
177             }
178              
179 5     5 0 6 sub strip_html {
180 5         6 my $content = shift;
181 5         9 $content =~ s/^\n//;
182 5         10 $content =~ s/(?<=\n)\n\z//;
183 5         17 return $content;
184             }
185              
186 0     0 0   sub compress_lib {
187 0 0 0       die "Must be run from the module source code directory\n"
188             unless -d 'lib' and -f 'Makefile.PL';
189 0           unshift @INC,'lib';
190 0 0         my $source_dir = shift
191             or die "No source directory specified\n";
192 0 0         die "Invalid source directory '$source_dir'\n"
193             unless -d $source_dir;
194 0           map {
195 0           my $class_name = $_;
196 0           my $class_id = $class_name->class_id;
197 0           $self->hub->config->add_config(
198             +{ "${class_id}_class" => $class_name }
199             );
200 0 0         warn "Compressing $class_name\n" unless $self->quiet;
201 0           $self->hub->$class_id->compress_files($source_dir);
202             }
203             grep {
204 0           my $name = $_;
205 0           eval "require $name";
206 0 0         die $@ if $@;
207 0 0         UNIVERSAL::can($name, 'compress_files')
208             and $name !~ /::(Installer)$/;
209             } map {
210 0           my $name = $_->name;
211 0 0         ($name =~ s/^lib\/(.*)\.pm$/$1/) ? do {
212 0           $name =~ s/\//::/g;
213 0           $name;
214             } : ();
215             } io('lib')->All_Files;
216             }
217              
218             __END__