#!/usr/bin/perl -w
#
#
#       makerpm.pl - A Perl script for building binary distributions
#                    of Perl packages
#
#       This script is Copyright (C) 1999       Jochen Wiedmann
#                                               Am Eisteich 9
#                                               72555 Metzingen
#                                               Germany
#
#                                               E-Mail: [email protected]
#
#       You may distribute under the terms of either the GNU General
#       Public License or the Artistic License, as specified in the
#       Perl README.
#

use strict;

use Cwd ();
use File::Find ();
use File::Path ();
use File::Spec ();
use Getopt::Long ();

use vars qw($VERSION);
$VERSION = "makerpm 0.1003 22-July-1999, (C) 1999 Jochen Wiedmann";

=pod

=head1 NAME

 makerpm - Build binary distributions of Perl packages


=head1 SYNOPSIS

Create a SPECS file:

 makerpm --specs --source=<package>-<version>.tar.gz

Apply the SPECS file (which in turn uses makerpm.pl):

 rpm -ba <package>-<version>.spec


=head1 DESCRIPTION

The I<makerpm> script is designed for creating binary distributions of
Perl modules, for example RPM packages (Linux) or PPM files (Windows,
running ActivePerl).


=head2 Creating RPM packages

To create a new binary and source RPM, you typically store the tar.gz
file in F</usr/src/redhat/SOURCES> (F</usr/src/packages/SOURCES> in
case of SuSE and F</usr/src/OpenLinux/SOURCES> in case of Caldera) and
do a

 makerpm --specs --source=<package>-<version>.tar.gz

This will create a SPECS file in F</usr/src/redhat/SPECS>
(F</usr/src/packages/SOURCES> in case of SuSE and
F</usr/src/OpenLinux/SOURCES> in case of Caldera) which you
can use with

 rpm -ba /usr/src/redhat/SPECS/<package>-<version>.spec

If the default behaviour is fine for you, that will do. Otherwise see
the list of options below.


=head2 Creating PPM packages

Not yet implemented


=head2 Command Line Options

Possible command line options are:

=over 8

=item --build

Compile the sources, typically by running

       perl Makefile.PL
       make

=item --build-root=<dir>

Installation of the Perl package occurs into a separate directory, the
build root directory. For example, a package DBI 1.07 could be installed
into F</var/tmp/DBI-1.07>. Binaries are installed into F<$build_root/usr/bin>
rather than F</usr/bin>, man pages in F<$build_root/usr/man> and so on.

The idea is making the build process really reproducible and building the
package without destructing an existing installation.

You don't need to supply a build root directory, a default name is
choosen.

=item --copyright=<msg>

Set the packages copyright message. The default is

 GNU General Public or Artistic License, as specified in the Perl README

=item --debug

Turns on debugging mode. Debugging mode prevents most things from really
being done and implies verbose mode.

=item --help

Print the usage message and exit.

=item --install

Install the sources, typically by running

       make install

Installation doesn't occur into the final destination. Instead a
so-called buildroot directory (for example F</var/tmp/build-root>)
is created and installation is adapted relative to that directory.
See the I<--build-root> option for details.

=item --make=<path>

Set path of the I<make> binary; defaults to the location read from Perl's
Config module. L<Config(3)>.

=item --makeopts=<opts>

Set options for running "make" and "make install"; defaults to none.

=item --makemakeropts=<opts>

If you need certain options for running "perl Makefile.PL", this is
your friend. By default no options are set.

=item --mode=<mode>

Set build mode, for example RPM or PPM. By default the build mode
is read from the script name: If you invoke it as I<makerpm>, then
RPM mode is choosen. When running as I<makeppm>, then PPM mode is
enabled.

=item --package-name=<name>

=item --package-version=<version>

Set the package name and version. These options are required for --build and
--install.

=item --prep

Extract the sources and prepare the source directory.

=item --rpm-base-dir=<dir>

=item --rpm-build-dir=<dir>

=item --rpm-source-dir=<dir>

=item --rpm-specs-dir=<dir>

Sets certain directory names related to RPM mode, defaults to
F</usr/src/redhat> (or F</usr/src/packages> on SuSE Linux or
F</usr/src/OpenLinux> on Caldera) F<$base_dir/BUILD>, F<$base_dir/SOURCES>
and F<$base_dir/SPECS>.

