diff options
Diffstat (limited to 'rt/tools/cpan2rpm')
-rw-r--r-- | rt/tools/cpan2rpm | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/rt/tools/cpan2rpm b/rt/tools/cpan2rpm new file mode 100644 index 000000000..9b54cb912 --- /dev/null +++ b/rt/tools/cpan2rpm @@ -0,0 +1,299 @@ +#!/usr/bin/perl -w + + +# Take a perl tarball and make a specfile for it. Now with bundles. +# +# Copyright 2000,2001 Simon Wilkinson. All rights reserved. +# +# 10/18/2001 - <jesse@bestpractical.com> +# Added resolution of prereq_pm modules +# +# This program is free software; you can redistribute it +# and/or modify it under the same terms as Perl itself. +# + +use strict; + +use CPAN; +use POSIX; +use Sys::Hostname; +use File::Basename; +use Getopt::Long; + +use vars qw ($DEBUG $ARCH $builddir $seen @report); + +$ARCH = 'i386'; + +$DEBUG = 0; +# Icky globals + +my $release; +my $package; + +$seen = {}; + + +sub usage +{ + print STDERR <<EOM; + +Usage: cpan2rpm [--release <release>] [--builddir <rpm build dir>] <Perl::Module> + +Where: +<release> is the release number of the RPM you wish to produce +<Perl::Module> is the name of the module to build +EOM + exit(1); +} + + +my $ret=GetOptions("release" => \$release, + "builddir=s" => \$builddir); + +$package=$ARGV[0]; +usage() if !$package; +$release=1 if !$release; + + +$builddir=ExtractRpmMacro($ENV{HOME}."/.rpmmacros","_topdir") if !$builddir; +$builddir=ExtractRpmMacro("/etc/rpm/macros","_topdir") if !$builddir; +$builddir=getcwd() if !$builddir; + +die "Build directory $builddir doesn't look like an RPM build root\n" + if ((! -d "$builddir/SPECS") || (! -d "$builddir/SOURCES")); + +process($package,$release); + +print join("\n",@report)."\n"; + +sub process { + my ($infile,$release)=@_; + + + +# Convert our installation list into an unbundled one + unbundle($infile); + + print "Building $infile\n"; + + cpan2rpm($infile,$builddir,$release); + +} + +# Given a Module, try to split it into its required components - this +# currently only handles Bundles, but could also be extended to deal with +# prereqs as well. + +sub unbundle { + my ($item) = @_; + + if ($item=~/Bundle::/) { + my $obj=CPAN::Shell->expand('Bundle',$item); + + foreach my $kid ($obj->contains) { + process($kid,$release); + } + } +} + + +sub cpan2rpm($$$) { + my ($infile,$builddir,$release) = @_; + + my $ret; + + my $obj=CPAN::Shell->expand('Module',$infile); + + print "CPAN tells us the following about $infile:\n",$obj->as_string if ($DEBUG); + + $ret=fetch_source($obj,$builddir); + $ret=build_specfile($obj,$builddir,$release) if !$ret; + + return $ret; +} + +# FIXME: Some error handling in the function below wouldn't go amiss ... +sub fetch_source { + my ($obj,$builddir)=@_; + + # Minor Sanity checks + my $id=$obj->{ID}; + + return "Error: No file for $id\n" + if $obj->cpan_file eq "N/A"; + return "Error: $id says 'Contact Author'\n" + if $obj->cpan_file =~ /^Contact Author/; + return "Error: $id is contained within Perl itself!\n" + if ($obj->cpan_file =~/perl-5\.\d?\.\d?\.tar\.gz/xo); + + # We do this so we can take advantage of CPAN's object caching. This is + # pinched from the CPAN::Distribution::get method, which we can't use + # directly, as it untars the package as well - which we let RPM do. + + my $dist = $CPAN::META->instance('CPAN::Distribution',$obj->cpan_file); + + + my($local_wanted) = + MM->catfile($CPAN::Config->{keep_source_where}, + "authors", + "id", + split("/",$dist->{ID}) + ); + + my $local_file = CPAN::FTP->localize("authors/id/$dist->{ID}", $local_wanted); + + $dist->{localfile} = $local_file; + + $dist->verifyMD5 if ($CPAN::META->has_inst('MD5')); + + + # Find all the prereqs for this distribution, then build em. + # TODO this should be somewhere else + + $dist->make; + build_prereqs( $dist->prereq_pm()); + + + + my $infile=basename($obj->cpan_file); + + File::Copy::copy($local_file,"$builddir/SOURCES/$infile"); + + return undef; +} + + +sub build_prereqs($) { + my ($prereqs) = @_; + + foreach my $prereq (keys %{$prereqs}) { + process ($prereq, $release); + } +} +sub build_specfile($$$) { + my ($obj,$builddir,$release) = @_; + + my $source=basename($obj->cpan_file); + + # don't go through dependencies on something we've already dealt with + return() if ($seen->{$source}); + $seen->{$source} = 1; + +my ($name,$version)=($source=~/(.*)-(.*)\.tar\.gz/); + return "Couldn't get a name for $source\n" if !$name; + return "Couldn't get a version for $source\n" if !$version; + + my $summary="$name module for perl"; + my $description=$obj->{description}; + $description= $summary if !$description; + + open(SPEC, ">$builddir/SPECS/perl-$name.spec") + or die "Couldn't open perl-$name.spec for writing."; + print SPEC <<EOF; + +Summary: $summary +Name: perl-$name +Version: $version +Release: $release +Copyright: distributable +Group: Applications/CPAN +Source0: $source +Url: http://www.cpan.org +BuildRoot: /var/tmp/perl-${name}-buildroot/ +Requires: perl + +%description +This is a perl module, autogenerated by cpan2rpm. The original package's +description was: + +$description + +%prep +%setup -q -n $name-%{version} + +%build +CFLAGS="\$RPM_OPT_FLAGS" perl Makefile.PL +make + +%clean +rm -rf \$RPM_BUILD_ROOT + +%install +rm -rf \$RPM_BUILD_ROOT +eval `perl '-V:installarchlib'` +mkdir -p \$RPM_BUILD_ROOT/\$installarchlib +make PREFIX=\$RPM_BUILD_ROOT/usr install +/usr/lib/rpm/brp-compress +find \$RPM_BUILD_ROOT/usr -type f -print | sed "s\@^\$RPM_BUILD_ROOT\@\@g" | grep -v perllocal.pod > $name-$version-filelist + +%files -f ${name}-${version}-filelist +%defattr(-,root,root) + +%changelog +EOF + print SPEC "* ",POSIX::strftime("%a %b %d %Y",localtime()), " ",$ENV{USER}," <",$ENV{USER},"\@",hostname(),">\n"; + print SPEC "- Spec file automatically generated by cpan2rpm\n"; + + close(SPEC); + + system("rpm -ba $builddir/SPECS/perl-$name.spec >/dev/null") == 0 + or push (@report, "RPM of $source failed with : $!\n"); + + system("rpm -Uvh $builddir/RPMS/$ARCH/perl-$name-$version-$release.$ARCH.rpm") == 0 + or warn "RPM of $source could not be installed: $!\n"; + + push (@report, "Built perl-$name-$version-$release.$ARCH.rpm"); +} + +sub ExtractRpmMacro { + my ($file,$macro) = @_; + + my $handle=new IO::File; + + if (!$handle->open($file)) { + return undef; + } + + while(<$handle>) { + if (/\%$macro (.*)/) { + return $1; + } + } + + return undef; +} + +=head1 NAME + +cpan2rpm - fetch and convert CPAN packages to RPMs + +=head1 SYNOPSIS + +cpan2rpm --release <release> <package> + +=head1 DESCRIPTION + +cpan2rpm provides a quick way of creating RPM packages from perl modules +published on CPAN. It interfaces with the perl CPAN module to fetch the +file from the selected mirror, and then creates a spec file from the +information in CPAN, and invokes RPM on that spec file. + +Files are created in the users RPM build root. + +=head1 OPTIONS + +=over 4 + +=item release + +Sets the release number of the created RPMs. + +=back + +=head1 SEE ALSO + +rpm(1) + +=head1 AUTHOR + +Simon Wilkinson <sxw@sxw.org.uk> |