File Coverage

blib/lib/Ado/Build.pm
Criterion Covered Total %
statement 36 172 20.9
branch 2 40 5.0
condition 1 30 3.3
subroutine 11 29 37.9
pod 15 15 100.0
total 65 286 22.7


line stmt bran cond sub pod time code
1             package Ado::Build;
2 3     3   50913 use 5.014;
  3         8  
3 3     3   13 use strict;
  3         3  
  3         71  
4 3     3   11 use warnings FATAL => 'all';
  3         4  
  3         133  
5 3     3   12 use File::Spec::Functions qw(catdir catfile);
  3         4  
  3         182  
6 3     3   13 use File::Path qw(make_path);
  3         4  
  3         150  
7 3     3   560 use File::Copy qw(copy);
  3         2055  
  3         142  
8 3     3   1613 use ExtUtils::Installed;
  3         286295  
  3         161  
9 3     3   1812 use ExtUtils::Install;
  3         30453  
  3         227  
10 3     3   17 use parent 'Module::Build';
  3         6  
  3         24  
11 3     3   107398 use Exporter qw( import ); #export functionality to Ado::BuildPlugin etc..
  3         6  
  3         4773  
12             our @EXPORT_OK = qw(
13             create_build_script process_etc_files do_create_readme
14             process_public_files process_templates_files
15             ACTION_perltidy ACTION_submit PERL_DIRS);
16              
17             sub PERL_DIRS {
18 0     0 1 0 state $dirs = [map { catdir($_[0]->base_dir, $_) } qw(bin lib etc t)];
  0         0  
19 0         0 return @$dirs;
20             }
21              
22             sub create_build_script {
23 1     1 1 5 my $self = shift;
24              
25             #Deciding where to install
26 1   33     12 my $prefix = $self->install_base || $self->config('siteprefix');
27 1         59 for my $be (qw(etc public log templates)) {
28              
29             #in case of installing a plugin, check if folder exists
30 4 100       58 next unless -d $be;
31 1         12 $self->add_build_element($be);
32 1         40 $self->install_path($be => catdir($prefix, $be));
33             }
34 1         17 return $self->SUPER::create_build_script();
35             }
36              
37             sub process_public_files {
38 0     0 1   my $self = shift;
39 0           for my $asset (@{$self->rscan_dir('public')}) {
  0            
40 0 0         if (-d $asset) {
41 0           make_path(catdir('blib', $asset));
42 0           next;
43             }
44 0           copy($asset, catfile('blib', $asset));
45             }
46 0           return;
47             }
48              
49             sub process_etc_files {
50 0     0 1   my $self = shift;
51 0   0       my $prefix = $self->install_base || $self->config('siteprefix');
52 0   0       my $mode = $ENV{MOJO_MODE} ||= 'development';
53              
54 0           for my $asset (@{$self->rscan_dir('etc')}) {
  0            
55 0 0         if (-d $asset) {
56 0           make_path(catdir('blib', $asset));
57 0           next;
58             }
59              
60             # skip SQLite automatically created files
61 0 0         next if ($asset =~ m/ado\-(shm|wal)/);
62 0           my $asset_path = catfile($prefix, $asset);
63 0 0 0       if ($asset =~ m/ado\.sqlite/ && -s $asset_path) {
64 0           $self->log_info("Skipping $asset because it already exists at $asset_path! $/");
65 0           next;
66             }
67 0           copy($asset, catfile('blib', $asset));
68             }
69 0           return;
70             }
71              
72             sub process_log_files {
73 0     0 1   my $self = shift;
74 0           for my $asset (@{$self->rscan_dir('log')}) {
  0            
75 0 0         if (-d $asset) {
76 0           make_path(catdir('blib', $asset));
77 0           next;
78             }
79 0           copy($asset, catfile('blib', $asset));
80             }
81 0           return;
82             }
83              
84             sub process_templates_files {
85 0     0 1   my $self = shift;
86 0           for my $asset (@{$self->rscan_dir('templates')}) {
  0            
87 0 0         if (-d $asset) {
88 0           make_path(catdir('blib', $asset));
89 0           next;
90             }
91 0           copy($asset, catfile('blib', $asset));
92             }
93 0           return;
94             }
95              
96             sub _uninstall {
97 0     0     my $self = shift;
98 0           my $dryrun = shift;
99 0   0       my $verbose = shift || 1; # true by default
100              
101 0 0         unshift @INC, $self->install_base if $self->install_base;
102              
103 0           my $module = $self->module_name;
104 0           my $installed = ExtUtils::Installed->new;
105 0           my $packlist = $installed->packlist($module)->packlist_file;
106              
107             # Remove all installed files
108 0           ExtUtils::Install::uninstall($packlist, $verbose, $dryrun);
109              
110             # Remove empty installation directories.
111 0           foreach (reverse sort $installed->directories($module)) {
112 0 0 0       say "rmdir $_" and next if $verbose and $dryrun;
      0        
113 0 0         say rmdir $_ ? "rmdir $_" : "rmdir $_ - $!" if not $dryrun;
    0          
114             }
115 0           return;
116             }
117              
118             sub ACTION_uninstall {
119 0     0 1   my $self = shift;
120 0           return $self->_uninstall;
121             }
122              
123             sub ACTION_fakeuninstall {
124 0     0 1   my $self = shift;
125 0           return $self->_uninstall('dry-run');
126             }
127              
128             sub ACTION_build {
129 0     0 1   my $self = shift;
130              
131             #Make sure *log files are empty before moving them to blib
132 0           _empty_log_files('log');
133              
134             #Do other interventions before the real build...
135 0           $self->SUPER::ACTION_build;
136 0           return;
137             }
138              
139             sub ACTION_test {
140 0     0 1   my $self = shift;
141              
142             #Custom functionality before test
143 0 0         $self->_process_custom_files(catdir('blib', 'etc'), catdir('blib', 'log'))
144             if -d 'blib';
145 0           $self->_process_custom_files('etc', 'log');
146 0           $self->SUPER::ACTION_test;
147 0           return;
148             }
149              
150             sub ACTION_dist {
151 0     0 1   my $self = shift;
152              
153             #Make sure *log files are empty before including them into the distro
154 0           _empty_log_files('log');
155              
156             #Do other interventions before the real dist..
157 0           $self->SUPER::ACTION_dist;
158 0           return;
159             }
160              
161             sub ACTION_install {
162 0     0 1   my $self = shift;
163              
164             #Custom functionality before installation
165             #here...
166             #TODO: Think about what to do with *.conf and *.sqlite files in case of upgrade!!!
167             #TODO: (upgrade)rotate logs - archive existing log files before emptying.
168 0           $self->SUPER::ACTION_install;
169              
170             #Custom functionality after installation
171 0           $self->_process_custom_files($self->install_path('etc'), $self->install_path('log'));
172 0           return;
173             }
174              
175             sub _process_custom_files {
176 0     0     my ($self, $etc_dir, $log_dir) = @_;
177              
178             #make some files writable and/or readable only by the user that runs the application
179 0           my $ro = oct('0400');
180 0           my $rw = oct('0600');
181 0           for my $asset (
182             qw(ado.conf plugins/routes.conf plugins/auth.conf plugins/markdown_renderer.conf))
183             {
184 0           _chmod($ro, catfile($etc_dir, $asset));
185             }
186 0           _chmod($rw, catfile($etc_dir, 'ado.sqlite'));
187              
188             #Make sure *log files are existing and empty
189 0           _empty_log_files($log_dir);
190 0           for my $asset (qw(development production)) {
191 0           _chmod($rw, catfile($log_dir, "$asset.log"));
192             }
193 0           return;
194             }
195              
196             sub _chmod {
197 0     0     my ($mode, $file) = @_;
198 0   0       return chmod($mode, $file)
199             || Carp::carp("Could not change mode for $file: $!");
200             }
201              
202             sub ACTION_perltidy {
203 0     0 1   my $self = shift;
204 0 0         eval { require Perl::Tidy } || do {
  0            
205 0           $self->log_warn(
206             "Perl::Tidy is not installed$/" . "Please install it and rerun ./Build perltidy$/");
207 0           return;
208             };
209 0           my @files;
210 0           for my $dir ($self->PERL_DIRS) {
211 0           my $dir_files = $self->rscan_dir($dir);
212 0           for my $file (@$dir_files) {
213 0 0 0       push @files, $file
214             if -f $file && $file =~ m{(\.pl|/ado|\.pm|ado.*?\.conf|\.t)$}x;
215             }
216             }
217              
218 0 0         if ($self->verbose) {
219 0           say join($/, @files) . "$/perltidy-ing " . @files . " files...";
220             }
221              
222             #We use ./.perltidyrc for all arguments
223 0           Perl::Tidy::perltidy(argv => [@files]);
224 0           foreach my $file (@{$self->rscan_dir($self->base_dir)}) {
  0            
225 0 0         unlink($file) if $file =~ /\.bak$/;
226             }
227 0           say "perltidy-ed distribution.";
228 0           return;
229             }
230              
231             sub ACTION_submit {
232 0     0 1   my $self = shift;
233              
234             #$self->depends_on("perltidy");
235 0           say "TODO: commit and push after tidying and testing and who knows what";
236 0           return;
237             }
238              
239              
240             #Empties log files in a given directory.
241             sub _empty_log_files {
242 0 0   0     (my ($log_dir) = @_) || Carp::croak('Please provide $log_dir');
243 0   0       open my $logd, ">", "$log_dir/development.log" || Carp::croak $!;
244 0           close $logd;
245 0   0       open my $logp, ">", "$log_dir/production.log" || Carp::croak $!;
246 0           close $logp;
247 0           return;
248             }
249              
250             sub do_create_readme {
251 0     0 1   my $self = shift;
252 0 0         if ($self->dist_version_from =~ /Ado\.pm$/) {
253              
254             #Create README from Ado::Manual.pod
255 0           require Pod::Text;
256 0           my $readme_from = catfile('lib', 'Ado', 'Manual.pod');
257 0           my $parser = Pod::Text->new(sentence => 0, indent => 2, width => 76);
258 0           $parser->parse_from_file($readme_from, 'README');
259 0           $self->log_info("Created README$/");
260              
261             #add README.md just to be cool..
262 0 0         eval { require Pod::Markdown }
  0            
263             || return $self->log_warn('Pod::Markdown required for creating README.md' . $/);
264 0           $parser = Pod::Markdown->new;
265 0           $parser->parse_from_file($readme_from);
266 0           my $readme_md = 'README.md';
267 0 0         if (open(my $out, '>', $readme_md)) {
268 0           my $markdown = $parser->as_markdown;
269 0           my $ci_badge =
270             '[![Build Status](https://travis-ci.org/kberov/Ado.svg?'
271             . 'branch=master)](https://travis-ci.org/kberov/Ado)';
272 0           $markdown =~ s/(\n.+Travis-CI.+\n)/$1\n$ci_badge\n\n/xgm;
273 0           $out->say($markdown);
274 0           $out->close;
275 0           $self->log_info("Created $readme_md$/");
276             }
277 0           else { Carp::croak("Could not create $readme_md... $!"); }
278             }
279             else {
280 0           $self->SUPER::do_create_readme();
281             }
282 0           return;
283             }
284              
285             1;
286              
287             =pod
288              
289             =encoding utf8
290              
291             =head1 NAME
292              
293             Ado::Build - Custom routines for Ado installation
294              
295             =head1 SYNOPSIS
296              
297             #Build.PL
298             use 5.014000;
299             use strict;
300             use warnings FATAL => 'all';
301             use FindBin;
302             use lib("$FindBin::Bin/lib");
303             use Ado::Build;
304             my $builder = Ado::Build->new(..);
305             $builder->create_build_script();
306              
307             #on the command line
308             cd /path/to/cloned/Ado
309             perl Build.PL
310             ./Build
311             ./Build test
312             #change/add some code
313             ./Build test
314             ./Build perltidy
315             ./Build dist
316             ./Build submit
317             #.... and so on
318              
319              
320             =head1 DESCRIPTION
321              
322             This is a subclass of L. We use L to add
323             custom functionality. This module and L exist just because of
324             the additional install paths that we use beside C and C and
325             processing the files in those paths. These modules also can serve as examples
326             for your own builders if you have some custom things to do during build, test,
327             install and even if you need to add a new C to your setup.
328              
329             =head1 ATTRIBUTES
330              
331             Ado::Build defines some attributes, used across different actions.
332              
333             =head2 PERL_DIRS
334              
335             Returns the list of absolute paths to directories in the project containing
336             Perl files. Read-only.
337              
338             $self->PERL_DIRS;
339             #(/base/dir/bin, /base/dir/lib, /base/dir/t, /base/dir/etc)
340              
341              
342              
343             =head1 METHODS
344              
345             Ado::Build inherits all methods from L and implements
346             the following ones.
347              
348             =head2 create_build_script
349              
350             This method is called in C.
351             In this method we also call C for C C,
352             C and C folders.
353             Finally we set all the Cs for the distro
354             and we call C<$self-ESUPER::create_build_script>.
355              
356             =head2 process_etc_files
357              
358             Moves files found in C to C.
359             See L
360             Returns void.
361              
362             =head2 process_log_files
363              
364             Moves files found in C to C.
365             Returns void.
366              
367             =head2 process_public_files
368              
369             Moves files found in C to C.
370             Returns void.
371              
372             =head2 process_templates_files
373              
374             Moves files found in C to C.
375             Returns void.
376              
377             =head2 ACTION_build
378              
379             We put here custom functionality executed around the
380             C<$self-ESUPER::ACTION_build>. See the source for details.
381              
382             =head2 ACTION_test
383              
384             We put here custom functionality executed around the
385             C<$self-ESUPER::ACTION_test>. See the source for details.
386              
387             =head2 ACTION_dist
388              
389             We put here custom functionality executed around the
390             C<$self-ESUPER::ACTION_dist>. See the sources for details.
391              
392             =head2 ACTION_install
393              
394             Changes file permissions to C<0600> of some files
395             like C and to C<0400> of some files like C.
396             You can put additional custom functionality here.
397              
398             =head2 ACTION_fakeuninstall
399              
400             Dry run for uninstall operation against module Ado.
401              
402             =head2 ACTION_uninstall
403              
404             Perform uninstall operation against Ado module.
405              
406             =head2 ACTION_perltidy
407              
408             Tidies all C<*.conf, *.pm, *.pl, *.t> files found in project
409             directories C in the distribution.
410             Uses the C<./pertidyrc> found in the project root directory.
411             Cleans up all C<.bak> files.
412             This action does not tidies C.
413             Use C for that.
414              
415             perl Build.PL
416             ./Build perltidy
417             ./Build
418             ...
419              
420             =head2 ACTION_submit
421              
422             TODO: commit and push after testing tidying and who knows what..
423              
424             ./Build submit
425              
426              
427              
428             =head2 do_create_readme
429              
430             Creates the README file from C.
431              
432             =head1 SEE ALSO
433              
434             L,
435             L,
436             L,
437             L,
438             Build.PL in Ado distribution directory.
439              
440             =head1 AUTHOR
441              
442             Красимир Беров (Krasimir Berov)
443              
444             =head1 COPYRIGHT AND LICENSE
445              
446             Copyright 2013-2014 Красимир Беров (Krasimir Berov).
447              
448             This program is free software, you can redistribute it and/or
449             modify it under the terms of the
450             GNU Lesser General Public License v3 (LGPL-3.0).
451             You may copy, distribute and modify the software provided that
452             modifications are open source. However, software that includes
453             the license may release under a different license.
454              
455             See http://opensource.org/licenses/lgpl-3.0.html for more information.
456              
457             =cut
458