File Coverage

blib/lib/App/SmokeBrew/BuildPerl.pm
Criterion Covered Total %
statement 63 108 58.3
branch 2 30 6.6
condition 0 5 0.0
subroutine 19 21 90.4
pod 1 1 100.0
total 85 165 51.5


line stmt bran cond sub pod time code
1             package App::SmokeBrew::BuildPerl;
2             $App::SmokeBrew::BuildPerl::VERSION = '1.00';
3             #ABSTRACT: build and install a particular version of Perl
4              
5 2     2   804 use strict;
  2         4  
  2         58  
6 2     2   9 use warnings;
  2         4  
  2         52  
7 2     2   461 use App::SmokeBrew::Tools;
  2         27  
  2         61  
8 2     2   533 use Log::Message::Simple qw[msg error];
  2         8976  
  2         120  
9 2     2   1009 use CPAN::Perl::Releases qw[perl_tarballs];
  2         3760  
  2         137  
10 2     2   15 use Perl::Version;
  2         4  
  2         50  
11 2     2   10 use File::Spec;
  2         3  
  2         37  
12 2     2   3507 use Devel::PatchPerl;
  2         46091  
  2         102  
13 2     2   14 use Config qw[];
  2         3  
  2         36  
14 2     2   11 use Cwd qw[chdir cwd];
  2         4  
  2         92  
15 2     2   10 use IPC::Cmd qw[run can_run];
  2         4  
  2         105  
16 2     2   10 use File::Path qw[mkpath rmtree];
  2         4  
  2         77  
17 2     2   9 use File::pushd qw[pushd];
  2         7  
  2         64  
18              
19 2     2   1123 use Moose;
  2         855804  
  2         17  
20 2     2   14132 use Moose::Util::TypeConstraints;
  2         5  
  2         19  
21 2     2   5425 use MooseX::Types::Path::Class qw[Dir];
  2         802993  
  2         24  
22 2     2   3727 use App::SmokeBrew::Types qw[ArrayRefStr ArrayRefUri];
  2         8  
  2         27  
