File Coverage

blib/lib/CPANPLUS/Dist/Arch.pm
Criterion Covered Total %
statement 339 673 50.3
branch 72 288 25.0
condition 7 52 13.4
subroutine 63 96 65.6
pod 24 24 100.0
total 505 1133 44.5


line stmt bran cond sub pod time code
1             package CPANPLUS::Dist::Arch;
2              
3 7     7   594197 use warnings 'FATAL' => 'all';
  7         16  
  7         320  
4 7     7   37 use strict;
  7         12  
  7         145  
5              
6 7     7   3645 use CPANPLUS::Dist::Base qw();
  7         1898091  
  7         171  
7 7     7   70 use Exporter qw(import);
  7         16  
  7         673  
8              
9             our $VERSION = '1.31';
10             our @EXPORT = qw();
11             our @EXPORT_OK = qw(dist_pkgname dist_pkgver);
12             our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
13             our @ISA = qw(CPANPLUS::Dist::Base);
14              
15 7     7   4689 use File::Spec::Functions qw(catfile catdir);
  7         5983  
  7         480  
16 7     7   21176 use Module::CoreList qw();
  7         343900  
  7         3364  
17 7     7   132 use CPANPLUS::Error qw(error msg);
  7         16  
  7         1588  
18 7     7   54 use Digest::MD5 qw();
  7         15  
  7         139  
19 7     7   8040 use Pod::Select qw();
  7         14857  
  7         180  
20 7     7   124 use List::Util qw(first);
  7         15  
  7         772  
21 7     7   35 use File::Path 2.06_05 qw(make_path);
  7         125  
  7         333  
22 7     7   1537 use File::Copy qw(copy);
  7         4732  
  7         389  
23 7     7   4548 use File::stat qw(stat);
  7         50455  
  7         39  
24 7     7   558 use DynaLoader qw();
  7         14  
  7         142  
25 7     7   36 use IPC::Cmd qw(can_run);
  7         20  
  7         316  
26 7     7   36 use version qw();
  7         12  
  7         140  
27 7     7   4723 use English qw(-no_match_vars);
  7         19351  
  7         42  
28 7     7   3022 use Carp qw(carp croak confess);
  7         12  
  7         366  
29 7     7   35 use Cwd qw();
  7         12  
  7         69375  