=item --rpm-group=<group>

Sets the RPM group; defaults to Development/Languages/Perl.

=item --setup-dir=<dir>

Name of setup directory; defaults to <package>-<version>. The setup
directory is the name of the directory that is created by extracting
the sources. Example: DBI-1.07.

=item --source=<file>

Source file name; used to determine defaults for --package-name and
--package-version. This option is required for --specs and --prep.

=item --summary=<msg>

Summary line; defaults to "The Perl package <name>".

=item --verbose

Turn on verbose mode. Lots of debugging messages are emitted.

=item --version

Print version string and exit.

=back

=cut


package Distribution;


$Distribution::TMP_DIR = '/tmp';
foreach my $dir (qw(/var/tmp /tmp C:/Windows/temp D:/Windows/temp)) {
   if (-d $dir) {
       $Distribution::TMP_DIR = $dir;
       last;
   }
}

$Distribution::COPYRIGHT = "Artistic or GNU General Public License,"
   . " as specified by the Perl README";


sub new {
   my $proto = shift;
   my $self = { @_ };
   bless($self, ref($proto) || $proto);

   if ($self->{'source'}  &&
       $self->{'source'} =~ /(.*(?:\/|\\))?(.*)-(.+)
                             (\.(tar\.gz|tgz|zip))$/x) {
       $self->{'package-name'} ||= $2;
       $self->{'package-version'} ||= $3;
   }

   $self->{'name'} = $self->{'package-name'}
       or die "Missing package name";
   $self->{'version'} = $self->{'package-version'}
       or die "Missing package version";

   $self->{'source_dirs'} ||= [ File::Spec->curdir() ];
   $self->{'default_setup_dir'} = "$self->{'name'}-$self->{'version'}";
   $self->{'setup-dir'} ||= $self->{'default_setup_dir'};
   $self->{'build_dir'} = File::Spec->curdir();
   $self->{'make'} ||= $Config::Config{'make'};
   $self->{'build-root'} ||= File::Spec->catdir($Distribution::TMP_DIR,
                                                $self->{'setup-dir'});
   $self->{'copyright'} ||= $Distribution::COPYRIGHT;
   $self->{'summary'} ||= "The Perl package $self->{'name'}";

   $self->{'start_perl'} = $self->{'perl-path'}
       || substr($Config::Config{'startperl'}, 2);
   $self->{'start_perl'} = undef if $self->{'start_perl'} eq 'undef';

   $self;
}


sub Extract {
   my $self = shift;  my $dir = shift || File::Spec->curdir();
   print "Changing directory to $dir\n" if $self->{'verbose'};
   chdir $dir || die "Failed to chdir to $dir: $!";

   # Look for the source file
   my $source = $self->{'source'} || die "Missing source definition";
   if (! -f $source) {
       foreach my $dir (@{$self->{'source_dirs'}}) {
           print "Looking for $source in $dir\n" if $self->{'debug'};
           my $s = File::Spec->catfile($dir, $source);
           if (-f $s) {
               print "Found $source in $dir\n" if $self->{'debug'};
               $source = $s;
               last;
           }
       }
   }

   $dir = $self->{'setup-dir'};
   if (-d $dir) {
       print "Removing directory $dir" if $self->{'verbose'};
       File::Path::rmtree($dir, 0, 0) unless $self->{'debug'};
   }

   print "Extracting $source\n" if $self->{'verbose'};
   eval { require Archive::Tar; require Compress::Zlib; };
   if ($@) {
       # Archive::Tar is not available; fallback to tar and gzip
       my $command = "gzip -cd $source | tar xf -";
       my $output = `$command 2>&1`;
       die "Archive::Tar and Compress::Zlib are not available\n"
           . " and using tar and gzip failed.\n"
           . " Command was: $command\n"
           . " Output was: $output\n"
               if $output;
   } else {
       die "Failed to extract archive $source: " . Archive::Tar->error()
           unless defined(Archive::Tar->extract_archive($source));
   }
}