23              
24             with 'App::SmokeBrew::PerlVersion';
25              
26             my @mirrors = (
27             'http://www.cpan.org/',
28             'http://cpan.cpantesters.org/',
29             'http://cpan.hexten.net/',
30             'ftp://ftp.funet.fi/pub/CPAN/',
31             );
32              
33             has 'builddir' => (
34             is => 'ro',
35             isa => Dir,
36             required => 1,
37             coerce => 1,
38             );
39              
40             has 'prefix' => (
41             is => 'ro',
42             isa => Dir,
43             required => 1,
44             coerce => 1,
45             );
46              
47             has 'perlargs' => (
48             is => 'ro',
49             isa => 'ArrayRefStr',
50             default => sub { [] },
51             auto_deref => 1,
52             );
53              
54             has 'skiptest' => (
55             is => 'ro',
56             isa => 'Bool',
57             default => 0,
58             );
59              
60             has 'verbose' => (
61             is => 'ro',
62             isa => 'Bool',
63             default => 0,
64             );
65              
66             has 'noclean' => (
67             is => 'ro',
68             isa => 'Bool',
69             default => 0,
70             );
71              
72             has 'nozapman' => (
73             is => 'ro',
74             isa => 'Bool',
75             default => 0,
76             );
77              
78             has 'make' => (
79             is => 'ro',
80             isa => 'Str',
81             default => sub { my $make = $Config::Config{make} || 'make'; can_run( $make ) },
82             );
83              
84             has 'jobs' => (
85             is => 'ro',
86             isa => 'Int',
87             );
88              
89             has 'mirrors' => (
90             is => 'ro',
91             isa => 'ArrayRefUri',
92             default => sub { \@mirrors },
93             coerce => 1,
94             );
95              
96             sub build_perl {
97 1     1 1 2 my $self = shift;
98 1         5 my $perl_version = $self->perl_version;
99 1         36 msg(sprintf("Starting build for '%s'",$perl_version), $self->verbose);
100 1 50       1235 if ( grep { m!Dusequadmath! } $self->perlargs ) {
  2         11  
101 1         33 msg(sprintf("Checking if this perl '%s' can be built with quadmath",$perl_version), $self->verbose);
102 1 50       849 if ( ! $self->can_quadmath ) {
103 1         85 error(sprintf("This perl '%s' cannot be built with quadmath",$perl_version), $self->verbose);
104 1         948 return;
105             }
106 0           msg(sprintf("Congratulations, this perl '%s' can be built with quadmath",$perl_version), $self->verbose);
107             }
108 0           $self->builddir->mkpath();
109 0           my $file = $self->_fetch();
110 0 0         return unless $file;
111 0           my $extract = $self->_extract( $file );
112 0 0         return unless $extract;
113 0 0         unlink( $file ) unless $self->noclean();
114 0           $self->prefix->mkpath();
115 0           my $prefix = File::Spec->catdir( $self->prefix->absolute, $perl_version );
116 0           msg("Removing existing installation at ($prefix)", $self->verbose );
117 0           rmtree( $prefix );
118 0           msg('Applying any applicable patches to the source', $self->verbose );
119 0           Devel::PatchPerl->patch_source( $self->version->stringify, $extract );
120             {
121 0           my $CWD = pushd( $extract );
  0            
122 0           mkpath( File::Spec->catdir( $prefix, 'bin' ) );
123 0           my @conf_opts = $self->perlargs;
124 0 0         push @conf_opts, '-Dusedevel' if $self->is_dev_release();
125 0           unshift @conf_opts, '-Dprefix=' . $prefix;
126 0           local $ENV{MAKE} = $self->make;
127 0           my $cmd = [ './Configure', '-des', @conf_opts ];
128 0 0 0       my $jobs = ( $self->jobs && $self->can_jobs ? "-j" . $self->jobs : '' );
129 0 0         return unless scalar run( command => $cmd,
130             verbose => 1, );
131 0 0         return unless scalar run( command => [ $self->make, $jobs ], verbose => $self->verbose );
132 0 0         unless ( $self->skiptest ) {
133 0 0         return unless scalar run( command => [ $self->make, $jobs, 'test' ], verbose => $self->verbose );
134             }
135 0 0         return unless scalar run( command => [ $self->make, $jobs, 'install' ], verbose => $self->verbose );
136 0 0         rmtree ( File::Spec->catdir( $prefix, 'man' ) ) # remove the manpages
137             unless $self->nozapman;
138             }
139 0 0         rmtree( $extract ) unless $self->noclean();
140 0           return $prefix;
141             }
142              
143             sub _fetch {
144 0     0     my $self = shift;
145 0           my $perldist;
146             {
147 0           ( my $version = $self->perl_version ) =~ s/perl-//g;
  0            
148 0           my $tarballs = perl_tarballs( $version );
149 0           $perldist = 'authors/id/' . $tarballs->{'tar.gz'};
150             }
151 0           msg("Fetching '" . $perldist . "'", $self->verbose);
152 0           my $stat = App::SmokeBrew::Tools->fetch( $perldist, $self->builddir->absolute, $self->mirrors );
153 0 0         return $stat if $stat;
154 0           error("Failed to fetch '". $perldist . "'", $self->verbose);
155 0           return $stat;
156             }
157              
158             sub _extract {
159 0     0     my $self = shift;
160 0   0       my $tarball = shift || return;
161 0           msg("Extracting '$tarball'", $self->verbose);
162 0           return App::SmokeBrew::Tools->extract( $tarball, $self->builddir->absolute );
163             }
164              
165 2     2   4125 no Moose;
  2         15  
  2         28  