30              
31             #-----------------------------------------------------------------------------
32             # CLASS CONSTANTS
33             #-----------------------------------------------------------------------------
34              
35              
36             my $MKPKGCONF_FQP = '/etc/makepkg.conf';
37             my $CPANURL = 'http://search.cpan.org';
38             my $ROOT_USER_ID = 0;
39              
40             my $CFG_VALUE_MATCH = '\A \s* (%s) \s* = \s* (.*?) \s* (?: \#.* )? \z';
41              
42             my $NONROOT_WARNING = <<'END_MSG';
43             In order to install packages as a non-root user (highly recommended)
44             you must have a sudo-like command specified in your CPANPLUS
45             configuration.
46             END_MSG
47              
48             # Patterns to use when using pacman for finding library owners.
49             my $PACMAN_FINDOWN = qr/\A.*? is owned by /;
50             my $PACMAN_FINDOWN_ERR = qr/\Aerror:/;
51              
52             # Override a package's name to conform to packaging guidelines.
53             # Copied entries from CPANPLUS::Dist::Pacman and alot more
54             # from searching for packages with perl in their name in
55             # [extra] and [community]
56             my $PKGNAME_OVERRIDES =
57             { map { split /[\s=]+/ } split /\s*\n+\s*/, <<'END_OVERRIDES' };
58              
59             libwww-perl = perl-libwww
60             aceperl = perl-ace
61             mod_perl = mod_perl
62              
63             glade-perl-two = perl-glade-two
64             Gnome2-GConf = gconf-perl
65             Gtk2-GladeXML = glade-perl
66             Glib = glib-perl
67             Gnome2 = gnome-perl
68             Gnome2-VFS = gnome-vfs-perl
69             Gnome2-Canvas = gnomecanvas-perl
70             Gnome2-GConf = gconf-perl
71             Gtk2 = gtk2-perl
72             Cairo = cairo-perl
73             Pango = pango-perl
74              
75             Perl-Critic = perl-critic
76             Perl-Tidy = perl-tidy
77             App-Ack = ack
78             TermReadKey = perl-term-readkey
79              
80             END_OVERRIDES
81              
82             # This var tells us whether to use a template module or our internal code:
83             my $TT_MOD_NAME;
84             my @TT_MOD_SEARCH = qw/ Template Template::Alloy Template::Tiny /;
85              
86             sub _tt_block
87             {
88 21     21   35 my $inside = shift;
89 21         479 return qr{ \[% -?
90             \s* $inside \s*
91             (?: (?: -%\] \n* ) | %\] ) }xms;
92             }
93             my $TT_IF_MATCH = _tt_block 'IF \s* (\w*)';
94             my $TT_END_MATCH = _tt_block 'END';
95             my $TT_VAR_MATCH = _tt_block '(\w+)';
96              
97             # Crude template for our PKGBUILD script
98             my $PKGBUILD_TEMPL = <<'END_TEMPL';
99             # Contributor: [% packager %]
100             # Generator : CPANPLUS::Dist::Arch [% version %]
101              
102             pkgname='[% pkgname %]'
103             pkgver='[% pkgver %]'
104             pkgrel='[% pkgrel %]'
105             pkgdesc="[% pkgdesc %]"
106             arch=([% arch %])
107             license=('PerlArtistic' 'GPL')
108             options=('!emptydirs')
109             depends=([% depends %])
110             makedepends=([% makedepends %])
111             [% IF checkdepends -%]
112             checkdepends=([% checkdepends %])
113             [% END -%]
114             [% IF conflicts -%]
115             conflicts=([% conflicts %])
116             [% END -%]
117             url='[% url %]'
118             source=('[% source %]')
119             md5sums=('[% md5sums %]')
120             [% IF sha512sums -%]
121             sha512sums=('[% sha512sums %]')
122             [% END -%]
123             _distdir="[% distdir %]"
124              
125             build() {
126             ( export PERL_MM_USE_DEFAULT=1 PERL5LIB="" \
127             PERL_AUTOINSTALL=--skipdeps \
128             PERL_MM_OPT="INSTALLDIRS=vendor DESTDIR='$pkgdir'" \
129             PERL_MB_OPT="--installdirs vendor --destdir '$pkgdir'" \
130             MODULEBUILDRC=/dev/null
131              
132             cd "$srcdir/$_distdir"
133             [% IF is_makemaker -%]
134             /usr/bin/perl Makefile.PL
135             make
136             [% END -%]
137             [% IF is_modulebuild -%]
138             /usr/bin/perl Build.PL
139             /usr/bin/perl Build
140             [% END -%]
141             )
142             }
143              
144             check() {
145             cd "$srcdir/$_distdir"
146             ( export PERL_MM_USE_DEFAULT=1 PERL5LIB=""
147             [% IF is_makemaker -%]
148             make test
149             [% END -%]
150             [% IF is_modulebuild -%]
151             /usr/bin/perl Build test
152             [% END -%]
153             )
154             }
155              
156             package() {
157             cd "$srcdir/$_distdir"
158             [% IF is_makemaker -%]
159             make install
160             [% END -%]
161             [% IF is_modulebuild -%]
162             /usr/bin/perl Build install
163             [% END -%]
164              
165             find "$pkgdir" -name .packlist -o -name perllocal.pod -delete
166             }
167              
168             # Local Variables:
169             # mode: shell-script
170             # sh-basic-offset: 2
171             # End:
172             # vim:set ts=2 sw=2 et:
173             END_TEMPL
174              
175             =for Weird "/usr/bin/perl Build" Syntax
176             We use "/usr/bin/perl Build" above instead of the normal "./Build" in
177             order to make the yaourt packager happy. Yaourt runs the PKGBUILD
178             under the /tmp directory and makepkg will fail if /tmp is a seperate
179             partition mounted with noexec. Thanks to xenoterracide on the AUR for
180             mentioning the problem.
181            
182             We also use /usr/bin/perl to ensure running the system-wide perl
183             interpreter.
184              
185             =cut
186              
187             #----------------------------------------------------------------------
188             # CLASS GLOBALS
189             #----------------------------------------------------------------------
190              
191             our ($Is_dependency, $PKGDEST, $SRCPKGDEST, $PACKAGER, $DEBUG);
192              
193             $PACKAGER = 'Anonymous';
194              
195             sub _DEBUG;
196             *_DEBUG = ( $ENV{DIST_ARCH_DEBUG}
197             ? sub { print STDERR '***DEBUG*** ', @_, "\n" }
198 21     21   33 : sub { return } );
199              
200             #---HELPER FUNCTION---
201             # Purpose: Expand environment variables and tildes like bash would.
202             #---------------------
203             sub _shell_expand
204             {
205 0     0   0 my $dir = shift;
206 0         0 $dir =~ s/ \A ~ / $ENV{HOME} /xmse; # tilde = homedir
  0         0  
207 0 0       0 $dir =~ s/ (?
  0         0  
208 0         0 $dir =~ s/ \\ [a-zA-Z] / /xmsg;
209 0         0 $dir =~ s/ \\ (.) / $1 /xmsg; # escaped special
210             # chars
211 0         0 return $dir;
212             }
213              
214             READ_CONF:
215             {
216             # Read makepkg.conf to see if there are system-wide settings
217             my $mkpkgconf;
218             if ( ! open $mkpkgconf, '<', $MKPKGCONF_FQP ) {
219             error "Could not read $MKPKGCONF_FQP: $!";
220             last READ_CONF;
221             }
222              
223             my %cfg_vars = ( 'PKGDEST' => \$PKGDEST,
224             'SRCPKGDEST' => \$SRCPKGDEST,
225             'PACKAGER' => \$PACKAGER );
226              
227             my $cfg_field_match = sprintf $CFG_VALUE_MATCH,
228             join '|', keys %cfg_vars;
229              
230             CFG_LINE:
231             while (<$mkpkgconf>) {
232             chomp;
233             next CFG_LINE unless ( my ($name, $value) = /$cfg_field_match/xmso );
234              
235             ${ $cfg_vars{$name} } =
236             ( $value =~ m/\A"(.*)"\z/
237             ? _shell_expand( $1 ) # expand double quotes
238             : ( $value =~ m/\A'(.*)'\z/
239             ? $1 # dont single quotes
240             : _shell_expand( $value )));
241             }
242             close $mkpkgconf or error "close on makepkg.conf: $!";
243             }
244              
245             # Environment variable has second highest priority for PACKAGER.
246             $PACKAGER = $ENV{PACKAGER} if $ENV{PACKAGER};
247              
248             #-----------------------------------------------------------------------------
249             # PUBLIC CPANPLUS::Dist::Base Interface
250             #-----------------------------------------------------------------------------
251              
252              
253             =for Interface Methods
254             See CPANPLUS::Dist::Base's documentation for a description of the
255             purpose of these functions. All of these "interface" methods override
256             Base's default actions in order to create our packages.
257              
258             =cut
259              
260             #---INTERFACE METHOD---
261             # Purpose : Checks if we have makepkg and pacman installed
262             # Returns : 1 - if we have the tools needed to make a pacman package.
263             # 0 - if we don't think so.
264             #----------------------
265             sub format_available
266             {
267 1     1 1 10 for my $prog ( qw/ makepkg pacman / ) {
268 1 50       7 if ( ! can_run($prog) ) {
269 1         507 error "CPANPLUS::Dist::Arch needs to run $prog, to work properly";
270 1         1252 return 0;
271             }
272             }
273 0         0 return 1;
274             }
275              
276             #---INTERFACE METHOD---
277             # Purpose : Initializes our object internals to get things started
278             # Returns : 1 always
279             #----------------------
280             sub init
281             {
282 5     5 1 113676 my $self = shift;
283              
284 5         35 $self->status->mk_accessors( qw{ pkgname pkgver pkgbase pkgdesc
285             pkgurl pkgsize arch pkgrel
286             builddir destdir metareqs
287              
288             pkgbuild_templ tt_init_args } );
289              
290 5         1460 return 1;
291             }
292              
293             #---INTERFACE METHOD---
294             # Purpose : Prepares the files and directories we will need to build a
295             # package. Also prepares any data we expect to have later,
296             # on a per-object basis.
297             # Return : 1 if ok, 0 on error.
298             # Postcond : Sets $self->status->prepare to 1 or 0 on success or
299             # failure.
300             #----------------------
301             sub prepare
302             {
303 0     0 1 0 my $self = shift;
304              
305 0         0 my $status = $self->status; # Private hash
306 0         0 my $module = $self->parent; # CPANPLUS::Module
307 0         0 my $intern = $module->parent; # CPANPLUS::Internals
308 0         0 my $conf = $intern->configure_object; # CPANPLUS::Configure
309 0         0 my $distcpan = $module->status->dist_cpan; # CPANPLUS::Dist::MM or
310             # CPANPLUS::Dist::Build
311              
312             # Call CPANPLUS::Dist::Base's prepare to resolve our pre-reqs.
313 0 0       0 $self->SUPER::prepare( @_ ) or return 0;
314              
315 0         0 $self->_prepare_status;
316 0         0 return $status->prepared;
317             }
318              
319             #---PRIVATE METHOD---
320             # Purpose : Finds the first package file that matches our internal data.
321             # (Meaning we might have built it) We search for .tar.gz and
322             # .tar.xz files.
323             # Note : .tar.xz files have higher priority than .tar.gz files.
324             # Params : $pkg_type - Must be 'bin' or 'src'.
325             # $destdir - The directory to search in for packages.
326             # Returns : The absolute path of the found package
327             #-------------------
328             sub _find_built_pkg
329             {
330 4     4   2516 my ($self, $pkg_type, $destdir) = @_;
331 4         27 my $status = $self->status;
332              
333 4         455 my $arch = $self->status->arch;
334 4 50       712 if ( $arch eq q{'any'} ) {
335 4         6 $arch = 'any';
336             }
337             else {
338 0         0 chomp( $arch = `uname -m` );
339             }
340              
341 4 100       23 my $pkgfile = catfile( $destdir,
    100          
342              
343             ( join q{.},
344              
345             ( join q{-},
346             $status->pkgname,
347             $status->pkgver,
348             $status->pkgrel,
349              
350             ( $pkg_type eq q{bin} ? $arch : qw// ),
351             ),
352              
353             ( $pkg_type eq q{bin} ? q{pkg} : q{src} ),
354              
355             q{tar},
356             ));
357              
358 4         740 _DEBUG "Searching for file starting with $pkgfile";
359              
360 4         7 my ($found) = grep { -f $_ } map { "$pkgfile.$_" } qw/ xz gz bz2 /;
  12         188  
  12         28  
361              
362 4 50       23 _DEBUG ( $found ? "Found $found" : "No package file found!" );
363              
364 4         25 return $found;
365             }
366              
367             #---INTERFACE METHOD---
368             # Purpose : Creates the pacman package using the 'makepkg' command.
369             #----------------------
370             sub create
371             {
372 0     0 1 0 my ($self, %opts) = (shift, @_);
373              
374 0         0 my $status = $self->status; # Private hash
375 0         0 my $module = $self->parent; # CPANPLUS::Module
376 0         0 my $intern = $module->parent; # CPANPLUS::Internals
377 0         0 my $conf = $intern->configure_object; # CPANPLUS::Configure
378 0         0 my $distcpan = $module->status->dist_cpan; # CPANPLUS::Dist::MM or
379             # CPANPLUS::Dist::Build
380              
381 0   0     0 my $pkg_type = $opts{pkg} || $opts{pkgtype} || 'bin';
382 0         0 $pkg_type = lc $pkg_type;
383              
384 0 0       0 unless ( $pkg_type =~ /^(?:bin|src)$/ ) {
385 0         0 error qq{Invalid package type requested: "$pkg_type"
386             Package type must be 'bin' or 'src'};
387 0         0 return 0;
388             }
389              
390 0 0       0 if ( $opts{verbose} ) {
391 0         0 my %fullname = ( bin => 'binary', src => 'source' );
392 0         0 msg "Creating a $fullname{$pkg_type} pacman package";
393             }
394              
395 0 0       0 if ( $pkg_type eq 'bin' ) {
396             # Use CPANPLUS::Dist::Base to make packages for pre-requisites...
397             # (starts the packaging process for any missing ones)
398 0         0 my @ok_resolve_args = qw/ verbose target force prereq_build /;
399 0         0 my %resolve_args = ( map { ( exists $opts{$_} ?
400 0 0       0 ($_ => $opts{$_}) : () ) }
401             @ok_resolve_args );
402              
403 0         0 local $Is_dependency = 1; # only top level pkgs explicitly installed
404              
405 0         0 $distcpan->_resolve_prereqs( %resolve_args,
406             'format' => ref $self,
407             'prereqs' => $module->status->prereqs );
408             }
409              
410             # Prepare our file name paths for pkgfile and source tarball...
411 0         0 my $srcfile_fqp = $status->pkgbase . '/' . $module->package;
412              
413 0         0 my ($destenv, $destdir) = $self->_calc_setdest( $pkg_type );
414 0   0     0 $destdir = $opts{'destdir'} || $status->destdir || $destdir;
415              
416             # Create directories for building and delivering the new package.
417             MKDIR_LOOP:
418 0         0 for my $dir ( $status->pkgbase, $destdir ) {
419 0 0       0 if ( -e $dir ) {
420 0 0       0 die "$dir exists but is not a directory!" unless ( -d _ );
421 0 0       0 die "$dir exists but is read-only!" unless ( -w _ );
422 0         0 next MKDIR_LOOP;
423             }
424              
425 0 0       0 make_path( $dir, { 'verbose' => $opts{'verbose'} ? 1 : 0 });
426             }
427 0         0 $destdir = Cwd::abs_path( $destdir );
428              
429             # Prepare our 'makepkg' package building directory,
430             # namely the PKGBUILD and source tarball files...
431 0 0       0 if ( ! -e $srcfile_fqp ) {
432 0         0 my $tarball_fqp = $module->_status->fetch;
433 0 0       0 link $tarball_fqp, $srcfile_fqp
434             or error "Failed to create link to $tarball_fqp: $OS_ERROR";
435             }
436              
437 0         0 $self->create_pkgbuild( $self->status->pkgbase );
438              
439             # Package it up!
440 0         0 local $ENV{ $destenv } = $destdir;
441              
442             my @cmdopts = (($EUID == 0) => '--asroot',
443             ($pkg_type eq 'src') => '--source',
444             $opts{'nocolor'} => '--nocolor',
445             $opts{'skiptest'} => '--nocheck',
446 0         0 $opts{'quiet'} => '2>&1 >/dev/null');
447 0         0 my $i = 0;
448 0         0 while ($i < @cmdopts) {
449 0 0       0 if ($cmdopts[$i]) {
450 0         0 splice @cmdopts, $i++, 1;
451             }
452             else {
453 0         0 splice @cmdopts, $i, 2;
454             }
455             }
456              
457 0         0 my $oldcwd = Cwd::getcwd();
458 0 0       0 chdir $status->pkgbase or die "chdir: $OS_ERROR";
459 0         0 my $makepkg_cmd = join q{ }, 'makepkg', '-f', @cmdopts;
460 0         0 system $makepkg_cmd;
461              
462 0 0       0 if ( $CHILD_ERROR ) {
463 0 0       0 error ( $CHILD_ERROR & 127
464             ? sprintf "makepkg failed with signal %d", $CHILD_ERROR & 127
465             : sprintf "makepkg returned abnormal status: %d",
466             $CHILD_ERROR >> 8 );
467 0         0 return 0;
468             }
469              
470 0 0       0 chdir $oldcwd or die "chdir: $OS_ERROR";
471              
472 0         0 my $pkg_path = $self->_find_built_pkg( $pkg_type, $destdir );
473 0         0 $status->dist( $pkg_path );
474              
475 0         0 return $status->created( 1 );
476             }
477              
478             #---INTERFACE METHOD---
479             # Purpose : Installs the package file (.pkg.tar.xz) using sudo and
480             # pacman.
481             # Comments : Called automatically on pre-requisite packages
482             #----------------------
483             sub install
484             {
485 0     0 1 0 my ($self, %opts) = (shift, @_);
486              
487 0         0 my $status = $self->status; # Private hash
488 0         0 my $module = $self->parent; # CPANPLUS::Module
489 0         0 my $intern = $module->parent; # CPANPLUS::Internals
490 0         0 my $conf = $intern->configure_object; # CPANPLUS::Configure
491              
492 0         0 my $pkgfile_fqp = $status->dist;
493 0 0       0 unless ( $pkgfile_fqp ) {
494 0         0 error << 'END_ERROR';
495             Path to package file has not been set.
496             Someone is using CPANPLUS::Dist::Arch incorrectly.
497             Tell them to call create() before install().
498             END_ERROR
499 0         0 return 0;
500             }
501              
502 0 0       0 die "Package file $pkgfile_fqp was not found" if ( ! -f $pkgfile_fqp );
503              
504             my @pacmancmd = ( 'pacman',
505 0 0       0 ($opts{'force'} ? '--force' : ()),
    0          
506             '--noconfirm',
507             ($Is_dependency ? '--asdeps' : '--asexplicit'),
508             '-U', $pkgfile_fqp,
509             );
510              
511             # Make sure the user has access to install a package...
512 0         0 my $sudocmd = $conf->get_program('sudo');
513 0 0       0 if ( $EFFECTIVE_USER_ID != $ROOT_USER_ID ) {
514 0 0       0 if ( $sudocmd ) {
515 0         0 unshift @pacmancmd, $sudocmd;
516             # $pacmancmd = "$sudocmd pacman -U $pkgfile_fqp";
517             }
518             else {
519 0         0 error $NONROOT_WARNING;
520 0         0 return 0;
521             }
522             }
523              
524 0         0 system @pacmancmd;
525              
526 0 0       0 if ( $CHILD_ERROR ) {
527 0 0       0 error ( $CHILD_ERROR & 127
528             ? sprintf qq{'@pacmancmd' failed with signal %d},
529             $CHILD_ERROR & 127
530             : sprintf qq{'@pacmancmd' returned abnormal status: %d},
531             $CHILD_ERROR >> 8
532             );
533 0         0 return 0;
534             }
535              
536 0         0 return $status->installed(1);
537             }
538              
539              
540             #-----------------------------------------------------------------------------
541             # EXPORTED FUNCTIONS
542             #-----------------------------------------------------------------------------
543              
544              
545             sub dist_pkgname
546             {
547 34 50   34 1 9755 croak "Must provide arguments to dist_pkgname" if ( @_ == 0 );
548 34         65 my ($distname) = @_;
549              
550             # Override this package name if there is one specified...
551             return $PKGNAME_OVERRIDES->{$distname}
552 34 100       131 if $PKGNAME_OVERRIDES->{$distname};
553              
554             # Package names should be lowercase and consist of alphanumeric
555             # characters only (and hyphens!)...
556 28         64 $distname = lc $distname;
557 28         52 $distname =~ tr/_/-/;
558 28         52 $distname =~ tr/-a-z0-9+//cd; # Delete all other chars
559 28         63 $distname =~ s/-[+]/-/g; # + next to - looks weird
560 28         45 $distname =~ s/[+]-/-/g;
561 28         48 $distname =~ tr/-/-/s;
562              
563             # Delete leading or trailing hyphens...
564 28         51 $distname =~ s/\A-//;
565 28         49 $distname =~ s/-\z//;
566              
567 28 50       137 die qq{Dist name '$distname' completely violates packaging standards}
568             if ( length $distname == 0 );
569              
570             # Don't prefix the package with perl- if it IS perl...
571 28 100       86 $distname = "perl-$distname" unless ( $distname eq 'perl' );
572              
573 28         106 return $distname;
574             }
575              
576             sub dist_pkgver
577             {
578 13     13 1 4287 my ($version) = @_;
579              
580             # Remove developer versions because pacman has no special logic
581             # to handle comparing them to regular versions such as perl uses.
582 13         46 $version =~ s/_[^_]+\z//;
583              
584             # Package versions should be numbers and decimal points only...
585 13         35 $version =~ tr/-_/../;
586 13         29 $version =~ tr/0-9.//cd;
587              
588 13         24 $version =~ tr/././s;
589 13         49 $version =~ s/^[.]|[.]$//g;
590              
591 13         76 return $version;
592             }
593              
594             =for Letters In Versions
595             Letters aren't allowed in versions because makepkg doesn't handle them
596             in dependencies. Example:
597             * CAM::PDF requires Text::PDF 0.29
598             * Text::PDF 0.29a was built/installed
599             * makepkg still complains about perl-text-pdf>=0.29 is missing ... ?
600             So ... no more letters in versions.
601              
602             =cut
603              
604              
605             #-----------------------------------------------------------------------------
606             # PUBLIC METHODS
607             #-----------------------------------------------------------------------------
608              
609              
610             sub set_destdir
611             {
612 0 0   0 1 0 croak 'Invalid arguments to set_destdir' if ( @_ != 2 );
613 0         0 my ($self, $destdir) = @_;
614 0         0 $self->status->destdir($destdir);
615 0         0 return $destdir;
616             }
617              
618             sub get_destdir
619             {
620             return shift->status->destdir
621 0     0 1 0 }
622              
623             sub get_pkgpath
624             {
625 0     0 1 0 shift->status->dist;
626             }
627              
628             sub get_cpandistdir
629             {
630 10     10 1 15 my ($self) = @_;
631              
632 10         61 my $module = $self->parent;
633 10         1127 my $distdir = $module->status->dist_cpan->status->distdir;
634 10         2525 $distdir =~ s{^.*/}{};
635              
636 10         87 return $distdir;
637             }
638              
639             sub get_pkgname
640             {
641 0     0 1 0 return shift->status->pkgname;
642             }
643              
644             sub get_pkgver
645             {
646 0     0 1 0 return shift->status->pkgver;
647             }
648              
649             sub get_pkgrel
650             {
651 0     0 1 0 my ($self) = @_;
652 0         0 return $self->status->pkgrel;
653             }
654              
655             sub set_pkgrel
656             {
657 0     0 1 0 my ($self, $new_pkgrel) = @_;
658 0         0 return $self->status->pkgrel( $new_pkgrel );
659             }
660              
661             #---HELPER FUNCTION---
662             # Converts a specification aref into a pkg specification (i.e. depends).
663             # This can be used as a PKGBUILD field's value.
664             sub _specstr
665             {
666 20     20   28 my ($a) = @_;
667 20         23 my @strs;
668 20         39 for my $x (@$a) {
669 10         35 push @strs, join q{}, @$x;
670             }
671 20         53 return join ' ', map { qq{'$_'} } @strs;
  10         79  
672             }
673              
674             sub get_pkgvars
675             {
676 10 50   10 1 32 croak 'Invalid arguments to get_pkgvars' if ( @_ != 1 );
677              
678 10         15 my $self = shift;
679 10         47 my $status = $self->status;
680              
681 10 50       922 croak 'prepare() must be called before get_pkgvars()'
682             unless ($status->prepared);
683              
684 10         611 my $pkglinks = $self->_get_pkg_rels;
685 10         18 my @shavars;
686              
687 10         65 my %vars = (pkgname => $status->pkgname,
688             pkgver => $status->pkgver,
689             pkgrel => $status->pkgrel,
690             arch => $status->arch,
691             pkgdesc => $status->pkgdesc,
692             url => $self->_get_disturl,
693             source => $self->_get_srcurl,
694             md5sums => $self->_calc_tarballmd5,
695             pkglinks => $pkglinks,
696             );
697 10 50       1560 if (eval { require Digest::SHA }) {
  10         2006  
698 10         12037 $vars{'sha512sums'} = $self->_calc_shasum(512);
699             }
700              
701 10         112 $vars{$_} = _specstr($pkglinks->{$_}) for (qw/depends makedepends/);
702 10         19 for (qw/checkdepends conflicts/) {
703 20 50       24 if (@{$pkglinks->{$_}}) {
  20         70  
704 0         0 $vars{$_} = _specstr($pkglinks->{$_});
705             }
706             }
707            
708 10         108 return %vars;
709             }
710              
711             sub get_pkgvars_ref
712             {
713 0 0   0 1 0 croak 'Invalid arguments to get_pkgvars_ref' if ( @_ != 1 );
714              
715 0         0 my $self = shift;
716 0         0 return { $self->get_pkgvars };
717             }
718              
719             sub set_tt_init_args
720             {
721 0     0 1 0 my $self = shift;
722              
723 0 0       0 croak 'set_tt_init_args() must be given a hash as an argument'
724             unless @_ % 2 == 0;
725              
726 0         0 return $self->status->tt_init_args( { @_ } );
727             }
728              
729             sub set_tt_module
730             {
731 2     2 1 162 my ($self, $modname) = @_;
732              
733 2 100       11 return ( $TT_MOD_NAME = 0 ) unless $modname;
734              
735 1 50       77 croak qq{Failed to load template module "$modname"}
736             unless eval "require $modname; 1;";
737              
738 1         7 _DEBUG "Loaded template module: $modname";
739              
740 1         7 return $TT_MOD_NAME = $modname;
741             }
742              
743             sub get_tt_module
744             {
745 1 50   1 1 163 _load_tt_module() unless defined $TT_MOD_NAME;
746              
747 1         6 return $TT_MOD_NAME;
748             }
749              
750             sub set_pkgbuild_templ
751             {
752 9     9 1 2100 my ($self, $template) = @_;
753              
754 9         54 return $self->status->pkgbuild_templ( $template );
755             }
756              
757             sub get_pkgbuild_templ
758             {
759 2     2 1 165 my ($self) = @_;
760              
761 2   66     10 return $self->status->pkgbuild_templ() || $PKGBUILD_TEMPL;
762             }
763              
764             sub get_pkgbuild
765             {
766 10 50   10 1 183 croak 'Invalid arguments to get_pkgbuild' if ( @_ < 1 );
767 10         19 my ($self) = @_;
768              
769 10         51 my $status = $self->status;
770 10         929 my $module = $self->parent;
771 10         899 my $conf = $module->parent->configure_object;
772              
773 10 50       1402 croak 'prepare() must be called before get_pkgbuild()'
774             unless $status->prepared;
775              
776 10         609 my %pkgvars = $self->get_pkgvars;
777              
778             # Quote our package desc for bash.
779 10         99 $pkgvars{pkgdesc} =~ s/ ([\$\"\`]) /\\$1/gxms;
780              
781 10         78 my $templ_vars = { packager => $PACKAGER,
782             version => $VERSION,
783             %pkgvars,
784             distdir => $self->get_cpandistdir(),
785             };
786              
787 10         58 my $dist_type = $module->status->installer_type;
788 10 50       1325 @{$templ_vars}{'is_makemaker', 'is_modulebuild'} =
  10 50       41  
789             ( $dist_type eq 'CPANPLUS::Dist::MM' ? (1, 0) :
790             $dist_type eq 'CPANPLUS::Dist::Build' ? (0, 1) :
791             die "unknown Perl module installer type: '$dist_type'" );
792              
793 10   66     54 my $templ_text = $status->pkgbuild_templ || $PKGBUILD_TEMPL;
794              
795 10         641 return scalar $self->_process_template( $templ_text, $templ_vars );
796             }
797              
798             sub create_pkgbuild
799             {
800 0 0   0 1 0 croak 'Invalid arguments to create_pkgbuild' if ( @_ < 2 );
801 0         0 my ($self, $destdir) = @_;
802              
803 0 0 0     0 croak qq{Invalid directory passed to create_pkgbuild: "$destdir" ...
804             Directory does not exist or is not writeable}
805             unless ( -d $destdir && -w _ );
806              
807 0         0 my $pkgbuild_text = $self->get_pkgbuild();
808 0         0 my $fqpath = catfile( $destdir, 'PKGBUILD' );
809              
810 0 0       0 open my $pkgbuild_file, '>', $fqpath
811             or die "failed to open new PKGBUILD: $OS_ERROR";
812 0         0 print $pkgbuild_file $pkgbuild_text;
813 0 0       0 close $pkgbuild_file
814             or die "failed to close new PKGBUILD: $OS_ERROR";
815              
816 0         0 return;
817             }
818              
819              
820             #-----------------------------------------------------------------------------
821             # PRIVATE INSTANCE METHODS
822             #-----------------------------------------------------------------------------
823              
824             #---HELPER METHOD---
825             # Caculates where we should store our built package.
826             # (does not take into account our $self->status state or parameters)
827             #
828             # Returns the environment variable we should override as well as the
829             # value we should set it to.
830             sub _calc_setdest
831             {
832 0     0   0 my ($self, $pkg_type) = @_;
833              
834 0 0       0 my $destenv = ( $pkg_type eq 'src' ? 'SRCPKGDEST' : 'PKGDEST' );
835 0   0     0 my $destdir = ( $ENV{ $destenv }
836             || ( $pkg_type eq 'src' ? $SRCPKGDEST : $PKGDEST )
837             || $self->_fallback_destdir );
838              
839 0         0 return ( $destenv, $destdir );
840             }
841              
842             #---HELPER METHOD---
843             # Returns the default base directory that our separate build and
844             # package cache directories append themselves to.
845             # Example: ~/.cpanplus/5.12.1/pacman
846             sub _cpanp_user_basedir
847             {
848 5     5   30 my $conf = shift->parent->parent->configure_object;
849 5         1163 return catdir( $conf->get_conf('base'),
850             ( sprintf '%vd', $PERL_VERSION ),
851             'pacman' );
852             }
853              
854             #---HELPER METHOD---
855             # Returns the default package cache directory when no other directory
856             # is specified by many other means. This directory is inside the
857             # $HOME/.cpanplus directory for each different user.
858             sub _fallback_destdir
859             {
860 0     0   0 catdir( shift->_cpanp_user_basedir, 'pkg' );
861             }
862              
863              
864             #-----------------------------------------------------------------------------
865             # PACKAGE RELATIONSHIP FUNCTIONS
866             #-----------------------------------------------------------------------------
867              
868             #---HELPER FUNCTION--
869             # Merge two version operators, if possible.
870             #--------------------
871             sub _cmpvops
872             {
873 0     0   0 my ($op, $x, $y) = @_;
874 0 0       0 return 0 if ($x eq $y); # specs are identical
875              
876 0         0 ($x, $y) = (version->new($x), version->new($y));
877 0 0       0 if ($op =~ /^
    0          
878 0 0       0 return ($x < $y ? -1 : 1);
879             } elsif ( $op =~ /^>/ ) {
880 0 0       0 return ($x > $y ? -1 : 1);
881             } else {
882             # We cannot merge specs other than <, <=, >, and >=.
883 0         0 return undef;
884             }
885             }
886              
887             #---HELPER FUNCTION---
888             # Perform very simple comparison of version specs.
889             # Returns undef if no merging is possible,
890             # 0 if the specs are equal,
891             # -1 if the first spec is dominant,
892             # or 1 if the second specs is dominant.
893             #
894             # Checks for undefined versions which indicate a dependency on a module
895             # which is not the main module of the distribution. Version specs which define
896             # a version replace other specs with identical names, operators, and no version.
897             #
898             # We use the version module so this only works with perl/CPAN/numerical versions.
899             #---------------------
900             sub _cmpspecs
901             {
902 0     0   0 my ($a, $b) = @_;
903 0         0 my ($x, $y, $z);
904              
905 0 0 0     0 if ($a->[0] ne $b->[0] || $a->[1] ne $b->[1]) {
    0 0        
    0 0        
    0 0        
906             # The most common case is that names won't even match.
907 0         0 return undef;
908             } elsif (defined ($x = $a->[2]) && defined ($y = $b->[2])) {
909 0         0 return _cmpvops($a->[1], $x, $y);
910             } elsif (!defined $x && defined $y) {
911 0         0 return 1;
912             } elsif (defined $x && !defined $y) {
913 0         0 return -1;
914             } else {
915             # Both specs are identical with undef versions.
916 0         0 return 0;
917             }
918             }
919              
920             #---HELPER FUNCTION---
921             # Normalize perl/CPAN version specifications. (we use numeric version cmp)
922             # Each spec is an aref containing a name, operator, and value.
923             # Sorts them and remove redundancies such as specs with the same name
924             # and operator.
925             #---------------------
926             sub _normspecs
927             {
928 80     80   97 my ($a) = @_;
929 80 100       177 return if (@$a == 0);
930              
931 20         68 @$a = sort _vspecs @$a;
932 20         30 my $i = 0;
933 20         25 my $x;
934 20         51 while ($i < $#$a) {
935 0         0 my $x = _cmpspecs($a->[$i], $a->[$i+1]);
936 0 0       0 if (!defined $x) {
    0          
937 0         0 $i++;
938             } elsif ($x <= 0) {
939 0         0 splice @$a, $i+1, 1;
940             } else {
941 0         0 splice @$a, $i, 1;
942             }
943             }
944 20         45 return;
945             }
946              
947             #---SORTING FUNCTION---
948             # Provided for use by the sort builtin, for sorting version specifications.
949             #----------------------
950             sub _vspecs
951             {
952 0     0   0 our ($a, $b);
953 0 0       0 $a->[0] cmp $b->[0] or $a->[1] cmp $b->[1];
954             }
955              
956             sub _yankspecs (&$)
957             {
958 60     60   84 my ($sub, $a) = @_;
959 60         67 my @b;
960 60         121 my $i = 0;
961 60         74 local $_;
962 60         137 while ($i <= $#$a) {
963 30         56 $_ = $a->[$i][0];
964 30 50       54 if ($sub->(@{$a->[$i]})) {
  30         85  
965 0         0 push @b, splice(@$a, $i, 1);
966             } else {
967 30         141 $i++;
968             }
969             }
970 60         161 return @b;
971             }
972              
973             sub _yanktestmods
974             {
975 10     10   40 _yankspecs { /^Test|^Pod::Coverage/ } shift;
  10     10   36  
976             }
977              
978             sub _yankmakemods
979             {
980 10     10   30 _yankspecs { /^ExtUtils-/ } shift;
  10     10   55  
981             }
982              
983             sub _yankcoremods
984             {
985             _yankspecs {
986 10     10   166 my $v = $Module::CoreList::version{0+$]}{$_[0]};
987 10   33     7266 return ($v && (version->new($v) >= version->new($_[2])));
988 40     40   149 } shift;
989             }
990              
991             #---HELPER FUNCTION---
992             # Decide if the module is named after the distribution.
993             #---------------------
994             sub _ismainmod
995             {
996 0     0   0 my ($m, $d) = @_;
997 0         0 $m =~ tr/:/-/s;
998 0         0 return (lc $m) eq (lc $d);
999             }
1000              
1001             #---HELPER FUNCTION---
1002             # Converts specifications upon modules into specifications upon distributions.
1003             #---------------------
1004             sub _distspecs
1005             {
1006 40     40   55 my ($be, $a) = @_;
1007 40         107 for my $i ( 0 .. $#$a ) {
1008 10         22 my $mod = $a->[$i][0];
1009 10 50       38 next if ($mod eq 'perl');
1010              
1011 0         0 my ($x, $y);
1012 0 0 0     0 if (!($x = $be->module_tree($mod)) || !($y = $x->package_name)) {
1013 0         0 die "failed to find a CPAN distribution containing: $mod";
1014             }
1015 0 0       0 if (!_ismainmod($mod, $y)) {
1016 0         0 undef $a->[$i][2];
1017             }
1018 0         0 $a->[$i][0] = $y;
1019             }
1020             }
1021              
1022             #---HELPER FUNCTION---
1023             # Converts specifications upon distributions into specifications upon packages.
1024             #---------------------
1025             sub _pkgspecs
1026             {
1027 40     40   54 my ($a) = @_;
1028 40         88 for my $i (0 .. $#$a) {
1029 10         40 $a->[$i][0] = dist_pkgname($a->[$i][0]);
1030 10         19 my $v = $a->[$i][2];
1031 10 50       43 if (!defined $v) {
    50          
1032 0         0 $v = 0;
1033             } elsif ($a->[$i][0] eq 'perl') {
1034 10         28 $v = _transperlver($v);
1035             } else {
1036 0         0 $v = dist_pkgver($v);
1037             }
1038 10         32 $a->[$i][2] = $v;
1039             }
1040             }
1041              
1042             #---HELPER FUNCTION---
1043             # Converts a decimal perl version (like $]) into the dotted decimal
1044             # form that the official ArchLinux perl package uses.
1045             #---------------------
1046             sub _transperlver
1047             {
1048 18     18   3806 my ($perlver) = @_;
1049              
1050             # Fix perl-style vstrings which have a leading "v".
1051 18 100       64 return $perlver if ($perlver =~ s/\Av//);
1052              
1053 17 100       81 return $perlver unless ($perlver =~ /\A(\d+)[.](\d{3})(\d{1,3})\z/);
1054              
1055             # Re-apply the missing trailing zeroes.
1056 3         8 my $patch = $3;
1057 3         9 $patch .= q{0} x (3 - length($patch));
1058 3         26 return sprintf '%d.%d.%d', $1, $2, $patch;
1059             }
1060              
1061             #---HELPER FUNCTION---
1062             # Translate a single CPAN dependency version specification.
1063             sub _scanvspec
1064             {
1065 0     0   0 my ($vspec) = @_;
1066              
1067             ## The module author forgot to specify a version in the (one) dependency.
1068 0 0       0 return 0 if (!defined $vspec);
1069              
1070             ## The simplest case is a version string.
1071 0 0       0 return $vspec if ($vspec =~ /^[0-9a-zA-Z._-]+$/);
1072              
1073             ## Combinations of complicated version specifications are also possible.
1074 0         0 my @specs;
1075 0         0 for my $opver (split /\s*,\s*/, $vspec) {
1076 0 0       0 if ($opver !~ /^([<>]=?|[!=]=) +([0-9a-zA-Z._-]+)$/) {
1077 0         0 die "invalid META version spec: $vspec"
1078             }
1079 0         0 my ($op, $ver) = ($1, $2);
1080 0         0 push @specs, [ $op, $ver ];
1081             }
1082 0 0       0 if (@specs == 0) {
1083 0         0 return 0;
1084             } else {
1085 0         0 return \@specs;
1086             }
1087             }
1088              
1089             sub _scanvspecs
1090             {
1091 0     0   0 my ($specs, $deps, $cons) = @_;
1092 0         0 while (my ($k, $v) = each %$specs) {
1093 0         0 my $vs = _scanvspec($v); # $vs is either a version string or an array-ref.
1094 0 0       0 unless (ref $vs) {
1095 0         0 push @$deps, [ $k, '>=', $vs ];
1096 0         0 next;
1097             }
1098 0         0 for my $x (@$vs) {
1099 0         0 my ($op, $ver) = @$x;
1100 0 0       0 if ($op eq '!=') {
1101             ## When $cons is elided, that means we are scanning conflict version specs.
1102             ## The '!=' spec specifies a conflict. What is a conflict of a conflict?
1103 0 0       0 unless (defined $cons) {
1104 0         0 die qq{unable to process "$k != $ver" in a conficts list};
1105             }
1106 0         0 push @$cons, [ $k, '=', $ver ];
1107             } else {
1108 0         0 push @$deps, [ $k, $op, $ver ];
1109             }
1110             }
1111             }
1112 0         0 return;
1113             }
1114              
1115             #---HELPER FUNCTION---
1116             sub _scanstage
1117             {
1118 0     0   0 my ($s, $r, $c) = @_;
1119 0         0 _scanvspecs($s->{'requires'}, $r, $c);
1120 0         0 _scanvspecs($s->{'conflicts'}, $c, undef);
1121             }
1122              
1123             #---HELPER FUNCTION---
1124             # Clean up deps for the sake of humans.
1125             #---------------------
1126             sub _pruneperldep
1127             {
1128 30     30   41 my ($d) = @_;
1129 30 50       81 if ((grep { $_->[0] =~ /^perl/ } @$d) > 1) {
  10         76  
1130             # Remove a redundant dependency on perl itself if a perl- package is
1131             # depended on.
1132 0 0       0 @$d = grep { $_->[0] ne 'perl' || $_->[2] } @$d;
  0         0  
1133             }
1134             }
1135              
1136             #---HELPER FUNCTION---
1137             # Remove duplicate dependencies. If a package verspec is in depends, then the identical
1138             # verspec does not need to be in makedepends or checkdepends.
1139             #
1140             # Given A and B, remove any duplicates from the array B.
1141             #---------------------
1142             sub _prunedups
1143             {
1144 20     20   26 my ($a, $b) = @_;
1145 20         33 for my $x (@$a) {
1146 20         23 my $i = 0;
1147 20         72 while ($i <= $#$b) {
1148             # remember that _cmpspecs may be undef
1149 0 0       0 if (eval { _cmpspecs($x, $b->[$i]) == 0 }) {
  0         0  
1150 0         0 splice @$b, $i, 1;
1151             } else {
1152 0         0 $i++;
1153             }
1154             }
1155             }
1156 20         45 return;
1157             }
1158              
1159             #---PRIVATE METHOD---
1160             # Purpose : Converts our CPAN requirements and conflicts into PKGBUILD
1161             # checkdepends, makedepends, depends, and conflicts
1162             # Returns : A hashref of package relations.
1163             # Top level keys are 'makedepends', 'depends', and 'conflicts'.
1164             # The values of these keys are arrayrefs. Every three elements
1165             # specify a package name, operator (e.g. <=, =, etc) and version.
1166             #---------------------
1167             sub _get_pkg_rels
1168             {
1169 10 50   10   72 croak 'Invalid arguments to _get_pkg_rels method' if (@_ != 1);
1170 10         21 my ($self) = @_;
1171              
1172 10         46 my $module = $self->parent;
1173 10         869 my (@deps, @mkdeps, @chdeps, @cons);
1174 10 50       47 if (defined $self->status->metareqs) {
1175 0         0 my $r = $self->status->metareqs;
1176 0         0 _scanstage($r->{'configure'}, \@mkdeps, \@cons);
1177 0         0 _scanstage($r->{'build'}, \@mkdeps, \@cons);
1178 0         0 _scanstage($r->{'test'}, \@chdeps, \@cons);
1179 0         0 _scanstage($r->{'runtime'}, \@deps, \@cons);
1180             } else {
1181 10         1586 my $reqs = $module->status->prereqs;
1182 10         1339 while (my ($k, $v) = each %$reqs) {
1183 10         92 push @deps, [ $k, '>=', $v ];
1184             }
1185 10         48 my $d = $module->package_name;
1186 10 50       711 unless ($d =~ /^ExtUtils-/) {
1187 10         30 @mkdeps = _yankmakemods(\@deps);
1188             }
1189 10 50       46 unless ($d =~ /^Test-/) {
1190 10         29 @chdeps = _yanktestmods(\@deps);
1191             }
1192             }
1193            
1194 10         68 my $be = $module->parent; # $module->parent is a CPANPLUS::Backend
1195 10         724 for my $a (\@deps, \@mkdeps, \@chdeps, \@cons) {
1196 40         82 _yankcoremods($a);
1197 40         158 _normspecs($a);
1198 40         98 _distspecs($be, $a); # specs are now on dist. names
1199 40         71 _normspecs($a);
1200 40         72 _pkgspecs($a); # specs are now on package names
1201             }
1202              
1203             # Merge in the XS package deps if they exist.
1204 10         42 my $xsdeps = $self->_transxsdeps();
1205 10 50       25 if (@$xsdeps) {
1206 0         0 push @deps, @$xsdeps;
1207 0         0 @deps = sort _vspecs @deps;
1208             }
1209              
1210 10         41 _pruneperldep($_) for (\@deps, \@mkdeps, \@chdeps);
1211 10 50       20 if (!grep { $_->[0] =~ /^perl/ } @deps) {
  10         50  
1212             # Require perl unless we have a dependency on a module or perl itself.
1213 0         0 unshift @deps, [ 'perl', '>=', '0' ];
1214             }
1215 10         37 _prunedups(\@deps, $_) for (\@mkdeps, \@chdeps);
1216             return {
1217 10         62 'depends' => \@deps,
1218             'makedepends' => \@mkdeps,
1219             'checkdepends' => \@chdeps,
1220             'conflicts' => \@cons,
1221             };
1222             }
1223              
1224              
1225             #-----------------------------------------------------------------------------
1226             # XS module library dependency hunting
1227             #-----------------------------------------------------------------------------
1228              
1229             #---INSTANCE METHOD---
1230             # Purpose : Attempts to find non-perl dependencies in XS modules.
1231             # Returns : A hashref of 'package name' => 'minimum version'.
1232             # (Minimum version will be the current installed version
1233             # of the library)
1234             #---------------------
1235             sub _transxsdeps
1236             {
1237 10     10   17 my $self = shift;
1238              
1239 10         58 my $modstat = $self->parent->status;
1240 10         1793 my $inst_type = $modstat->installer_type;
1241 10         694 my $distcpan = $modstat->dist_cpan;
1242              
1243             # Delegate to the other methods depending on the dist type...
1244 10 50       691 my $libs_ref = ( $inst_type eq 'CPANPLUS::Dist::MM'
1245             ? $self->_get_mm_xs_deps($distcpan) : [] );
1246             # TODO: figure out how to do this with Module::Build
1247              
1248             # Turn the linker flags into package deps...
1249             return [ map {
1250 10         28 my ($pkg, $ver) = $self->_get_lib_pkg($_);
  0         0  
1251 0         0 [ $pkg, '>=', $ver ]
1252             } @$libs_ref ];
1253             }
1254              
1255             #---INSTANCE METHOD---
1256             # Usage : %pkg = $self->_get_lib_pkg($lib)
1257             # Params : $lib - Can be a dynamic library name, with/without lib prefix
1258             # or the -l flag that is passed to the linker.
1259             # (anything DynaLoader::dl_findfile accepts)
1260             # Returns : A hash (or two element list) of:
1261             # 'package name' => 'installed version'
1262             # or an empty list if the lib/package owner could not be found.
1263             #---------------------
1264             sub _get_lib_pkg
1265             {
1266 0     0   0 my ($self, $libname) = @_;
1267              
1268 0 0       0 my $lib_fqp = DynaLoader::dl_findfile($libname)
1269             or return ();
1270              
1271 0         0 $lib_fqp =~ s/([\\\$"`])/\\$1/g;
1272 0         0 my $result = `LC_ALL=C pacman -Qo "$lib_fqp"`;
1273 0         0 chomp $result;
1274 0 0 0     0 if ( $CHILD_ERROR != 0 || !($result =~ s/$PACMAN_FINDOWN//) ) {
1275 0 0       0 if ( $CHILD_ERROR == 127 ) {
1276 0         0 error q{C-library dep lookup failed. Pacman is missing!?};
1277             }
1278             else {
1279 0         0 error qq{Could not find owner of linked library }
1280             . qq{"$libname", ignoring.};
1281             }
1282 0         0 return ();
1283             }
1284              
1285 0         0 my ($pkgname, $pkgver) = split / /, $result;
1286 0         0 $pkgver =~ s/-\d+\z//; # remove the package revision number
1287 0         0 return ($pkgname, $pkgver);
1288             }
1289              
1290             sub _unique(@)
1291             {
1292 0     0   0 my %seen;
1293 0 0       0 return map { $seen{$_}++ ? () : $_ } @_;
  0         0  
1294             }
1295              
1296             #---INSTANCE METHOD---
1297             # Usage : my $deps_ref = $self->_get_mm_xs_deps($dist_obj);
1298             # Params : $dist_obj - A CPANPLUS::Dist::MM object
1299             # Returns : Arrayref of library flags (-l...) passed to the linker on build.
1300             #---------------------
1301             sub _get_mm_xs_deps
1302             {
1303 0     0   0 my ($self, $dist) = @_;
1304              
1305 0         0 my $field_srch = '\A(?:EXTRALIBS|LDLOADLIBS|BSLOADLIBS) = (.+)\z';
1306              
1307 0 0       0 my $mkfile_fqp = $dist->status->makefile
1308             or die "Internal error: makefile() path is unset in our object";
1309              
1310 0 0       0 open my $mkfile, '<', $mkfile_fqp
1311             or die "Internal error: failed to open Makefile at $mkfile_fqp ... $!";
1312 0         0 my @libs = _unique map { chomp; (/$field_srch/o) } <$mkfile>;
  0         0  
  0         0  
1313 0         0 close $mkfile;
1314              
1315 0         0 return [ grep { /\A-l/ } map { split } @libs ];
  0         0  
  0         0  
1316             }
1317              
1318             #---HELPER FUNCTION---
1319             sub _find_xs_files
1320             {
1321 0     0   0 my ($dirpath) = @_;
1322 0   0     0 return -f "$dirpath/typemap" || scalar glob "$dirpath/*.xs";
1323             }
1324              
1325              
1326             #-----------------------------------------------------------------------------
1327             # CPAN Distribution Scraping
1328             #-----------------------------------------------------------------------------
1329              
1330              
1331             #---HELPER FUNCTION---
1332             sub _pod_pkgdesc
1333             {
1334 0     0   0 my ($mod_obj) = @_;
1335 0         0 my $podselect = Pod::Select->new;
1336 0         0 my $modname = $mod_obj->name;
1337 0         0 $podselect->select('NAME');
1338              
1339             =for POD Search
1340             We use the package name because there is usually a module file
1341             with the exact same name as the package file.
1342            
1343             We want the main module's description, just in case the user requested
1344             a lesser module in the same package file.
1345            
1346             Assume the main .pm or .pod file is under lib/Module/Name/Here.pm
1347              
1348             =cut
1349              
1350 0         0 my $mainmod_path = $mod_obj->package_name;
1351 0         0 $mainmod_path =~ tr{-}{/}s;
1352              
1353 0         0 my $mainmod_file = $mainmod_path;
1354 0         0 $mainmod_file =~ s{\A.*/}{};
1355 0         0 $mainmod_path =~ s{/$mainmod_file}{};
1356              
1357 0         0 my $base_path = $mod_obj->status->extract;
1358              
1359             # First check under lib/ for a "properly" pathed module, with
1360             # nested directories. Then search desperately for a .pm file that
1361             # matches the module's last name component.
1362              
1363 0         0 my @possible_pods = ( glob "$base_path/{lib/,}{$mainmod_path/,}"
1364             . "$mainmod_file.{pod,pm}" );
1365              
1366             PODSEARCH:
1367 0         0 for my $podfile_path ( @possible_pods ) {
1368 0 0       0 next PODSEARCH unless ( -e $podfile_path );
1369              
1370 0         0 _DEBUG "Searching the POD inside $podfile_path for pkgdesc...";
1371              
1372 0         0 my $name_section = q{};
1373              
1374 0 0       0 open my $podfile, '<', $podfile_path
1375             or next PODSEARCH;
1376              
1377 0 0       0 open my $podout, '>', \$name_section
1378             or die "failed open on filehandle to string: $!";
1379 0         0 $podselect->parse_from_filehandle( $podfile, $podout );
1380              
1381 0         0 close $podfile;
1382 0 0       0 close $podout or die "failed close on filehandle to string: $!";
1383              
1384 0 0       0 next PODSEARCH unless ( $name_section );
1385              
1386             # Remove formatting codes.
1387 0         0 $name_section =~ s{ [IBCLEFSXZ] <(.*?)> }{$1}gxms;
1388 0         0 $name_section =~ s{ [IBCLEFSXZ] <<(.*?)>> }{$1}gxms;
1389              
1390             # The short desc is on a line beginning with 'Module::Name - '
1391 0 0       0 if ( $name_section =~ / ^ \s* $modname [ -]+ ([^\n]+) /xms ) {
1392 0         0 _DEBUG qq{Found pkgdesc "$1" in POD};
1393 0         0 return $1;
1394             }
1395             }
1396              
1397 0         0 return undef;
1398             }
1399              
1400             #---HELPER FUNCTION---
1401             sub _readme_pkgdesc
1402             {
1403 0     0   0 my ($mod_obj) = @_;
1404 0         0 my $mod_name = $mod_obj->name;
1405              
1406 0 0       0 open my $readme, '<', catfile( $mod_obj->status->extract, 'README' )
1407             or return undef;
1408              
1409             LINE:
1410 0         0 while ( <$readme> ) {
1411 0         0 chomp;
1412              
1413             # limit ourselves to a NAME section
1414 0 0 0     0 next LINE unless ( ( /^NAME/ ... /^[A-Z]+/ ) &&
1415             / ^ \s* ${mod_name} [\s\-]+ (.+) $ /oxms );
1416            
1417 0         0 _DEBUG qq{Found pkgdesc "$1" in README};
1418 0         0 return $1;
1419             }
1420              
1421 0         0 return undef;
1422             }
1423              
1424             #---PRIVATE METHOD---
1425             # Try to find out if this distribution has any XS files.
1426             # If it does, then the arch PKGBUILD field should be ('i686', 'x86_64').
1427             # If it doesn't, then the arch field should be ('any').
1428             sub _prepare_arch
1429             {
1430 5     5   11 my ($self) = @_;
1431              
1432 5         31 my $dist_cpan = $self->parent->status->dist_cpan;
1433 5         1044 my $dist_dir = $dist_cpan->status->distdir;
1434              
1435 5 50 33     768 unless ( $dist_dir && -d $dist_dir ) {
1436 5         40 return $self->status->arch( q{'any'} );
1437             }
1438              
1439             # Only search the top distribution directory and then go
1440             # one directory-level deep. .xs files are usually at the top
1441             # or in a subdir. Don't use File::Find, that could be really slow.
1442              
1443 0         0 my $found_xs;
1444 0 0       0 if ( _find_xs_files( $dist_dir )) {
1445 0         0 $found_xs = 1;
1446             }
1447             else {
1448 0 0       0 opendir my $basedir, $dist_dir or die "opendir: $!";
1449 0 0       0 my @childdirs = grep { !/^./ && -d $_ } readdir $basedir;
  0         0  
1450              
1451             DIR_LOOP:
1452 0         0 for my $childdir ( @childdirs ) {
1453 0 0       0 next DIR_LOOP unless _find_xs_files( $childdir );
1454 0         0 $found_xs = 1;
1455 0         0 last DIR_LOOP;
1456             }
1457              
1458 0         0 closedir $basedir;
1459             }
1460              
1461 0 0       0 return $self->status->arch( $found_xs
1462             ? q{'i686' 'x86_64'} : q{'any'} );
1463             }
1464              
1465             #---INSTANCE METHOD---
1466             # Usage : $pkgdesc = $self->_prepare_pkgdesc();
1467             # Purpose : Tries to find a module's "abstract" short description for
1468             # use as a package description.
1469             # Postcond : Sets the $self->status->pkgdesc accessor to the found
1470             # package description.
1471             # Returns : The package short description.
1472             # Comments : We search through the META.yml file, the main module's .pm file,
1473             # .pod file, and then the README file.
1474             #---------------------
1475             sub _prepare_pkgdesc
1476             {
1477 5 50   5   331 croak 'Invalid arguments to _prepare_pkgdesc method' if @_ != 1;
1478              
1479 5         11 my ($self) = @_;
1480 5         31 my ($status, $module, $pkgdesc) = ($self->status, $self->parent);
1481              
1482             my @pkgdesc_srcs =
1483             (
1484             # 1. We checked the META.yml earlier in the _scanmeta method.
1485              
1486             # 2. Registered modules have their description stored in the object.
1487 5     5   36 sub { $module->description },
1488              
1489             # 3. Parse the source file or pod file for a NAME section.
1490 5         917 \&_pod_pkgdesc,
1491              
1492             # 4. Try to find it in in the README file.
1493             \&_readme_pkgdesc,
1494              
1495             );
1496              
1497             PKGDESC_LOOP:
1498 5         15 for my $pkgdesc_src ( @pkgdesc_srcs ) {
1499 5 50       26 $pkgdesc = $pkgdesc_src->( $module ) and last PKGDESC_LOOP;
1500             }
1501              
1502 5 50       421 if ( $pkgdesc ) {
1503             # Avoid CR chars because of CRLF line endings in sources.
1504 5         17 $pkgdesc =~ tr/\r//d;
1505             } else {
1506 0         0 $pkgdesc = q{};
1507             }
1508 5         31 $status->pkgdesc( $pkgdesc );
1509 5         337 return;
1510             }
1511              
1512             #----------------------------
1513             # META Spec File Functions
1514             #----------------------------
1515              
1516             sub _metapath
1517             {
1518 5     5   14 my ($mod) = @_;
1519 5         14 my $metapath;
1520 5         12 for my $ext (qw/json yml/) {
1521 10         63 my $p = catfile($mod->status->extract, "META.$ext");
1522 10 50       1404 if (-f $p) {
1523 0         0 $metapath = $p;
1524 0         0 last;
1525             }
1526             }
1527 5         29 return $metapath;
1528             }
1529              
1530             # Smooth over differences between incompatible META specs.
1531             sub _metareqs
1532             {
1533 0     0   0 my ($meta) = @_;
1534 0         0 my $r;
1535 0 0 0     0 if (defined $meta->{'meta-spec'} &&
1536             $meta->{'meta-spec'}{'url'} =~ /cpan[.]org/) {
1537 0         0 $r = $meta->{'prereqs'};
1538             } else {
1539 0         0 for (qw/configure build/) {
1540 0         0 $r->{$_}{'requires'} = $meta->{"${_}_requires"};
1541             }
1542 0         0 $r->{'runtime'}{'requires'} = $meta->{'requires'};
1543 0         0 $r->{'build'}{'conflicts'} = $meta->{'conflicts'};
1544            
1545             # When upgrading, try to detect testing requirements.
1546 0 0       0 if ($meta->{'name'} !~ /^Test-/) {
1547 0         0 for my $m (keys %{$r->{'build'}{'requires'}}) {
  0         0  
1548 0 0       0 if ($m =~ /^Test::/) {
1549 0         0 $r->{'test'}{'requires'}{$m} = delete $r->{'build'}{'requires'}{$m};
1550             }
1551             }
1552             }
1553             }
1554 0         0 return $r;
1555             }
1556              
1557             sub _metadesc
1558             {
1559 0     0   0 my ($meta) = @_;
1560 0 0       0 my $d = $meta->{'abstract'} or return undef;
1561              
1562             # META.yml abstract entries we should ignore.
1563 0         0 my @bad = ( q{~}, 'Module abstract (<= 44 characters) goes here' );
1564 0         0 for my $b ( @bad ) {
1565 0 0       0 return if ( $d eq $b );
1566             }
1567 0         0 return $d;
1568            
1569             }
1570              
1571             #--- PRIVATE METHOD ---
1572             # We read the META.json or META.yml file with Parse::CPAN::META and extract
1573             # data needed for makedepends and pkgdesc if we can.
1574             #----------------------
1575             sub _scanmeta
1576             {
1577 5     5   13 my ($self) = @_;
1578 5         30 my ($status, $modobj) = ($self->status, $self->parent);
1579              
1580             # Leave metareqs undef if there is no META.yml/META.json.
1581 5 50       891 my $path = _metapath($modobj) or return;
1582 0         0 my $meta = eval { Parse::CPAN::Meta::LoadFile($path) };
  0         0  
1583 0 0       0 return unless ($meta);
1584              
1585 0         0 my $reqs = _metareqs($meta);
1586 0         0 my $desc = _metadesc($meta);
1587 0         0 $status->metareqs($reqs);
1588 0         0 $status->pkgdesc($desc);
1589 0         0 return;
1590             }
1591              
1592             #---INSTANCE METHOD---
1593             # Usage : $self->_prepare_status()
1594             # Purpose : Prepares all the package-specific accessors in our $self->status
1595             # accessor object (of the class Object::Accessor).
1596             # Postcond : Accessors assigned to: pkgname pkgver pkgbase arch destdir
1597             # Returns : The object's status accessor.
1598             #---------------------
1599             sub _prepare_status
1600             {
1601 5 50   5   92 croak 'Invalid arguments to _prepare_status method' if @_ != 1;
1602              
1603 5         11 my $self = shift;
1604 5         44 my $status = $self->status; # Private hash
1605 5         515 my $module = $self->parent; # CPANPLUS::Module
1606 5         434 my $conf = $module->parent->configure_object;
1607              
1608 5         691 my ($pkgver, $pkgname)
1609             = ( dist_pkgver( $module->package_version ),
1610             dist_pkgname( $module->package_name));
1611              
1612 5         49 my $pkgbase = catdir( $self->_cpanp_user_basedir,
1613             'build', "$pkgname-$pkgver" );
1614              
1615 5         1040 foreach ( $pkgname, $pkgver, $pkgbase ) {
1616 15 50       44 die "A package variable is invalid" unless defined;
1617             }
1618              
1619 5         41 $status->pkgname( $pkgname );
1620 5         335 $status->pkgver ( $pkgver );
1621 5         371 $status->pkgbase( $pkgbase );
1622 5         322 $status->pkgrel ( 1 );
1623              
1624 5         326 $status->tt_init_args( {} );
1625              
1626 5         386 $self->_prepare_arch();
1627 5         835 $self->_scanmeta();
1628              
1629             # _scanmeta() might find a pkgdesc for us
1630 5 50       37 $self->_prepare_pkgdesc() unless $status->pkgdesc();
1631              
1632 5         16 return $status;
1633             }
1634              
1635             #---INSTANCE METHOD---
1636             # Usage : my $pkgurl = $self->_get_disturl()
1637             # Purpose : Creates a nice, version agnostic homepage URL for the
1638             # distribution.
1639             # Returns : URL to the distribution's web page on CPAN.
1640             #---------------------
1641             sub _get_disturl
1642             {
1643 10 50   10   2947 croak 'Invalid arguments to _get_disturl method' if @_ != 1;
1644 10         23 my $self = shift;
1645 10         54 my $dist = $self->parent->package_name;
1646 10         1601 return "https://metacpan.org/release/$dist";
1647             }
1648              
1649             #---INSTANCE METHOD---
1650             # Usage : my $srcurl = $self->_get_srcurl()
1651             # Purpose : Generates the standard cpan download link for the source tarball.
1652             # Returns : URL to the distribution's tarball on CPAN.
1653             #---------------------
1654             sub _get_srcurl
1655             {
1656 10 50   10   30 croak 'Invalid arguments to _get_srcurl method' if @_ != 1;
1657 10         18 my ($self) = @_;
1658 10         45 my $module = $self->parent;
1659              
1660 10         926 return join '/', $CPANURL, 'CPAN', $module->path, $module->package;
1661             }
1662              
1663             #---INSTANCE METHOD---
1664             # Usage : my $md5hex = $self->calc_tarballmd5()
1665             # Purpose : Returns the hex md5 string for the source (dist) tarball
1666             # of the module.
1667             # Throws : failed to get md5 of : ...
1668             # Returns : The MD5 sum of the .tar.gz file in hex string form.
1669             #---------------------
1670             sub _calc_tarballmd5
1671             {
1672 0     0   0 my ($self) = @_;
1673 0         0 my $module = $self->parent;
1674              
1675 0         0 my $tarball_fqp = $module->_status->fetch;
1676 0 0       0 open my $distfile, '<', $tarball_fqp
1677             or die "failed to get md5 of $tarball_fqp: $OS_ERROR";
1678 0         0 binmode $distfile;
1679              
1680 0         0 my $md5 = Digest::MD5->new;
1681 0         0 $md5->addfile($distfile);
1682 0         0 close $distfile;
1683              
1684 0         0 return $md5->hexdigest;
1685             }
1686              
1687             #---INSTANCE METHOD---
1688             # Usage : my $shasum = $self->calc_shasum(512);
1689             # Params : The bitsizes to use for the SHA digest calculated.
1690             # Throws : failed to get shasum of :\n...
1691             # Returns : Hex-string checksum of the tarball for the bit size
1692             # provided as a parameter.
1693             #---------------------
1694             sub _calc_shasum
1695             {
1696 0     0   0 my ($self, $size) = @_;
1697 0         0 my $module = $self->parent;
1698 0         0 my $fqp = $module->_status->fetch;
1699 0         0 my $sum = eval {
1700 0         0 Digest::SHA->new( $size )->addfile( $fqp, q{b} )->hexdigest;
1701             };
1702 0 0       0 return $sum if $sum;
1703 0         0 die "failed to get sha${size}sum of $fqp:\n$EVAL_ERROR";
1704             }
1705              
1706              
1707             #---HELPER FUNCTION---
1708             # Purpose : Split the text into everything before the tags, inside tags, and
1709             # after the tags. Inner nested tags are skipped.
1710             #---------------------
1711             sub _extract_nested
1712             {
1713 4 50   4   10 croak 'Invalid arguments to _extract_nested' unless ( @_ == 3 );
1714              
1715 4         7 my ($text, $begin_match, $end_match) = @_;
1716              
1717 4         4 my ($before_end, $middle_start, $middle_end, $after_start);
1718 4 50       23 croak qq{could not find beginning match "$begin_match"}
1719             unless ( $text =~ /$begin_match/ );
1720              
1721 4         13 $before_end = $LAST_MATCH_START[0];
1722 4         9 $middle_start = $LAST_MATCH_END [0];
1723              
1724 4         6 my $search_pos = $middle_start;
1725              
1726             END_SEARCH:
1727             {
1728 4         4 pos $text = $search_pos;
  4         17  
1729 4 50       34 croak sprintf <<'END_ERR', substr $text, $search_pos, 30
1730             could not find ending match starting at:
1731             %s...
1732             END_ERR
1733             unless ( $text =~ /$end_match/go );
1734              
1735 4         8 $middle_end = $LAST_MATCH_START[0];
1736 4         9 $after_start = $LAST_MATCH_END[0];
1737              
1738 4         8 pos $text = $search_pos;
1739 4 50 33     14 if ( $text =~ /$begin_match/go && pos($text) < $after_start ) {
1740 0         0 $search_pos = $after_start;
1741 0         0 redo END_SEARCH;
1742             }
1743             }
1744              
1745 4         8 my $before = substr $text, 0, $before_end;
1746 4         9 my $middle = substr $text, $middle_start, $middle_end-$middle_start;
1747 4         6 my $after = substr $text, $after_start;
1748              
1749 4         17 return ($before, $middle, $after);
1750             }
1751              
1752             #---HELPER FUNCTION---
1753             # Purpose : Removes IF blocks whose variables are not true.
1754             # Params : $templ - The template as a string.
1755             # $templ_vars - A hashref to template variables.
1756             #---------------------
1757             sub _prune_if_blocks
1758             {
1759 9     9   16 my ($templ, $templ_vars) = @_;
1760              
1761 9         73 while (my ($varname) = $templ =~ $TT_IF_MATCH) {
1762 4 50       9 croak "Invalid template given.\n"
1763             . 'Must provide a variable name in an IF block' unless $varname;
1764              
1765 4         10 my @chunks = _extract_nested($templ, $TT_IF_MATCH, $TT_END_MATCH);
1766 4 100       12 unless ($templ_vars->{$varname}) { splice @chunks, 1, 1; }
  1         2  
1767 4         49 $templ = join q{}, @chunks;
1768             }
1769              
1770 9         20 return $templ;
1771             }
1772              
1773             #---HELPER FUNCTION---
1774             # Purpose : Load a template module and store its name for later use.
1775             # Postcond : Stores the template name into $TT_MOD_NAME.
1776             # Returns : Nothing.
1777             #---------------------
1778             sub _load_tt_module
1779             {
1780 1     1   6 _DEBUG "Searching for template modules...";
1781             TT_SEARCH:
1782 1         2 for my $ttmod ( @TT_MOD_SEARCH ) {
1783 3 50       854 eval "require $ttmod; 1;" or next TT_SEARCH;
1784 0         0 _DEBUG "Loaded template module: $ttmod";
1785 0         0 $TT_MOD_NAME = $ttmod;
1786 0         0 return;
1787             }
1788              
1789 1         168 _DEBUG "None found!";
1790 1         2 $TT_MOD_NAME = 0;
1791 1         2 return;
1792             }
1793              
1794             #---HELPER METHOD---
1795             # Purpose : Create our template module object and process our template text.
1796             # Params : $templ - A string of template text.
1797             # $templ_vars - A hashref of template variable names and their
1798             # values.
1799             # Returns : The template module's processed text.
1800             #-------------------
1801             sub _tt_process
1802             {
1803 1     1   2 my ($self, $templ, $templ_vars) = @_;
1804              
1805 1 50       4 confess 'Internal Error: $TT_MOD_NAME not set' unless $TT_MOD_NAME;
1806              
1807 1         5 _DEBUG "Processing template using $TT_MOD_NAME";
1808              
1809 1         1 my ($tt_obj, $tt_output, $tt_init_args);
1810 1         6 $tt_init_args = $self->status->tt_init_args();
1811 1         189 $tt_output = q{};
1812 1 50       13 $tt_obj = $TT_MOD_NAME->new( $TT_MOD_NAME eq 'Template'
1813             ? $tt_init_args : %$tt_init_args );
1814             # TT takes a hashref, others take the hash
1815              
1816 1         11 $tt_obj->process( \$templ, $templ_vars, \$tt_output );
1817              
1818             croak "$TT_MOD_NAME failed to process PKGBUILD template:\n"
1819 1 50       49 . $tt_obj->error if ( eval { $tt_obj->error } );
  1         31  
1820              
1821 1         39 return $tt_output;
1822             }
1823              
1824             #---INSTANCE METHOD---
1825             # Usage : $self->_process_template( $templ, $templ_vars );
1826             # Purpose : Process template text with a template module or our builtin
1827             # template code.
1828             # Params : templ - A string containing the template text.
1829             # templ_vars - A hashref of template variables that you can
1830             # refer to in the template to insert the
1831             # variable's value.
1832             # Throws : 'Template variable %s was not provided' is thrown if a template
1833             # variable is used in $templ but not provided in $templ_vars,
1834             # OR IF IT IS UNDEF!
1835             # Returns : String of the template result.
1836             #---------------------
1837             sub _process_template
1838             {
1839 10 50   10   30 croak "Invalid arguments to _process_template" if @_ != 3;
1840 10         20 my ($self, $templ, $templ_vars) = @_;
1841              
1842 10 50       33 croak 'templ_var parameter must be a hashref'
1843             if ( ref $templ_vars ne 'HASH' );
1844              
1845             # Try to find a TT module if this is our first time called...
1846 10 50       24 _load_tt_module() unless defined $TT_MOD_NAME;
1847              
1848             # Use the TT module if we have found one earlier...
1849 10 100       29 return $self->_tt_process( $templ, $templ_vars ) if $TT_MOD_NAME;
1850              
1851 9         23 _DEBUG "Processing PKGBUILD template with built-in code...";
1852              
1853             # Fall back on our own primitive little template engine...
1854 9         25 $templ = _prune_if_blocks( $templ, $templ_vars );
1855 9         125 $templ =~ s{ $TT_VAR_MATCH }
1856 6 100       44 { (defined $templ_vars->{$1} ? $templ_vars->{$1} : "") }xmseg;
1857              
1858 9         112 return $templ;
1859             }
1860              
1861             1; # End of CPANPLUS::Dist::Arch
1862