sub Modes {
   my $self = shift; my $dir = shift || File::Spec->curdir();
   print "Changing directory to $dir\n" if $self->{'verbose'};
   chdir $dir || die "Failed to chdir to $dir: $!";
   my $handler = sub {
       my($dev, $ino, $mode, $nlink, $uid, $gid) = stat;
       my $new_mode = 0444;
       $new_mode |= 0200 if $mode & 0200;
       $new_mode |= 0111 if $mode & 0100;
       chmod $new_mode, $_
           or die "Failed to change mode of $File::Find::name: $!";
       chown 0, 0, $_
           or die "Failed to change ownership of $File::Find::name: $!";
   };

   $dir = File::Spec->curdir();
   print "Changing modes in $dir\n" if $self->{'verbose'};
   File::Find::find($handler, $dir);
}

sub Prep {
   my $self = shift;
   my $old_dir = Cwd::cwd();
   eval {
       my $dir = $self->{'build_dir'};
       print "Changing directory to $dir\n" if $self->{'verbose'};
       chdir $dir || die "Failed to chdir to $dir: $!";
       if (-d $self->{'setup-dir'}) {
           print "Removing directory: $self->{'setup-dir'}\n"
               if $self->{'verbose'};
           File::Path::rmtree($self->{'setup-dir'}, 0, 0);
       }
       $self->Extract();
       $self->Modes($self->{'setup-dir'});
   };
   my $status = $@;
   print "Changing directory to $old_dir\n" if $self->{'verbose'};
   chdir $old_dir;
   die $@ if $status;
}

sub PerlMakefilePL {
   my $self = shift; my $dir = shift || File::Spec->curdir();
   print "Changing directory to $dir\n" if $self->{'verbose'};
   chdir $dir || die "Failed to chdir to $dir: $!";
   my $command = "$^X Makefile.PL " . ($self->{'makemakeropts'} || '');
   print "Creating Makefile: $command\n" if $self->{'verbose'};
   exit 1 if system $command;
}

sub Make {
   my $self = shift;
   if (my $dir = shift) {
       print "Changing directory to $dir\n" if $self->{'verbose'};
       chdir $dir || die "Failed to chdir to $dir: $!";
   }
   my $command = "$self->{'make'} " . ($self->{'makeopts'} || '');
   print "Running Make: $command\n";
   exit 1 if system $command;

   if ($self->{'runtests'}) {
       $command .= " test";
       print "Running Make Test: $command\n";
       exit 1 if system $command;
   }
}

sub ReadLocations {
   my %vars;
   my $fh = Symbol::gensym();
   open($fh, "<Makefile") || die "Failed to open Makefile: $!";
   while (my $line = <$fh>) {
       # Skip comments and/or empty lines
       next if $line =~ /^\s*\#/ or $line =~ /^\s*$/;
       if ($line =~ /^\s*(\w+)\s*\=\s*(.*)\s*$/) {
           # Variable definition
           my $var = $1;
           my $val = $2;
           $val =~ s/\$(\w)/defined($vars{$1})?$vars{$1}:''/gse;
           $val =~ s/\$\((\w+)\)/defined($vars{$1})?$vars{$1}:''/gse;
           $val =~ s/\$\{(\w+)\}/defined($vars{$1})?$vars{$1}:''/gse;
           $vars{$var} = $val;
       }
   }
   \%vars;
}

sub AdjustPaths {
   my $self = shift; my $build_root = shift;
   my $adjustPathsSub = sub {
       my $f = $_;
       return unless -f $f && ! -z _;
       my $fh = Symbol::gensym();
       open($fh, "+<$f") or die "Failed to open $File::Find::name: $!";
       local $/ = undef;
       my $contents;
       die "Failed to read $File::Find::name: $!"
           unless defined($contents = <$fh>);
       my $modified;
       if ($self->{'start_perl'}) {
           $contents =~ s/^\#\!(\S+)/\#\!$self->{'start_perl'}/s;
           $modified = 1;
       }
       if ($contents =~ s/\Q$build_root\E//gs) {
           $modified = 1;
       }
       if ($modified) {
           seek($fh, 0, 0) or die "Failed to seek in $File::Find::name: $!";
           (print $fh $contents)
               or die "Failed to write $File::Find::name: $!";
           truncate $fh, length($contents)
               or die "Failed to truncate $File::Find::name: $!";
       }
       close($fh) or die "Failed to close $File::Find::name: $!";
   };
   File::Find::find($adjustPathsSub, $self->{'build-root'});
}


