import rt 2.0.14
[freeside.git] / rt / tools / cpan2rpm
diff --git a/rt/tools/cpan2rpm b/rt/tools/cpan2rpm
new file mode 100644 (file)
index 0000000..9b54cb9
--- /dev/null
@@ -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>