our
@ISA
=
qw(CPANPLUS::Dist::Base Exporter)
;
use
Carp
qw(carp croak confess)
;
our
$VERSION
=
'1.08'
;
our
@EXPORT
=
qw()
;
our
@EXPORT_OK
=
qw(dist_pkgname dist_pkgver)
;
our
%EXPORT_TAGS
= (
'all'
=> [
@EXPORT_OK
] );
my
$MKPKGCONF_FQP
=
'/etc/makepkg.conf'
;
my
$ROOT_USER_ID
= 0;
my
$CFG_VALUE_MATCH
=
'\A \s* (%s) \s* = \s* (.*?) \s* (?: \#.* )? \z'
;
my
$NONROOT_WARNING
=
<<'END_MSG';
In order to install packages as a non-root user (highly recommended)
you must have a sudo-like command specified in your CPANPLUS
configuration.
END_MSG
my
@BAD_METAYML_ABSTRACTS
= (
q{~}
,
'Module abstract (<= 44 characters) goes here'
);
my
$PACMAN_FINDOWN
=
qr/\A[^ ]+ is owned by ([\w-]+) ([\w.-]+)/
;
my
$PACMAN_FINDOWN_ERR
=
qr/\Aerror:/
;
my
$PKGNAME_OVERRIDES
=
{
map
{
split
/[\s=]+/ }
split
/\s*\n+\s*/,
<<'END_OVERRIDES' };
libwww-perl = perl-libwww
aceperl = perl-ace
mod_perl = mod_perl
glade-perl-two = perl-glade-two
Gnome2-GConf = gconf-perl
Gtk2-GladeXML = glade-perl
Glib = glib-perl
Gnome2 = gnome-perl
Gnome2-VFS = gnome-vfs-perl
Gnome2-Canvas = gnomecanvas-perl
Gnome2-GConf = gconf-perl
Gtk2 = gtk2-perl
Cairo = cairo-perl
Pango = pango-perl
SDL_Perl = sdl_perl
Perl-Critic = perl-critic
Perl-Tidy = perl-tidy
App-Ack = ack
TermReadKey = perl-term-readkey
END_OVERRIDES
my
$TT_MOD_NAME
;
my
@TT_MOD_SEARCH
=
qw/ Template Template::Alloy Template::Tiny /
;
sub
_tt_block
{
my
$inside
=
shift
;
return
qr{ \[% -?
\s* $inside \s*
(?: (?: -%\] \n* ) | %\] ) }
xms;
}
my
$TT_IF_MATCH
= _tt_block
'IF \s* (\w*)'
;
my
$TT_END_MATCH
= _tt_block
'END'
;
my
$TT_VAR_MATCH
= _tt_block
'(\w+)'
;
my
$PKGBUILD_TEMPL
=
<<'END_TEMPL';
# Contributor: [% packager %]
# Generator : CPANPLUS::Dist::Arch [% version %]
pkgname='[% pkgname %]'
pkgver='[% pkgver %]'
pkgrel='[% pkgrel %]'
pkgdesc="[% pkgdesc %]"
arch=([% arch %])
license=('PerlArtistic' 'GPL')
options=('!emptydirs')
depends=([% depends %])
makedepends=([% makedepends %])
url='[% url %]'
source=('[% source %]')
md5sums=('[% md5sums %]')
build() {
PERL=/usr/bin/perl
DIST_DIR="${srcdir}/[% distdir %]"
export PERL_MM_USE_DEFAULT=1 PERL5LIB="" \
PERL_AUTOINSTALL=--skipdeps \
PERL_MM_OPT="INSTALLDIRS=vendor DESTDIR='$pkgdir'" \
PERL_MB_OPT="--installdirs vendor --destdir '$pkgdir'" \
MODULEBUILDRC=/dev/null
{ cd "$DIST_DIR" &&
[% IF is_makemaker -%]
$PERL Makefile.PL &&
make &&
[% IF skiptest %]#[% END %]make test &&
make install;
[% END -%]
[% IF is_modulebuild -%]
$PERL Build.PL &&
$PERL Build &&
[% IF skiptest %]#[% END %]$PERL Build test &&
$PERL Build install;
[% END -%]
} || return 1;
find "$pkgdir" -name .packlist -o -name perllocal.pod -delete
}
END_TEMPL
our
(
$Is_dependency
,
$PKGDEST
,
$PACKAGER
,
$DEBUG
);
$PACKAGER
=
'Anonymous'
;
sub
_DEBUG;
*_DEBUG
= (
$ENV
{DIST_ARCH_DEBUG}
?
sub
{
print
STDERR
'***DEBUG*** '
,
@_
,
"\n"
}
:
sub
{
return
} );
sub
_shell_expand
{
my
$dir
=
shift
;
$dir
=~ s/ \A ~ /
$ENV
{HOME} /xmse;
$dir
=~ s/ (?<!\\) \$ (\w+) /
$ENV
{$1} ||
q{}
/xmseg;
$dir
=~ s/ \\ [a-zA-Z] / /xmsg;
$dir
=~ s/ \\ (.) / $1 /xmsg;
return
$dir
;
}
READ_CONF:
{
my
$mkpkgconf
;
if
( !
open
$mkpkgconf
,
'<'
,
$MKPKGCONF_FQP
) {
error
"Could not read $MKPKGCONF_FQP: $!"
;
last
READ_CONF;
}
my
%cfg_vars
= (
'PKGDEST'
=> \
$PKGDEST
,
'PACKAGER'
=> \
$PACKAGER
);
my
$cfg_field_match
=
sprintf
$CFG_VALUE_MATCH
,
join
'|'
,
keys
%cfg_vars
;
CFG_LINE:
while
(<
$mkpkgconf
>) {
chomp
;
next
CFG_LINE
unless
(
my
(
$name
,
$value
) = /
$cfg_field_match
/xmso );
${
$cfg_vars
{
$name
} } =
(
$value
=~ m/\A
"(.*)"
\z/
? _shell_expand( $1 )
: (
$value
=~ m/\A
'(.*)'
\z/
? $1
: _shell_expand(
$value
)));
}
close
$mkpkgconf
or error
"close on makepkg.conf: $!"
;
}
sub
format_available
{
for
my
$prog
(
qw/ makepkg pacman /
) {
if
( ! can_run(
$prog
) ) {
error
"CPANPLUS::Dist::Arch needs to run $prog, to work properly"
;
return
0;
}
}
return
1;
}
sub
init
{
my
$self
=
shift
;
$self
->status->mk_accessors(
qw{ pkgname pkgver pkgbase pkgdesc
pkgurl pkgsize arch pkgrel
builddir destdir cfgdeps
pkgbuild_templ tt_init_args }
);
return
1;
}
sub
prepare
{
my
$self
=
shift
;
my
$status
=
$self
->status;
my
$module
=
$self
->parent;
my
$intern
=
$module
->parent;
my
$conf
=
$intern
->configure_object;
my
$distcpan
=
$module
->status->dist_cpan;
$self
->SUPER::prepare(
@_
) or
return
0;
$self
->_prepare_status;
return
$status
->prepared;
}
sub
_find_built_pkg
{
my
(
$self
,
$pkg_type
,
$destdir
) =
@_
;
my
$status
=
$self
->status;
my
$arch
=
$self
->status->arch;
if
(
$arch
eq
q{'any'}
) {
$arch
=
'any'
;
}
else
{
chomp
(
$arch
= `uname -m` );
}
my
$pkgfile
= catfile(
$destdir
,
(
join
q{.}
,
(
join
q{-}
,
$status
->pkgname,
$status
->pkgver,
$status
->pkgrel,
(
$pkg_type
eq
q{bin}
?
$arch
:
qw//
),
),
(
$pkg_type
eq
q{bin}
?
q{pkg}
:
q{src}
),
q{tar}
,
));
_DEBUG
"Searching for file starting with $pkgfile"
;
my
(
$found
) =
(
grep
{ -f
$_
}
map
{
"$pkgfile.$_"
}
qw/ xz gz /
);
_DEBUG (
$found
?
"Found $found"
:
"No package file found!"
);
return
$found
;
}
sub
create
{
my
(
$self
,
%opts
) = (
shift
,
@_
);
my
$status
=
$self
->status;
my
$module
=
$self
->parent;
my
$intern
=
$module
->parent;
my
$conf
=
$intern
->configure_object;
my
$distcpan
=
$module
->status->dist_cpan;
MKDIR_LOOP:
for
my
$dir
(
$status
->pkgbase,
$status
->destdir ) {
if
( -e
$dir
) {
die
"$dir exists but is not a directory!"
unless
( -d _ );
die
"$dir exists but is read-only!"
unless
( -w _ );
next
MKDIR_LOOP;
}
make_path(
$dir
, {
verbose
=>
$opts
{verbose} ? 1 : 0 });
}
my
$pkg_type
=
$opts
{pkg} ||
$opts
{pkgtype} ||
'bin'
;
$pkg_type
=
lc
$pkg_type
;
unless
(
$pkg_type
=~ /^(?:bin|src)$/ ) {
error
qq{Invalid package type requested: "$pkg_type"
Package type must be 'bin' or 'src'}
;
return
0;
}
if
(
$opts
{verbose} ) {
my
%fullname
= (
bin
=>
'binary'
,
src
=>
'source'
);
msg
"Creating a $fullname{$pkg_type} pacman package"
;
}
if
(
$pkg_type
eq
'bin'
) {
my
@ok_resolve_args
=
qw/ verbose target force prereq_build /
;
my
%resolve_args
= (
map
{ (
exists
$opts
{
$_
} ?
(
$_
=>
$opts
{
$_
}) : () ) }
@ok_resolve_args
);
local
$Is_dependency
= 1;
$distcpan
->_resolve_prereqs(
%resolve_args
,
'format'
=>
ref
$self
,
'prereqs'
=>
$module
->status->prereqs );
}
my
$srcfile_fqp
=
$status
->pkgbase .
'/'
.
$module
->
package
;
$status
->destdir(
$opts
{destdir} )
if
$opts
{destdir};
my
$destdir
=
$status
->destdir;
$destdir
= Cwd::abs_path(
$destdir
);
if
( ! -e
$srcfile_fqp
) {
my
$tarball_fqp
=
$module
->_status->fetch;
link
$tarball_fqp
,
$srcfile_fqp
or error
"Failed to create link to $tarball_fqp: $OS_ERROR"
;
}
$self
->create_pkgbuild(
$self
->status->pkgbase,
$opts
{skiptest} );
local
$ENV
{PKGDEST} =
$destdir
;
my
$oldcwd
= Cwd::getcwd();
chdir
$status
->pkgbase or
die
"chdir: $OS_ERROR"
;
my
$makepkg_cmd
=
join
q{ }
, (
'makepkg'
,
'-f'
,
(
$EUID
== 0 ?
'--asroot'
: () ),
(
$pkg_type
eq
'src'
?
'--source'
: () ),
(
$opts
{nocolor} ?
'--nocolor'
: () ),
(
$opts
{quiet} ?
'2>&1 >/dev/null'
: () ),
);
system
$makepkg_cmd
;
if
(
$CHILD_ERROR
) {
error (
$CHILD_ERROR
& 127
?
sprintf
"makepkg failed with signal %d"
,
$CHILD_ERROR
& 127
:
sprintf
"makepkg returned abnormal status: %d"
,
$CHILD_ERROR
>> 8 );
return
0;
}
chdir
$oldcwd
or
die
"chdir: $OS_ERROR"
;
my
$pkg_path
=
$self
->_find_built_pkg(
$pkg_type
,
$destdir
);
$status
->dist(
$pkg_path
);
return
$status
->created( 1 );
}
sub
install
{
my
(
$self
,
%opts
) = (
shift
,
@_
);
my
$status
=
$self
->status;
my
$module
=
$self
->parent;
my
$intern
=
$module
->parent;
my
$conf
=
$intern
->configure_object;
my
$pkgfile_fqp
=
$status
->dist;
unless
(
$pkgfile_fqp
) {
error <<
'END_ERROR'
;
Path to
package
file
has
not been set.
Someone is using CPANPLUS::Dist::Arch incorrectly.
Tell them to call create()
before
install().
END_ERROR
return
0;
}
die
"Package file $pkgfile_fqp was not found"
if
( ! -f
$pkgfile_fqp
);
my
@pacmancmd
= (
'pacman'
,
'--noconfirm'
,
'-U'
,
$pkgfile_fqp
,
(
$Is_dependency
?
'--asdeps'
:
'--asexplicit'
),
);
my
$sudocmd
=
$conf
->get_program(
'sudo'
);
if
(
$EFFECTIVE_USER_ID
!=
$ROOT_USER_ID
) {
if
(
$sudocmd
) {
unshift
@pacmancmd
,
$sudocmd
;
}
else
{
error
$NONROOT_WARNING
;
return
0;
}
}
system
@pacmancmd
;
if
(
$CHILD_ERROR
) {
error (
$CHILD_ERROR
& 127
?
sprintf
qq{'@pacmancmd' failed with signal %d}
,
$CHILD_ERROR
& 127
:
sprintf
qq{'@pacmancmd' returned abnormal status: %d}
,
$CHILD_ERROR
>> 8
);
return
0;
}
return
$status
->installed(1);
}
sub
dist_pkgname
{
croak
"Must provide arguments to dist_pkgname"
if
(
@_
== 0 );
my
(
$distname
) =
@_
;
return
$PKGNAME_OVERRIDES
->{
$distname
}
if
$PKGNAME_OVERRIDES
->{
$distname
};
$distname
=
lc
$distname
;
$distname
=~
tr
/_/-/;
$distname
=~
tr
/-a-z0-9//cd;
$distname
=~
tr
/-/-/s;
$distname
=~ s/\A-//;
$distname
=~ s/-\z//;
die
qq{Dist name '$distname' completely violates packaging standards}
if
( !
$distname
);
$distname
=
"perl-$distname"
unless
(
$distname
eq
'perl'
);
return
$distname
;
}
sub
dist_pkgver
{
croak
"Must provide arguments to pacman_version"
if
(
@_
== 0 );
my
(
$version
) =
@_
;
$version
=~
tr
/-/./;
$version
=~
tr
/_0-9.-//cd;
unless
((
$version
=~
tr
/_/_/ == 1 ) && (
$version
=~ /\d_\d+$/ )) {
$version
=~
tr
/_//d;
}
$version
=~
tr
/././s;
$version
=~ s/[.]$//;
$version
=~ s/^[.]//;
return
$version
;
}
sub
set_destdir
{
croak
'Invalid arguments to set_destdir'
if
(
@_
!= 2 );
my
(
$self
,
$destdir
) =
@_
;
$self
->status->destdir(
$destdir
);
return
$destdir
;
}
sub
get_destdir
{
my
$self
=
shift
;
return
$self
->status->destdir;
}
sub
get_pkgpath
{
my
$self
=
shift
;
return
$self
->status->dist;
}
sub
get_cpandistdir
{
my
(
$self
) =
@_
;
my
$module
=
$self
->parent;
my
$distdir
=
$module
->status->dist_cpan->status->distdir;
$distdir
=~ s{^.*/}{};
return
$distdir
;
}
sub
get_pkgname
{
return
shift
->status->pkgname;
}
sub
get_pkgver
{
return
shift
->status->pkgver;
}
sub
get_pkgrel
{
my
(
$self
) =
@_
;
return
$self
->status->pkgrel;
}
sub
set_pkgrel
{
my
(
$self
,
$new_pkgrel
) =
@_
;
return
$self
->status->pkgrel(
$new_pkgrel
);
}
sub
_deps_string
{
my
(
$deps_ref
) =
@_
;
return
(
join
' '
,
map
{
qq{'$_'}
}
map
{
$deps_ref
->{
$_
} ?
qq{$_>=$deps_ref->{$_}
} :
$_
}
sort
keys
%$deps_ref
);
}
sub
get_pkgvars
{
croak
'Invalid arguments to get_pkgvars'
if
(
@_
!= 1 );
my
$self
=
shift
;
my
$status
=
$self
->status;
croak
'prepare() must be called before get_pkgvars()'
unless
(
$status
->prepared );
my
$deps_ref
=
$self
->_get_pkg_deps;
return
(
pkgname
=>
$status
->pkgname,
pkgver
=>
$status
->pkgver,
pkgrel
=>
$status
->pkgrel,
arch
=>
$status
->arch,
pkgdesc
=>
$status
->pkgdesc,
depends
=> _deps_string(
$deps_ref
->{
'depends'
} ),
makedepends
=> _deps_string(
$deps_ref
->{
'makedepends'
} ),
url
=>
$self
->_get_disturl,
source
=>
$self
->_get_srcurl,
md5sums
=>
$self
->_calc_tarballmd5,
depshash
=>
$deps_ref
,
);
}
sub
get_pkgvars_ref
{
croak
'Invalid arguments to get_pkgvars_ref'
if
(
@_
!= 1 );
my
$self
=
shift
;
return
{
$self
->get_pkgvars };
}
sub
set_tt_init_args
{
my
$self
=
shift
;
croak
'set_tt_init_args() must be given a hash as an argument'
unless
@_
% 2 == 0;
return
$self
->status->tt_init_args( {
@_
} );
}
sub
set_tt_module
{
my
(
$self
,
$modname
) =
@_
;
return
(
$TT_MOD_NAME
= 0 )
unless
$modname
;
croak
qq{Failed to load template module "$modname"}
unless
eval
"require $modname; 1;"
;
_DEBUG
"Loaded template module: $modname"
;
return
$TT_MOD_NAME
=
$modname
;
}
sub
get_tt_module
{
_load_tt_module()
unless
defined
$TT_MOD_NAME
;
return
$TT_MOD_NAME
;
}
sub
set_pkgbuild_templ
{
my
(
$self
,
$template
) =
@_
;
return
$self
->status->pkgbuild_templ(
$template
);
}
sub
get_pkgbuild_templ
{
my
(
$self
) =
@_
;
return
$self
->status->pkgbuild_templ() ||
$PKGBUILD_TEMPL
;
}
sub
get_pkgbuild
{
croak
'Invalid arguments to get_pkgbuild'
if
(
@_
< 1 );
my
(
$self
,
$skiptest
) =
@_
;
my
$status
=
$self
->status;
my
$module
=
$self
->parent;
my
$conf
=
$module
->parent->configure_object;
croak
'prepare() must be called before get_pkgbuild()'
unless
$status
->prepared;
my
%pkgvars
=
$self
->get_pkgvars;
$pkgvars
{pkgdesc} =~ s/ ([\$\"\`]) /\\$1/gxms;
my
$templ_vars
= {
packager
=>
$ENV
{PACKAGER} ||
$PACKAGER
,
version
=>
$VERSION
,
%pkgvars
,
distdir
=>
$self
->get_cpandistdir(),
skiptest
=>
$skiptest
||
$conf
->get_conf(
'skiptest'
),
};
my
$dist_type
=
$module
->status->installer_type;
@{
$templ_vars
}{
'is_makemaker'
,
'is_modulebuild'
} =
(
$dist_type
eq
'CPANPLUS::Dist::MM'
? (1, 0) :
$dist_type
eq
'CPANPLUS::Dist::Build'
? (0, 1) :
die
"unknown Perl module installer type: '$dist_type'"
);
my
$templ_text
=
$status
->pkgbuild_templ ||
$PKGBUILD_TEMPL
;
return
scalar
$self
->_process_template(
$templ_text
,
$templ_vars
);
}
sub
create_pkgbuild
{
croak
'Invalid arguments to create_pkgbuild'
if
(
@_
< 2 );
my
(
$self
,
$destdir
,
$skiptest
) =
@_
;
croak
qq{Invalid directory passed to create_pkgbuild: "$destdir" ...
Directory does not exist or is not writeable}
unless
( -d
$destdir
&& -w _ );
my
$pkgbuild_text
=
$self
->get_pkgbuild(
$skiptest
);
my
$fqpath
= catfile(
$destdir
,
'PKGBUILD'
);
open
my
$pkgbuild_file
,
'>'
,
$fqpath
or
die
"failed to open new PKGBUILD: $OS_ERROR"
;
print
$pkgbuild_file
$pkgbuild_text
;
close
$pkgbuild_file
or
die
"failed to close new PKGBUILD: $OS_ERROR"
;
return
;
}
sub
_is_main_module
{
my
(
$mod_name
,
$dist_name
) =
@_
;
$mod_name
=~
tr
/:/-/s;
return
(
lc
$mod_name
) eq (
lc
$dist_name
);
}
sub
_merge_deps
{
my
(
$left_deps
,
$right_deps
) =
@_
;
MERGE_LOOP:
while
(
my
(
$pkg
,
$ver
) =
each
%$right_deps
) {
next
MERGE_LOOP
if
$left_deps
->{
$pkg
} &&
( qv(
$left_deps
->{
$pkg
}) > qv(
$ver
) );
$left_deps
->{
$pkg
} =
$ver
;
}
return
$left_deps
;
}
sub
_extract_makedepends
{
my
(
$self
,
$deps_ref
) =
@_
;
my
%makedeps
;
my
$cpanpkg
=
$self
->parent->package_name;
unless
(
$cpanpkg
=~ /^Test-/ ) {
for
my
$testdep
(
grep
{ /perl-test-/ }
keys
%$deps_ref
) {
$makedeps
{
$testdep
} =
delete
$deps_ref
->{
$testdep
};
}
for
my
$dep
(
qw/ perl-pod-coverage /
) {
$makedeps
{
$dep
} =
delete
$deps_ref
->{
$dep
}
if
exists
$deps_ref
->{
$dep
};
}
}
for
my
$extdep
(
grep
{ /perl-extutils-/ }
keys
%$deps_ref
) {
$makedeps
{
$extdep
} =
delete
$deps_ref
->{
$extdep
};
}
return
\
%makedeps
;
}
sub
_translate_cpan_deps
{
my
(
$self
,
$moddeps_ref
) =
@_
;
my
$modobj
=
$self
->parent;
my
$backend
=
$modobj
->parent;
my
%pkgdeps
;
CPAN_DEP_LOOP:
for
my
$modname
(
keys
%$moddeps_ref
) {
my
$depver
=
$moddeps_ref
->{
$modname
};
if
(
$modname
eq
'perl'
) {
$pkgdeps
{perl} =
$depver
;
next
CPAN_DEP_LOOP;
}
my
$modobj
=
$backend
->module_tree(
$modname
)
or
next
CPAN_DEP_LOOP;
my
$cpanpkg
=
$modobj
->package_name;
my
$pkgname
= dist_pkgname(
$cpanpkg
);
if
(
exists
$pkgdeps
{
$pkgname
} ) {
next
CPAN_DEP_LOOP
unless
_is_main_module(
$modname
,
$cpanpkg
);
}
$pkgdeps
{
$pkgname
} = (
$depver
? dist_pkgver(
$depver
) :
'0'
);
}
return
\
%pkgdeps
;
}
sub
_get_pkg_deps
{
croak
'Invalid arguments to _get_pkg_deps method'
if
@_
!= 1;
my
(
$self
) =
@_
;
my
$module
=
$self
->parent;
my
$backend
=
$module
->parent;
my
$prereqs
=
$module
->status->prereqs;
my
$pkgdeps_ref
=
$self
->_translate_cpan_deps(
$prereqs
);
my
$makedeps_ref
=
$self
->_extract_makedepends(
$pkgdeps_ref
);
my
$cfgdeps_ref
=
$self
->_translate_cpan_deps(
$self
->status->cfgdeps );
_merge_deps(
$makedeps_ref
,
$cfgdeps_ref
);
my
$xs_deps
=
$self
->_translate_xs_deps;
_merge_deps(
$pkgdeps_ref
,
$xs_deps
);
$pkgdeps_ref
->{
'perl'
} = 0
unless
grep
{ /^perl/ }
keys
%$pkgdeps_ref
;
return
{
'depends'
=>
$pkgdeps_ref
,
'makedepends'
=>
$makedeps_ref
};
}
sub
_metayml_pkgdesc
{
my
(
$mod_obj
) =
@_
;
my
$metayml
;
unless
(
open
$metayml
,
'<'
,
catfile(
$mod_obj
->status->extract,
'META.yml'
)) {
_DEBUG(
"Could not open META.yml to get pkgdesc: $!"
);
return
undef
;
}
while
( <
$metayml
> ) {
chomp
;
if
(
my
(
$pkgdesc
) = / \A abstract: \s* (.+) \s* \z /xms ) {
_DEBUG
qq{Found pkgdesc "$pkgdesc" in META.yml}
;
$pkgdesc
= $2
if
(
$pkgdesc
=~ / \A (['"]) (.*) \1 \z /xms );
for
my
$bad
(
@BAD_METAYML_ABSTRACTS
) {
return
undef
if
$pkgdesc
eq
$bad
;
}
return
$pkgdesc
;
}
}
return
undef
;
}
sub
_pod_pkgdesc
{
my
(
$mod_obj
) =
@_
;
my
$podselect
= Pod::Select->new;
my
$modname
=
$mod_obj
->name;
$podselect
->
select
(
'NAME'
);
my
$mainmod_path
=
$mod_obj
->package_name;
$mainmod_path
=~
tr
{-}{/}s;
my
$mainmod_file
=
$mainmod_path
;
$mainmod_file
=~ s{\A.*/}{};
$mainmod_path
=~ s{/
$mainmod_file
}{};
my
$base_path
=
$mod_obj
->status->extract;
my
@possible_pods
= (
glob
"$base_path/{lib/,}{$mainmod_path/,}"
.
"$mainmod_file.{pod,pm}"
);
PODSEARCH:
for
my
$podfile_path
(
@possible_pods
) {
next
PODSEARCH
unless
( -e
$podfile_path
);
_DEBUG
"Searching the POD inside $podfile_path for pkgdesc..."
;
my
$name_section
=
q{}
;
open
my
$podfile
,
'<'
,
$podfile_path
or
next
PODSEARCH;
open
my
$podout
,
'>'
, \
$name_section
or
die
"failed open on filehandle to string: $!"
;
$podselect
->parse_from_filehandle(
$podfile
,
$podout
);
close
$podfile
;
close
$podout
or
die
"failed close on filehandle to string: $!"
;
next
PODSEARCH
unless
(
$name_section
);
$name_section
=~ s{ [IBCLEFSXZ] <(.*?)> }{$1}gxms;
$name_section
=~ s{ [IBCLEFSXZ] <<(.*?)>> }{$1}gxms;
if
(
$name_section
=~ / ^ \s*
$modname
[ -]+ ([^\n]+) /xms ) {
_DEBUG
qq{Found pkgdesc "$1" in POD}
;
return
$1;
}
}
return
undef
;
}
sub
_readme_pkgdesc
{
my
(
$mod_obj
) =
@_
;
my
$mod_name
=
$mod_obj
->name;
open
my
$readme
,
'<'
, catfile(
$mod_obj
->status->extract,
'README'
)
or
return
undef
;
LINE:
while
( <
$readme
> ) {
chomp
;
next
LINE
unless
( ( /^NAME/ ... /^[A-Z]+/ ) &&
/ ^ \s* ${mod_name} [\s\-]+ (.+) $ /oxms );
_DEBUG
qq{Found pkgdesc "$1" in README}
;
return
$1;
}
return
undef
;
}
sub
_find_xs_files
{
my
(
$dirpath
) =
@_
;
return
-f
"$dirpath/typemap"
||
scalar
glob
"$dirpath/*.xs"
;
}
sub
_prepare_arch
{
my
(
$self
) =
@_
;
my
$dist_cpan
=
$self
->parent->status->dist_cpan;
my
$dist_dir
=
$dist_cpan
->status->distdir;
unless
(
$dist_dir
&& -d
$dist_dir
) {
return
$self
->status->arch(
q{'any'}
);
}
my
$found_xs
;
if
( _find_xs_files(
$dist_dir
)) {
$found_xs
= 1;
}
else
{
opendir
my
$basedir
,
$dist_dir
or
die
"opendir: $!"
;
my
@childdirs
=
grep
{ !/^./ && -d
$_
}
readdir
$basedir
;
DIR_LOOP:
for
my
$childdir
(
@childdirs
) {
next
DIR_LOOP
unless
_find_xs_files(
$childdir
);
$found_xs
= 1;
last
DIR_LOOP;
}
closedir
$basedir
;
}
return
$self
->status->arch(
$found_xs
?
q{'i686' 'x86_64'}
:
q{'any'}
);
}
sub
_prepare_pkgdesc
{
croak
'Invalid arguments to _prepare_pkgdesc method'
if
@_
!= 1;
my
(
$self
) =
@_
;
my
(
$status
,
$module
,
$pkgdesc
) = (
$self
->status,
$self
->parent);
my
@pkgdesc_srcs
=
(
sub
{
$module
->description },
\
&_metayml_pkgdesc
,
\
&_pod_pkgdesc
,
\
&_readme_pkgdesc
,
);
PKGDESC_LOOP:
for
my
$pkgdesc_src
(
@pkgdesc_srcs
) {
$pkgdesc
=
$pkgdesc_src
->(
$module
) and
last
PKGDESC_LOOP;
}
return
$status
->pkgdesc(
$pkgdesc
||
q{}
);
}
sub
_prepare_cfgdeps
{
my
(
$self
) =
@_
;
my
(
$status
,
$modobj
) = (
$self
->status,
$self
->parent);
$status
->cfgdeps( {} );
my
$metapath
= catfile(
$modobj
->status->extract,
'META.yml'
);
return
unless
-f
$metapath
;
my
$meta_ref
= Parse::CPAN::Meta::LoadFile(
$metapath
);
return
unless
$meta_ref
->{
'configure_requires'
};
$status
->cfgdeps(
$meta_ref
->{
'configure_requires'
} );
return
;
}
sub
_prepare_status
{
croak
'Invalid arguments to _prepare_status method'
if
@_
!= 1;
my
$self
=
shift
;
my
$status
=
$self
->status;
my
$module
=
$self
->parent;
my
$conf
=
$module
->parent->configure_object;
my
$our_base
= catdir(
$conf
->get_conf(
'base'
),
(
sprintf
"%vd"
,
$PERL_VERSION
),
'pacman'
);
$status
->destdir(
$ENV
{PKGDEST} ||
$PKGDEST
||
catdir(
$our_base
,
'pkg'
) );
my
(
$pkgver
,
$pkgname
)
= ( dist_pkgver(
$module
->package_version ),
dist_pkgname(
$module
->package_name));
my
$pkgbase
= catdir(
$our_base
,
'build'
,
"$pkgname-$pkgver"
);
foreach
(
$pkgname
,
$pkgver
,
$pkgbase
) {
die
"A package variable is invalid"
unless
defined
;
}
$status
->pkgname(
$pkgname
);
$status
->pkgver (
$pkgver
);
$status
->pkgbase(
$pkgbase
);
$status
->pkgrel ( 1 );
$status
->tt_init_args( {} );
$self
->_prepare_arch();
$self
->_prepare_pkgdesc();
$self
->_prepare_cfgdeps();
return
$status
;
}
sub
_get_disturl
{
croak
'Invalid arguments to _get_disturl method'
if
@_
!= 1;
my
$self
=
shift
;
my
$module
=
$self
->parent;
my
$distname
=
$module
->package_name;
return
join
'/'
,
$CPANURL
,
'dist'
,
$distname
;
}
sub
_get_srcurl
{
croak
'Invalid arguments to _get_srcurl method'
if
@_
!= 1;
my
(
$self
) =
@_
;
my
$module
=
$self
->parent;
return
join
'/'
,
$CPANURL
,
'CPAN'
,
$module
->path,
$module
->
package
;
}
sub
_calc_tarballmd5
{
my
(
$self
) =
@_
;
my
$module
=
$self
->parent;
my
$tarball_fqp
=
$module
->_status->fetch;
open
my
$distfile
,
'<'
,
$tarball_fqp
or
die
"failed to get md5 of $tarball_fqp: $OS_ERROR"
;
my
$md5
= Digest::MD5->new;
$md5
->addfile(
$distfile
);
close
$distfile
;
return
$md5
->hexdigest;
}
sub
_extract_nested
{
croak
'Invalid arguments to _extract_nested'
unless
(
@_
== 3 );
my
(
$text
,
$begin_match
,
$end_match
) =
@_
;
my
(
$before_end
,
$middle_start
,
$middle_end
,
$after_start
);
croak
qq{could not find beginning match "$begin_match"}
unless
(
$text
=~ /
$begin_match
/ );
$before_end
=
$LAST_MATCH_START
[0];
$middle_start
=
$LAST_MATCH_END
[0];
my
$search_pos
=
$middle_start
;
END_SEARCH:
{
pos
$text
=
$search_pos
;
croak
sprintf
<<'END_ERR', substr $text, $search_pos, 30
could not find ending match starting at:
%s...
END_ERR
unless
(
$text
=~ /
$end_match
/go );
$middle_end
=
$LAST_MATCH_START
[0];
$after_start
=
$LAST_MATCH_END
[0];
pos
$text
=
$search_pos
;
if
(
$text
=~ /
$begin_match
/go &&
pos
(
$text
) <
$after_start
) {
$search_pos
=
$after_start
;
redo
END_SEARCH;
}
}
my
$before
=
substr
$text
, 0,
$before_end
;
my
$middle
=
substr
$text
,
$middle_start
,
$middle_end
-
$middle_start
;
my
$after
=
substr
$text
,
$after_start
;
return
(
$before
,
$middle
,
$after
);
}
sub
_prune_if_blocks
{
my
(
$templ
,
$templ_vars
) =
@_
;
while
(
my
(
$varname
) =
$templ
=~
$TT_IF_MATCH
) {
croak
"Invalid template given.\n"
.
'Must provide a variable name in an IF block'
unless
$varname
;
croak
"Unknown variable name in IF block: $varname"
unless
(
exists
$templ_vars
->{
$varname
} );
my
@chunks
= _extract_nested(
$templ
,
$TT_IF_MATCH
,
$TT_END_MATCH
);
if
( !
$templ_vars
->{
$varname
} ) {
splice
@chunks
, 1, 1; }
$templ
=
join
q{}
,
@chunks
;
}
return
$templ
;
}
sub
_load_tt_module
{
_DEBUG
"Searching for template modules..."
;
TT_SEARCH:
for
my
$ttmod
(
@TT_MOD_SEARCH
) {
eval
"require $ttmod; 1;"
or
next
TT_SEARCH;
_DEBUG
"Loaded template module: $ttmod"
;
$TT_MOD_NAME
=
$ttmod
;
return
;
}
_DEBUG
"None found!"
;
$TT_MOD_NAME
= 0;
return
;
}
sub
_tt_process
{
my
(
$self
,
$templ
,
$templ_vars
) =
@_
;
confess
'Internal Error: $TT_MOD_NAME not set'
unless
$TT_MOD_NAME
;
_DEBUG
"Processing template using $TT_MOD_NAME"
;
my
(
$tt_obj
,
$tt_output
,
$tt_init_args
);
$tt_init_args
=
$self
->status->tt_init_args();
$tt_output
=
q{}
;
$tt_obj
=
$TT_MOD_NAME
->new(
$TT_MOD_NAME
eq
'Template'
?
$tt_init_args
:
%$tt_init_args
);
$tt_obj
->process( \
$templ
,
$templ_vars
, \
$tt_output
);
croak
"$TT_MOD_NAME failed to process PKGBUILD template:\n"
.
$tt_obj
->error
if
(
eval
{
$tt_obj
->error } );
return
$tt_output
;
}
sub
_process_template
{
croak
"Invalid arguments to _process_template"
if
@_
!= 3;
my
(
$self
,
$templ
,
$templ_vars
) =
@_
;
croak
'templ_var parameter must be a hashref'
if
(
ref
$templ_vars
ne
'HASH'
);
_load_tt_module()
unless
defined
$TT_MOD_NAME
;
return
$self
->_tt_process(
$templ
,
$templ_vars
)
if
$TT_MOD_NAME
;
_DEBUG
"Processing PKGBUILD template with built-in code..."
;
$templ
= _prune_if_blocks(
$templ
,
$templ_vars
);
$templ
=~ s{
$TT_VAR_MATCH
}
{ (
defined
$templ_vars
->{$1}
?
$templ_vars
->{$1}
: croak
"Template variable $1 was not provided"
)
}xmseg;
return
$templ
;
}
sub
_translate_xs_deps
{
my
$self
=
shift
;
my
$modstat
=
$self
->parent->status;
my
$inst_type
=
$modstat
->installer_type;
my
$distcpan
=
$modstat
->dist_cpan;
my
$libs_ref
= (
$inst_type
eq
'CPANPLUS::Dist::MM'
?
$self
->_get_mm_xs_deps(
$distcpan
) : [] );
return
+{
map
{
$self
->_get_lib_pkg(
$_
) }
@$libs_ref
};
}
sub
_get_lib_pkg
{
my
(
$self
,
$libname
) =
@_
;
my
$lib_fqp
= DynaLoader::dl_findfile(
$libname
)
or
return
();
my
$result
= `pacman -Qo
$lib_fqp
`;
chomp
$result
;
if
(
$result
=~ /
$PACMAN_FINDOWN_ERR
/ ) {
error
qq{Could not find owner of linked library }
.
qq{"$libname", ignoring.}
;
return
();
}
my
(
$pkgname
,
$pkgver
) =
$result
=~ /
$PACMAN_FINDOWN
/;
$pkgver
=~ s/-\d+\z//;
return
(
$pkgname
=>
$pkgver
);
}
sub
_unique(@)
{
my
%seen
;
return
map
{
$seen
{
$_
}++ ? () :
$_
}
@_
;
}
sub
_get_mm_xs_deps
{
my
(
$self
,
$dist
) =
@_
;
my
$field_srch
=
'\A(?:EXTRALIBS|LDLOADLIBS|BSLOADLIBS) = (.+)\z'
;
my
$mkfile_fqp
=
$dist
->status->makefile
or
die
"Internal error: makefile() path is unset in our object"
;
open
my
$mkfile
,
'<'
,
$mkfile_fqp
or
die
"Internal error: failed to open Makefile at $mkfile_fqp ... $!"
;
my
@libs
= _unique
map
{
chomp
; (/
$field_srch
/o) } <
$mkfile
>;
close
$mkfile
;
return
[
grep
{ /\A-l/ }
map
{
split
}
@libs
];
}
1;