sub MakeInstall {
   my $self = shift;
   if (my $dir = shift) {
       print "Changing directory to $dir\n" if $self->{'verbose'};
       chdir $dir || die "Failed to chdir to $dir: $!";
   }

   my $locations = ReadLocations();

   my $command = "$self->{'make'} " . ($self->{'makeopts'} || '')
       . " install";
   foreach my $key (qw(INSTALLPRIVLIB INSTALLARCHLIB INSTALLSITELIB
                       INSTALLSITEARCH INSTALLBIN INSTALLSCRIPT
                       INSTALLMAN1DIR INSTALLMAN3DIR)) {
       my $d = File::Spec->canonpath(File::Spec->catdir($self->{'build-root'},
                                                        $locations->{$key}));
       $command .= " $key=$d";
   }
   print "Running Make Install: $command\n" if $self->{'verbose'};
   exit 1 if !$self->{'debug'} and system $command;

   print "Adjusting Paths in $self->{'build-root'}\n";
   $self->AdjustPaths($self->{'build-root'});

   my($files, $dirs) = $self->Files($self->{'build-root'});
   my $fileList = '';
   foreach my $dir (sort keys %$dirs) {
       next if $dirs->{$dir};
       $fileList .= "%dir $dir\n";
   }
   foreach my $file (sort keys %$files) {
       $fileList .= "$file\n";
   }

   my($filelist_path, $specs_path) = $self->FileListPath();
   if ($filelist_path) {
       my $fh = Symbol::gensym();
       (open($fh, ">$filelist_path")  and  (print $fh $fileList)
        and  close($fh))
           or  die "Failed to create list of files in $filelist_path: $!";
   }
   $specs_path;
}


sub Build {
   my $self = shift;
   my $old_dir = Cwd::cwd();
   eval {
       my $dir = $self->{'build_dir'};
       print "Changing directory to $dir\n" if $self->{'verbose'};
       chdir $dir || die "Failed to chdir to $dir: $!";
       $self->PerlMakefilePL($self->{'setup-dir'});
       $self->Make();
   };
   my $status = $@;
   chdir $old_dir;
   die $@ if $status;
}

sub CleanBuildRoot {
   my $self = shift; my $dir = shift || die "Missing directory name";
   print "Cleaning build root $dir\n" if $self->{'verbose'};
   File::Path::rmtree($dir, 0, 0) unless $self->{'debug'};
}

sub Install {
   my $self = shift;
   my $old_dir = Cwd::cwd();
   my $filelist;
   eval {
       my $dir = $self->{'build_dir'};
       print "Changing directory to $dir\n" if $self->{'verbose'};
       chdir $dir || die "Failed to chdir to $dir: $!";
       $self->CleanBuildRoot($self->{'build-root'});
       $filelist = $self->MakeInstall($self->{'setup-dir'});
   };
   my $status = $@;
   chdir $old_dir;
   die $@ if $status;
   $filelist;
}


package Distribution::RPM;

@Distribution::RPM::ISA = qw(Distribution);

{
   my($source_dir, $build_dir, $specs_dir);
   sub Init {
       my $proto = shift; my $fatal = shift;
       if (!$source_dir) {
           my $rpm_output = `rpm --showrc`;
           my $rpm_version = `rpm --version`;
           if ($rpm_version =~ /rpm\s+version\s+2\.+/i) {
               foreach my $ref (['specdir', \$specs_dir],
                                ['sourcedir', \$source_dir],
                                ['builddir', \$build_dir]) {
                   my $var = $ref->[0];
                   if ($rpm_output =~ /^$var\s+\S+\s+(.*)/m) {
                       ${$ref->[1]} = $1;
                   }
               }
           } elsif ($rpm_version =~ /rpm\s+version\s+3\.+/i) {
               my $varfunc;
               $varfunc = sub {
                   my $var = shift;
                   my $val;
                   if ($rpm_output =~ /^\S+\s+$var\s+(.*)/m) {
                       $val = $1;
                       while ($val =~ /\%\{(\S+)\}/) {
                           my $vr = $1;
                           my $vl = &$varfunc($vr);
                           if (defined($vl)) {
                               $val =~ s/^\%\{\Q$vr\E\}/$vl/gs;
                           } else {
                               return undef;
                           }
                       }
                       return $val;
                   }
                   return undef;
               };
               foreach my $ref (['_specdir', \$specs_dir],
                                ['_sourcedir', \$source_dir],
                                ['_builddir', \$build_dir]) {
                   ${$ref->[1]} = &$varfunc($ref->[0]);
               }
           }
           die "Cannot handle your RPM version: " . ($rpm_version || "")
               if (!$source_dir or !$specs_dir or !$build_dir) and $fatal;
       }
       my $base_dir = '/usr/src/redhat';
       $source_dir ||= "$base_dir/SOURCES";
       $specs_dir ||= "$base_dir/SPECS";
       $build_dir ||= "$base_dir/BUILD";
       return ($source_dir, $build_dir, $specs_dir);
   }
}

