File Coverage

blib/lib/Acme/Module/Build/Tiny.pm
Criterion Covered Total %
statement 42 187 22.4
branch 0 30 0.0
condition 0 21 0.0
subroutine 14 45 31.1
pod 6 9 66.6
total 62 292 21.2


line stmt bran cond sub pod time code
1             package Acme::Module::Build::Tiny;
2 1     1   153904 use strict;
  1         2  
  1         43  
3 1     1   6 use warnings;
  1         2  
  1         31  
4 1     1   4 use Config;
  1         2  
  1         41  
5 1     1   1010 use Data::Dumper 0 ();
  1         11684  
  1         32  
6 1     1   1059 use ExtUtils::Install 0 ();
  1         412727  
  1         40  
7 1     1   722018 use ExtUtils::MakeMaker 0 ();
  1         475967  
  1         37  
8 1     1   8 use File::Find 0 ();
  1         8882  
  1         104  
9 1     1   20 use File::Path 0 ();
  1         40  
  1         29  
10 1     1   7 use File::Spec 0 ();
  1         23  
  1         21  
11 1     1   1791 use Getopt::Long 0 ();
  1         12979  
  1         58  
12 1     1   3392 use Test::Harness 0 ();
  1         84380  
  1         35  
13 1     1   1612 use Tie::File 0 ();
  1         21972  
  1         32  
14 1     1   13 use Text::ParseWords 0 ();
  1         20  
  1         2283  
