#!/usr/bin/perl # # ebuilder.pl - create ebuilds for modules on CPAN # Leon Brocard use strict; use CPANPLUS::Backend; use Cwd; use Data::Denter; use FileHandle; use File::Spec; use IPC::Run qw(run timeout); use Template; use vars qw($VERSION); $VERSION = "0.01"; # This allows you to add additional dependencies to a perl distribution my $DEPENDS = { # YAML::ConfigFile doesn't list this as a dependency, but needs it # to test. The module doesn't pass its tests atm anyway 'YAML-ConfigFile' => 'dev-perl/Test-Simple', }; # Keep track of the current directory my $cwd = cwd; # This is the directory where we will write our ebuilds my $EBUILDS = File::Spec->catfile($cwd, 'ebuilds'); # Construct our CPANPLUS object my $cp = CPANPLUS::Backend->new(conf => {verbose => 1}); # Search for all the modules beginnig with 'Y' my $modules = $cp->search(type => 'module', list => ['^Y']) || die "No modules found"; # Loop through all the modules foreach my $module (values %$modules) { # Ignore if it is a core perl module next if $module->package =~ /^perl/; # Ignore mod_perl for now next if $module->module =~ /^Apache/; process($module->module); } # Given a module object, returns true if we have already built an # ebuild for it sub already_done { my $module = shift; my $dist = _get_dist($module); my $dist_and_version = _get_dist_and_version($module); return -f File::Spec->catfile($EBUILDS, $dist, "$dist_and_version.ebuild"); } # Process a module name sub process { my $module_name = shift; print "* $module_name\n"; my $module = $cp->module_tree()->{$module_name} || die "Module $module_name not found!"; if (already_done($module)) { print "... already processed, skipped\n"; return; } # print Denter($module); # print $module->description, "\n"; # Fetch the module from CPAN print "... fetching\n"; my $tar = $module->fetch(); # Extract the module print "... extracting\n"; my $dir = $cp->extract(files => [$tar]); $dir = $dir->{$tar}; # Run 'perl Makefile.PL' chdir $dir; run(["/usr/bin/perl", File::Spec->catfile($dir, "Makefile.PL")]); # my($in, $out, $err); # run(["/usr/bin/perl", File::Spec->catfile($dir, "Makefile.PL")], \$in, \$out, \$err); chdir $cwd; # Find the dependencies my $p = _find_prereq($dir); if (not defined $p) { print "... error: Makefile not found, skipped\n"; return; } # Munge the dependencies into what newdepend expects my $depend = ""; $depend .= $DEPENDS->{_get_dist($module)}; if (keys %$p) { foreach my $m (keys %$p) { my $v = $p->{$m}; my $module = $cp->module_tree()->{$m}; if (not defined $module) { print "... error: dependency $m not found, skipped\n"; return; } my $dist = _get_dist_and_version($module); my $d = " >=dev-perl/$dist "; # print "$d\n"; $depend .= $d; } print "... has prereqs: $depend\n"; } else { print "... has no prereqs\n"; } print "... generating ebuild\n"; _generate_ebuild($module, $depend); print "... done\n"; } # Actually write out the ebuild sub _generate_ebuild { my($module, $depend) = @_; my $template = ' # Copyright 1999-2002 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License, v2 or later # $Header$ # Autogenerated by Leon Brocard # Inherit from perl-module.eclass inherit perl-module S=${WORKDIR}/${P} DESCRIPTION="Perl module: [% module.description %]" SRC_URI="http://www.cpan.org/authors/id/[% module.path %]/${P}.tar.gz" HOMEPAGE="http://search.cpan.org/search?dist=[% dist | uri %]" [% IF depend %] newdepend "[% depend %]" [% END %] src_compile() { try perl Makefile.PL try make try make test } '; my $dist = _get_dist($module); my $dist_and_version = _get_dist_and_version($module); my $conf = { module => $module, depend => $depend, dist => $dist }; mkdir $EBUILDS; mkdir File::Spec->catfile($EBUILDS, $dist); my $TT = Template->new(); $TT->process(\$template, $conf, File::Spec->catfile($EBUILDS, $dist, "$dist_and_version.ebuild")) || die $TT->error(); } # Given a module object, returns the distribution name sub _get_dist { my $module = shift; my $dist = $module->package; $dist =~ s/\.tar.gz$//; $dist =~ s/\.zip$//; $dist =~ s/(-|\.|\d)+$//g; return $dist; } # Given a module object, returns the distribution name (including the # version) sub _get_dist_and_version { my $module = shift; my $dist = $module->package; $dist =~ s/\.tar.gz$//; $dist =~ s/\.zip$//; return $dist; } # Scary code shamelessly stolen from the CPANPLUS internals. Given a # directory where 'perl Makefile.PL' has been run, looks in the # Makefile and returns a hashref of the dependencies, where the key is # the module name and the value is the minimum version sub _find_prereq { my $d = shift; my $fh = FileHandle->new; ### open the Makefile unless ( $fh->open(File::Spec->catfile($d, "Makefile") ) ) { return; } my %p; while (<$fh>) { last if /MakeMaker post_initialize section/; ### find prereqs my ($p) = m{^[\#] \s+PREREQ_PM\s+=>\s+(.+) }x; next unless $p; ### parse out the single prereqs while ( $p =~ m/(?:\s)([\w\:]+)=>(?:q\[(.*?)\],?|undef)/g ){ ### In case a prereq is mentioned twice, complain. if ( defined $p{$1} ) { warn "Warning: PREREQ_PM mentions $1 more than once, last mention wins!"; } $p{$1} = $2; } last; } return \%p; }