sub new {
   my $proto = shift;
   my $self = $proto->SUPER::new(@_);
   ($self->{'rpm-source-dir'}, $self->{'rpm-build-dir'},
    $self->{'rpm-specs-dir'}) = $proto->Init(1);
   $self->{'rpm-group'} ||= 'Development/Languages/Perl';
   push(@{$self->{'source_dirs'}}, $self->{'rpm-source-dir'});
   $self->{'build_dir'} = $self->{'rpm-build-dir'};
   $self;
}


sub Files {
   my $self = shift;  my $buildRoot = shift;
   my(%files, %dirs);
   my $findSub = sub {
       if (-d $_) {
           $dirs{$File::Find::name} ||= 0;
           $dirs{$File::Find::dir} = 1;
       } elsif (-f _) {
           $files{$File::Find::name} = 1;
           $dirs{$File::Find::dir} = 1;
       } else {
           die "Unknown file type: $File::Find::name";
       }
   };
   File::Find::find($findSub, $buildRoot);

   # Remove the trailing buildRoot
   my(%f, %d);
   while (my($key, $val) = each %files) {
       $key =~ s/^\Q$buildRoot\E//;
       $f{$key} = $val
   }
   while (my($key, $val) = each %dirs) {
       $key =~ s/^\Q$buildRoot\E//;
       $d{$key} = $val
   }
   (\%f, \%d, \%files, \%dirs);
}

sub FileListPath {
   my $self = shift;
   my $fl = $self->{'setup-dir'} . ".rpmfilelist";
   ($fl, File::Spec->catdir($self->{'setup-dir'}, $fl));
}

sub Specs {
   my $self = shift;
   my $old_dir = Cwd::cwd();
   eval {
       $self->Prep();
       $self->Build();
       my $filelist = $self->Install();

       my($files, $dirs) = $self->Files($self->{'build-root'});

       my $specs = <<"EOF";
%define packagename $self->{'name'}
%define packageversion $self->{'version'}
%define release 1
EOF
       my $mo = $self->{'makeopts'} || '';
       $mo =~ s/\n\t/ /sg;
       $specs .= sprintf("%%define makeopts \"%s\"\n",
                         ($mo ? sprintf("--makeopts=%s",
                                        quotemeta($mo)) : ""));
       my $mmo = $self->{'makemakeropts'} || '';
       $mmo =~ s/\n\t/ /sg;
       $specs .= sprintf("%%define makemakeropts \"%s\"\n",
                         ($mmo ? sprintf("--makemakeropts=%s",
                                         quotemeta($mmo)) : ""));
       my $setup_dir = $self->{'setup-dir'} eq $self->{'default_setup_dir'} ?
           "" : " --setup-dir=$self->{'setup-dir'}";

       my $makerpm_path = File::Spec->catdir('$RPM_SOURCE_DIR', 'makerpm.pl');
       $makerpm_path = File::Spec->canonpath($makerpm_path) . $setup_dir .
           " --source=$self->{'source'}";
       $specs .= <<"EOF";

Name:      perl-%{packagename}
Version:   %{packageversion}
Release:   %{release}
Group:     $self->{'rpm-group'}
Source:    $self->{'source'}
Source1:   makerpm.pl
Copyright: $self->{'copyright'}
BuildRoot: $self->{'build-root'}
Provides:  perl-%{packagename}
Summary:   $self->{'summary'}
EOF

       if (my $req = $self->{'require'}) {
           $specs .= "Requires: " . join(" ", @$req) . "\n";
       }

       my $runtests = $self->{'runtests'} ? " --runtests" : "";


       $specs .= <<"EOF";

%description
$self->{'summary'}

%prep
$makerpm_path --prep

%build
$makerpm_path --build$runtests %{makeopts} %{makemakeropts}

%install
rm -rf \$RPM_BUILD_ROOT
$makerpm_path --install %{makeopts}

%clean
rm -rf \$RPM_BUILD_ROOT

%files -f $filelist
EOF

       my $specs_name = "$self->{'name'}-$self->{'version'}.spec";
       my $specs_file = File::Spec->catfile($self->{'rpm-specs-dir'},
                                            $specs_name);
       $specs_file = File::Spec->canonpath($specs_file);
       print "Creating SPECS file $specs_file\n";
       print $specs if $self->{'verbose'};
       unless ($self->{'debug'}) {
           my $fh = Symbol::gensym();
           open(FILE, ">$specs_file") or die "Failed to open $specs_file: $!";
           (print FILE $specs) or die "Failed to write to $specs_file: $!";
           close(FILE) or die "Failed to close $specs_file: $!";
       }
   };
   my $status = $@;
   chdir $old_dir;
   die $@ if $status;
}