166              
167             __PACKAGE__->meta->make_immutable;
168              
169             qq[Building a perl];
170              
171             __END__
172              
173             =pod
174              
175             =encoding UTF-8
176              
177             =head1 NAME
178              
179             App::SmokeBrew::BuildPerl - build and install a particular version of Perl
180              
181             =head1 VERSION
182              
183             version 1.00
184              
185             =head1 SYNOPSIS
186              
187             use strict;
188             use warnings;
189             use App::SmokeBrew::BuildPerl;
190              
191             my $bp = App::SmokeBrew::BuildPerl->new(
192             version => '5.12.0',
193             builddir => 'build',
194             prefix => 'prefix',
195             skiptest => 1,
196             verbose => 1,
197             perlargs => [ '-Dusemallocwrap=y', '-Dusemymalloc=n' ],
198             );
199              
200             my $prefix = $bp->build_perl();
201              
202             print $prefix, "\n";
203              
204             =head1 DESCRIPTION
205              
206             App::SmokeBrew::BuildPerl encapsulates the task of configuring, building, testing and installing
207             a perl executable ( and associated core modules ).
208              
209             =head1 CONSTRUCTOR
210              
211             =over
212              
213             =item C<new>
214              
215             Creates a new App::SmokeBrew::BuildPerl object. Takes a number of options.
216              
217             =over
218              
219             =item C<version>
220              
221             A required attribute, this is the version of perl to install. Must be a valid perl version.
222              
223             =item C<builddir>
224              
225             A required attribute, this is the working directory where builds can take place. It will be coerced
226             into a L<Path::Class::Dir> object by L<MooseX::Types::Path::Class>.
227              
228             =item C<prefix>
229              
230             A required attribute, this is the prefix of the location where perl installs will be made, it will be coerced
231             into a L<Path::Class::Dir> object by L<MooseX::Types::Path::Class>.
232              
233             example:
234              
235             prefix = /home/cpan/pit/rel
236             perls will be installed as /home/cpan/pit/perl-5.12.0, /home/cpan/pit/perl-5.10.1, etc.
237              
238             =item C<skiptest>
239              
240             Optional boolean attribute, which defaults to 0, indicates whether the testing phase of the perl installation
241             ( C<make test> ) should be skipped or not.
242              
243             =item C<perlopts>
244              
245             Optional attribute, takes an arrayref of perl configuration flags that will be passed to C<Configure>.
246             There is no need to specify C<-Dprefix> or C<-Dusedevel> as the module handles these for you.
247              
248             perlopts => [ '-Dusethreads', '-Duse64bitint' ],
249              
250             =item C<verbose>
251              
252             Optional boolean attribute, which defaults to 0, indicates whether we should produce verbose output.
253              
254             =item C<noclean>
255              
256             Optional boolean attribute, which defaults to 0, indicates whether we should cleanup files that we
257             produce under the C<builddir> or not.
258              
259             =item C<nozapman>
260              
261             This is an optional boolean attribute. Usually C<man> pages that are generated by the perl installation are removed.
262             Specify this option if you wish the C<man> pages to be retained.
263              
264             =item C<make>
265              
266             Optional attribute to specify the C<make> utility to use. Defaults to C<make> and you should only have to
267             mess with this on wacky platforms.
268              
269             =item C<mirrors>
270              
271             This is an optional argument. Specify the URL of a CPAN mirror that should be used for retrieving required files
272             during the build process. This may be a single URL or an arrayref of a number of URLs.
273              
274             =back
275              
276             =back
277              
278             =head1 METHODS
279              
280             =over
281              
282             =item C<build_perl>
283              
284             Fetches, extracts, configures, builds, tests (see C<skiptest>) and installs the C<perl> executable.
285              
286             The C<builddir> is used for the first five processes. Installation is made into the given C<prefix>
287             directory.
288              
289             =back
290              
291             =head1 SEE ALSO
292              
293             L<App::perlbrew>
294              
295             L<Module::CoreList>
296              
297             =head1 AUTHOR
298              
299             Chris Williams <chris@bingosnet.co.uk>
300              
301             =head1 COPYRIGHT AND LICENSE
302              
303             This software is copyright (c) 2020 by Chris Williams.
304              
305             This is free software; you can redistribute it and/or modify it under
306             the same terms as the Perl 5 programming language system itself.
307              
308             =cut