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