package main;

sub Mode {
   return "RPM" if $0 =~ /rpm$/i;
   undef;
}

sub Usage {
   my $mode = Mode() || "undef";
   my $build_root = File::Spec->catdir($Distribution::TMP_DIR,
                                       "<name>-<version>");
   my $start_perl = substr($Config::Config{'startperl'}, 2);

   my ($rpm_source_dir, $rpm_build_dir, $rpm_specs_dir) =
       Distribution::RPM->Init(1);

   print <<EOF;
Usage: $0 <action> [options]

Possible actions are:

 --prep        Prepare the source directory
 --build       Compile the sources
 --install     Install the compiled sources into the buildroot directory
 --specs       Create a SPECS file by performing the above steps in order
               to determine the list of installed files.

Possible options are:

 --build-root=<dir>            Set build-root directory for installation;
                               defaults to $build_root.
 --copyright=<msg>             Set copyright message, defaults to
                               "GNU General Public License or Artistic
                               License, as specified in the Perl README".
 --debug                       Turn on debugging mode
 --help                        Print this message
 --make=<path>                 Set "make" path; defaults to $Config::Config{'make'}
 --makemakeropts=<opts>        Set options for running "perl Makefile.PL";
                               defaults to none.
 --makeopts=<opts>             Set options for running "make" and "make
                               install"; defaults to none.
 --mode=<mode>                 Set build mode, defaults to $mode.
 --package-name=<name>         Set package name.
 --package-version=<name>      Set package version.
 --perl-path=<path>            Perl path to verify in generated scripts;
                               defaults to $start_perl
 --require=<package>           Set prerequisite packages. May be used
                               multiple times.
 --runtests                    By default no "make test" is done. You
                               can override this with --runtests.
 --setup-dir=<dir>             Name of setup directory; defaults to
                               <name>-<version>
 --source=<file>               Source file name; used to determine defaults
                               for <name> and <version>.
 --summary=<msg>               One line desription of the package; defaults
                               to "The Perl package <name>".
 --verbose                     Turn on verbose mode.
 --version                     Print version string and exit.

Options for RPM mode are:

 --rpm-build-dir=<dir>         RPM build directory; defaults to
                               $rpm_build_dir.
 --rpm-group=<group>           RPM group, default Development/Languages/Perl.
 --rpm-source-dir=<dir>        RPM source directory; defaults to
                               $rpm_source_dir.
 --rpm-specs-dir=<dir>         RPM specs directory; defaults to
                               $rpm_specs_dir.

$VERSION
EOF
   exit 1;
}

