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