15             our $VERSION = '0.06';
16              
17             my %re = (
18             lib => qr{\.(?:pm|pod)$},
19             t => qr{\.t},
20             't/lib' => qr{\.(?:pm|pod)$},
21             prereq => qr{^\s*use[ \t]+(\S+)[ \t]+(v?[0-9._]+)[^;]*;}m,
22             authors => qr{^=head1 AUTHORS?\s*\n(.*?)^=\w}sm,
23             );
24              
25             my %install_map = map { +"blib/$_" => $Config{"installsite$_"} } qw/lib script/;
26              
27             my %install_base = ( lib => [qw/lib perl5/], script => [qw/lib bin/] );
28              
29             my @opts_spec = ( 'install_base:s', 'uninst:i' );
30              
31             sub _split_like_shell {
32 0     0     my $string = shift;
33 0           $string =~ s/^\s+|\s+$//g;
34 0           return Text::ParseWords::shellwords($string);
35             }
36              
37 0   0 0     sub _home { return $ENV{HOME} || $ENV{USERPROFILE} }
38              
39 0     0     sub _default_rc { return File::Spec->catfile( _home(), '.modulebuildrc' ) }
40              
41             sub _get_rc_opts {
42 0   0 0     my $rc_file = ($ENV{MODULEBUILDRC} || _default_rc());
43 0 0         return {} unless -f $rc_file;
44 0           my $guts = _slurp( $rc_file );
45 0           $guts =~ s{\n[ \t]+}{ }mg; # join lines with leading whitespace
46 0           $guts =~ s{^#.*$}{}mg; # strip comments
47 0           $guts =~ s{\n\s*\n}{\n}mg; # empty lines
48 0           my %opt = map { my ($k,$v) = $_ =~ /(\S+)\s+(.*)/; $k => $v }
  0            
  0            
49 0           grep { /\S/ } split /\n/, $guts;
50 0           return \%opt;
51             }
52              
53             sub _get_options {
54 0     0     my ($action,$opt) = @_;
55 0           my $rc_opts = _get_rc_opts;
56 0           for my $s ( $ENV{PERL_MB_OPT}, $rc_opts->{$action}, $rc_opts->{'*'} ) {
57 0 0 0       unshift @ARGV, _split_like_shell($s) if defined $s && length $s;
58             }
59 0           Getopt::Long::GetOptions($opt, @opts_spec);
60             }
61              
62             sub run {
63 0   0 0 0   my $opt = eval { do '_build/build_params' } || {};
64 0 0         my $action = ! defined $ARGV[0] ? 'build'
    0          
65             : $ARGV[0] =~ /\A\w+\z/ ? $ARGV[0]
66             : 'build';
67 0           _get_options($action, $opt);
68 0 0         my $fcn = __PACKAGE__->can($action) or die "$action not implemented\n";
69 0           $fcn->(%$opt);
70             }
71              
72             sub debug {
73 0     0 0   my %opt = @_;
74 0           print _data_dump(\%opt) . "\n";
75             }
76              
77             sub import {
78 0     0     _get_options('Build_PL', my $opt = {});
79 0           my @f = _files('lib');
80 0           my $meta = {
81             name => _mod2dist(_path2mod($f[0])),
82             version => MM->parse_version($f[0]),
83             };
84 0           print "Creating new 'Build' script for '$meta->{name}'" .
85             " version '$meta->{version}'\n";
86 0 0         my $perl = $^X =~ /\Aperl[.0-9]*\z/ ? $Config{perlpath} : $^X;
87 0           _spew('Build' => "#!$perl\n", _slurp( $INC{_mod2pm(shift)} ) );
88 0           chmod 0755, 'Build';
89 0           _spew( '_build/prereqs', _data_dump(_find_prereqs()) );
90 0           _spew( '_build/build_params', _data_dump($opt) );
91 0           _spew( '_build/meta', _data_dump(_fill_meta($meta, $f[0])) );
92 0 0         _spew( 'MYMETA.yml', _slurp('META.yml')) if -f 'META.yml';
93             }
94              
95             sub build {
96 0           my $map = {
97             (map {$_=>"blib/$_"} _files('lib')),
98 0     0 0   (map {;"bin/$_"=>"blib/script/$_"} map {s{^bin/}{}; $_} _files('bin')),
  0            
  0            
  0            
99             };
100 0           ExtUtils::Install::pm_to_blib($map, 'blib/lib/auto');
101 0           ExtUtils::MM->fixin($_), chmod(0555, $_) for _files('blib/script');
102 0           return 1;
103             }
104              
105             sub test {
106 0     0 1   build();
107 0           local @INC = (File::Spec->rel2abs('blib/lib'), @INC);
108 0           Test::Harness::runtests(_files('t'));
109             }
110              
111             sub _install_base {
112 0     0     my $map = {map {$_=>File::Spec->catdir($_[0],@{$install_base{$_}})} keys %install_base};
  0            
  0            
113             }
114              
115             sub install {
116 0     0 1   my %opt = @_;
117 0           build();
118 0 0         ExtUtils::Install::install(
119             ($opt{install_base} ? _install_base($opt{install_base}) : \%install_map), 1
120             );
121 0           return 1;
122             }
123              
124             sub distdir {
125 0     0 1   require ExtUtils::Manifest; ExtUtils::Manifest->VERSION(1.57);
  0            
126 0           File::Path::rmtree(_distdir());
127 0 0         _spew('MANIFEST.SKIP', "#!include_default\n^"._distbase()."\n") unless -f 'MANIFEST.SKIP';
128 0           local $ExtUtils::Manifest::Quiet = 1;
129 0           ExtUtils::Manifest::mkmanifest();
130 0           ExtUtils::Manifest::manicopy( ExtUtils::Manifest::maniread(), _distdir() );
131 0           _spew(_distdir("/inc/",_mod2pm(__PACKAGE__)) => _slurp( __FILE__ ) );
132 0           _append(_distdir("MANIFEST"), "inc/" . _mod2pm(__PACKAGE__) . "\n");
133 0           _write_meta(_distdir("META.yml"));
134 0           _append(_distdir("MANIFEST"), "META.yml");
135             }
136              
137             sub dist {
138 0     0 1   require Archive::Tar; Archive::Tar->VERSION(1.09);
  0            
139 0           distdir();
140 0           my ($distdir,@f) = (_distdir(),_files(_distdir()));
141 1     1   12 no warnings 'once';
  1         8  
  1         1964  
142 0 0         $Archive::Tar::DO_NOT_USE_PREFIX = (grep { length($_) >= 100 } @f) ? 0 : 1;
  0            
143 0           my $tar = Archive::Tar->new;
144 0           $tar->add_files(@f);
145 0           $_->mode($_->mode & ~022) for $tar->get_files;
146 0           $tar->write("$distdir.tar.gz", 1);
147 0           File::Path::rmtree($distdir);
148             }
149              
150 0     0 1   sub clean { File::Path::rmtree('blib'); 1 }
  0            
151              
152 0     0 1   sub realclean { clean(); File::Path::rmtree($_) for _distdir(), qw/Build _build/; 1; }
  0            
  0            
153              
154 0     0     sub _slurp { do { local (@ARGV,$/)=$_[0]; <> } }
  0            
  0            
155             sub _spew {
156 0     0     my $file = shift;
157 0           File::Path::mkpath(File::Basename::dirname($file));
158 0           open my $fh, '>', $file;
159 0           print {$fh} @_;
  0            
160             }
161 0     0     sub _append { open my $fh, ">>", shift; print {$fh} @_ }
  0            
  0            
162              
163             sub _data_dump {
164 0     0     'do{ my ' . Data::Dumper->new([shift],['x'])->Purity(1)->Dump() . '$x; }'
165             }
166              
167 0     0     sub _mod2pm { (my $mod = shift) =~ s{::}{/}g; return "$mod.pm" }
  0            
168 0     0     sub _path2mod { (my $pm = shift) =~ s{/}{::}g; return substr $pm, 5, -3 }
  0            
169 0     0     sub _mod2dist { (my $mod = shift) =~ s{::}{-}g; return $mod; }
  0            
170              
171             sub _files {
172 0     0     my ($dir,@f) = shift;
173 0 0         return unless -d $dir;
174 0   0       my $regex = $re{$dir} || qr/./;
175 0 0 0 0     File::Find::find( sub { -f && /$regex/ && push @f, $File::Find::name},$dir);
  0            
176 0           return sort { length $a <=> length $b } @f;
  0            
177             }
178              
179 0     0     sub _distbase { my @f = _files('lib'); return _mod2dist(_path2mod($f[0])) }
  0            
180              
181             sub _distdir {
182 0     0     my @f = _files('lib');
183 0           return File::Spec->catfile(_distbase ."-". MM->parse_version($f[0]), @_);
184             }
185              
186             sub _fill_meta {
187 0     0     my ($m, $src) = @_;
188 0           for ( split /\n/, _slurp($src) ) {
189 0 0         next unless /^=(?!cut)/ .. /^=cut/; # in POD
190 0 0         ($m->{abstract}) = /^ (?: [a-z:]+ \s+ - \s+ ) (.*\S) /ix
191             unless $m->{abstract};
192             }
193 0           $m->{author} = _find_authors($src);
194 0           return $m;
195             }
196              
197             sub _find_authors {
198 0     0     my $guts = _slurp($_[0]);
199 0           my ($block) = $guts =~ $re{authors};
200 0 0         return $block ? [ map { s{^\s+}{}; s{\s+$}{}; $_ } grep { /\S/ } split /\n/, $block ] : [];
  0            
  0            
  0            
  0            
201             }
202              
203             sub _write_meta {
204 0     0     my $file = shift;
205 0   0       my $meta = eval { do '_build/meta' } || {};
206 0   0       my $prereqs = eval { do '_build/prereqs' } || {};
207 0           $meta->{$_} = $prereqs->{$_} for keys %$prereqs;
208 0           $meta->{generated_by} = sprintf("%s version %s", __PACKAGE__, $VERSION);
209 0           $meta->{'meta-spec'} = { version => 1.4, url => 'http://module-build.sourceforge.net/META-spec-v1.4.html' };
210 0           $meta->{'license'} = 'perl';
211 0           require CPAN::Meta::YAML;
212 0           CPAN::Meta::YAML::DumpFile($file,$meta);
213             }
214              
215             sub _find_prereqs {
216 0     0     my (%requires, %build_requires);
217 0           for my $guts ( map { _slurp($_) } _files('lib'), _files('bin') ) {
  0            
218 0           while ( $guts =~ m{$re{prereq}}g ) { $requires{$1}=$2; }
  0            
219             }
220 0           for my $guts ( map { _slurp($_) } _files('t'), _files('t/lib') ) {
  0            
221 0           while ( $guts =~ m{$re{prereq}}g ) { $build_requires{$1}=$2; }
  0            
222             }
223 0           return { requires => \%requires, build_requires => \%build_requires };
224             }
225              
226             run() unless caller; # modulino :-)
227              
228             1;
229              
230             __END__