{
   my %o;
   Getopt::Long::GetOptions(\%o, 'build', 'build-root=s', 'copyright=s',
                            'debug', 'help', 'install', 'make=s',
                            'makemakeropts=s', 'makeopts=s', 'mode=s',
                            'package-name=s', 'package-version=s',
                            'prep', 'require=s@', 'rpm-base-dir=s',
                            'rpm-build-dir=s', 'rpm-source-dir=s',
                            'rpm-specs-dir=s', 'rpm-group=s',
                            'runtests', 'setup-dir=s', 'source=s', 'specs',
                            'summary=s',
                            'verbose', 'version=s');
   Usage() if $o{'help'};
   if ($o{'version'}) { print "$VERSION\n"; exit 1}
   $o{'verbose'} = 1 if $o{'debug'};

   my $class = 'Distribution::RPM';
   if ($o{'mode'}) {
       if ($o{'mode'} ne 'rpm') {
           die "Unknown mode: $o{'mode'}";
       }
   }
   my $self = $class->new(%o);

   if ($o{'prep'}) {
       $self->Prep();
   } elsif ($o{'build'}) {
       $self->Build();
   } elsif ($o{'install'}) {
       $self->Install();
   } elsif ($o{'specs'}) {
       $self->Specs();
   } else {
       die "Missing action";
   }
}


__END__

=pod

=head1 INSTALLATION

Before using this script, you need to install the required packages:

 C<File::Spec>

If you are using Perl 5.00502 or later, then this package is already
part of your Perl installation. It is recommended to use the

 C<Archive::Tar>
 C<Compress::Zlib>

packages, if possible.

All of these packages are available on any CPAN mirror, for example

 ftp://ftp.funet.fi/pub/languages/perl/CPAN/modules/by-module

To install a package, fetch the corresponding distribution file, for
example

 Archive/Archive-Tar-0.21.tar.gz

extract it with

 gzip -cd Archive-Tar-0.21.tar.gz

and install it with

 cd Archive-Tar-0.21
 perl Makefile.PL
 make
 make test
 make install

Alternatively you might try automatic installation via the CPAN module:

 cpan          (until Perl 5.00503 you need: perl -MCPAN -e shell)
 install Archive::Tar
 install Compress::Zlib
 install File::Spec  (only with Perl 5.004 or lower)


=head1 AUTHOR AND COPYRIGHT

This script is Copyright (C) 1999

       Jochen Wiedmann
       Am Eisteich 9
       72555 Metzingen
       Germany

       E-Mail: [email protected]

You may distribute under the terms of either the GNU General Public
License or the Artistic License, as specified in the Perl README.


=head1 CPAN

This file is available as a CPAN script. The following subsections are
for CPAN's automatic link generation and not for humans. You can safely
ignore them.


=head2 SCRIPT CATEGORIES

UNIX/System_administration


=head2 README

This script can be used to build RPM or PPM packages automatically.


=head2 PREREQUISITES

This script requires the C<File::Spec> package.


=head1 TODO

=over 8

=item -

Handling of prerequisites by reading PREREQ_PM from the Makefile

=item -

Support for installation and deinstallation scripts

=item -

Make package relocatable

=item -

Support for %description.

=back


=head1 CHANGES

1999-09-13  Jochen Wiedmann <[email protected]>

     * Modes: Fixed the use of ||= instead of |=; thanks to Tim Potter,
       Tim Potter <[email protected]>
     * Now using %files -f <listfile>

1999-07-22  Jochen Wiedmann <[email protected]>

     * Now falling back to use of "tar" and "gzip", if Archive::Tar and
       Compress::Zlib are not available.
     * Added --runtests, suggested by Seth Chaiklin <[email protected]>.

1999-07-09  Jochen Wiedmann <[email protected]>

     * Now using 'rpm --showrc' to determine RPM's base dirs.

1999-07-01  Jochen Wiedmann  <[email protected]>

     * /usr/src/redhat was used rather than $Distribution::RPM::BASE_DIR.
     * The AdjustPaths function is now handling files zero size files
       properly.
     * An INSTALLATION section was added to the docs that describes
       the installation of prerequisites.
     * A warning for <HANDLE> being possibly "0" is now suppressed with
       Perl 5.004.

1999-05-24  Jochen Wiedmann <[email protected]>

       * Added --perl-path and support for fixing startperl in scripts.
         Some authors don't know how to fix it. :-(

=head1 SEE ALSO

L<ExtUtils::MakeMaker(3)>, L<rpm(1)>, L<ppm(1)>


=cut