The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl 
#
# Myrpm.pl is distributed under the GPL v2 licence terms
# Contact : Jean-Marie Renouard <jmrenouard at gmail.com>
#
# ENLIGHTMENT ROAD
# FEA 13 : config from rpm --showrc
# FEA 16 : autobuild list for install
# FEA 17 : Make a CPAN module
# FEA 18 : Pluginify the solution for other package system
# FEA 19 : Purify the solution
# FEA 20 : Objectify the solution massively

use warnings;
use strict;
#use lib './lib';

use Text::Template;
use Archive::Tar;
use File::stat;
use File::Path;
use Getopt::Long;
use File::Find;
use File::Basename;
use File::Spec;
use Cwd;

use Package::Utils;
use Package::Builder;

sub printUsage($);
sub printError($);

my $version_number = $Package::Builder::VERSION;
printError("Wrong parameter : -N, -V ,-R at least\n$0 -h for help")
  unless ( $#ARGV >= 0 );

my $topdir          = getParameterFromConfig( "_topdir", "/usr/src/redhat" );
my $specDir         = $topdir . "/SPECS";
my $srcDir          = $topdir . "/SOURCES";

######
# Misc declaration section
######
my $line      = "";
my @files     = ();
my @instFiles = ();
my @instDirs  = ();

my @defFiles     = ();
my @defConfFiles = ();
my @defDocFiles  = ();

######
# Command line option section
######
Getopt::Long::Configure('bundling');

my (
    $help,          $build,           $verbose,     $multi,
    $templateName,  $root_dir,        $snap_dir,    $Name,
    $Version,       $Release,         $Description, $Summary,
    $ChangeLog,     $Packager,        $Vendor,      $VendorUrl,
    $Archi,         $Distro,          $archive,     $requires_string,
    $pre_script,    $build_script,    $post_script, $preun_script,
    $postun_script, $exclude_pattern, $uid,         $gid,
    $nodoc,         $noconf,          $nores
);

GetOptions(
    "h"                => \$help,
    "help"             => \$help,
    "b"                => \$build,
    "build"            => \$build,
    "v"                => \$verbose,
    "verbose"          => \$verbose,
    "m"                => \$multi,
    "multiple"         => \$multi,
    "t=s"              => \$templateName,
    "template=s"       => \$templateName,
    "r=s"              => \$root_dir,
    "root-directory=s" => \$root_dir,
    "d=s"              => \$snap_dir,
    "directory=s"      => \$snap_dir,
    "x=s"              => \$exclude_pattern,
    "exclude=s"        => \$exclude_pattern,
    "a=s"              => \$archive,
    "archive=s"        => \$archive,
    "u=s"              => \$uid,
    "uid=s"            => \$uid,
    "g=s"              => \$gid,
    "gid=s"            => \$gid,
    "n"                => \$nodoc,
    "nodoc"            => \$nodoc,
    "c"                => \$noconf,
    "noconfig"         => \$noconf,
    "s"                => \$nores,
    "noreserved"       => \$nores,
    "N=s"              => \$Name,
    "name=s"           => \$Name,
    "V=s"              => \$Version,
    "version=s"        => \$Version,
    "R=s"              => \$Release,
    "release=s"        => \$Release,
    "C=s"              => \$ChangeLog,
    "changelog=s"      => \$ChangeLog,
    "D=s"              => \$Description,
    "description=s"    => \$Description,
    "S=s"              => \$Summary,
    "summary=s"        => \$Summary,
    "P=s"              => \$Packager,
    "packager=s"       => \$Packager,
    "O=s"              => \$Vendor,
    "vendor=s"         => \$Vendor,
    "U=s"              => \$VendorUrl,
    "url-vendor=s"     => \$VendorUrl,
    "A=s"              => \$Archi,
    "architecture=s"   => \$Archi,
    "T=s"              => \$Distro,
    "distribution=s"   => \$Distro,
    "requires=s"       => \$requires_string,
    "pre-script=s"     => \$pre_script,
    "post-script=s"    => \$post_script,
    "preun-script=s"   => \$preun_script,
    "postun-script=s"  => \$postun_script,
    "build-script=s"   => \$build_script
);

printUsage($0) if defined $help;

($templateName) || ( $templateName = shift ) || ( $templateName = "" );
($root_dir)     || ( $root_dir     = shift ) || ( $root_dir     = "" );
$root_dir =~ s/\/$//;

($snap_dir) || ( $snap_dir = shift ) || ( $snap_dir = "" );
$snap_dir =~ s/\/$//;

($exclude_pattern) || ( $exclude_pattern = shift ) || ( $exclude_pattern = "" );

($archive) || ( $archive = shift ) || ( $archive = undef );

($uid) || ( $uid = shift ) || ( $uid = 0 );
($gid) || ( $gid = shift ) || ( $gid = 0 );
($Name) || ( $Name = shift ) || ( printError("Missing -N option : mandatory") );
($Version)
  || ( $Version = shift )
  || ( printError("Missing -V option : mandatory") );
($Release)
  || ( $Release = shift )
  || ( printError("Missing -R option : mandatory") );
($ChangeLog)
  || ( $ChangeLog = shift )
  || ( $ChangeLog = "http://www.123solution.fr - RPM solution provider" );

($Description)
  || ( $Description = shift )
  || ( $Description = "Package $Name-$Version-$Release" );
($Summary)
  || ( $Summary = shift )
  || ( $Summary = "This package is used for $Name-$Version-$Release" );
($Packager)
  || ( $Packager = shift )
  || ( $Packager =
    getParameterFromConfig( "packager", "jmrenouard\@gmail.com" ) );
($Vendor)
  || ( $Vendor = shift )
  || ( $Vendor = getParameterFromConfig( "vendor", "123Solution" ) );
($VendorUrl)
  || ( $VendorUrl = shift )
  || ( $VendorUrl =
    getParameterFromConfig( "vendor_url", "http://www.123solution.fr" ) );
($Archi)
  || ( $Archi = shift )
  || ( $Archi = getParameterFromConfig( "_arch", "noarch" ) );
($Distro)
  || ( $Distro = shift )
  || ( $Distro = getParameterFromConfig( "_dist", "Generic Red Hat" ) );

($pre_script) || ( $pre_script = shift ) || ( $pre_script = "" );
print "\n * pre : $pre_script" if defined $verbose;

($preun_script) || ( $preun_script = shift ) || ( $preun_script = "" );
print "\n * preun : $preun_script" if defined $verbose;

($post_script) || ( $post_script = shift ) || ( $post_script = "" );
print "\n * post : $post_script" if defined $verbose;

($postun_script) || ( $postun_script = shift ) || ( $postun_script = "" );
print "\n * postun : $postun_script" if defined $verbose;

($build_script) || ( $build_script = shift ) || ( $build_script = "" );
print "\n * install : $build_script" if defined $verbose;

($requires_string) || ( $requires_string = shift ) || ( $requires_string = "" );
print "\n * requires info : $requires_string" if defined $verbose;

my @reqs = split( ',', $requires_string );

######
##
######
our @doc_pattern    = () if defined $nodoc;
our @config_pattern = () if defined $noconf;
our @reserved_dirs  = () if defined $nores;

######
# Checking arguments section
######
print "\t * Version : " . $version_number . "\n" if defined $verbose;

my %lusers;
my %lgroups;

#Version
printError("Wrong version format : XX.YY;ZZ, XX.YY, ...")
  unless ( checkVersionFormat $Version );
print "Checking version : $Version: OK\n" if defined $verbose;

#Release
printError("Wrong release format : X without dots")
  unless ( checkReleaseFormat $Release );
print "Checking release : $Release: OK\n" if defined $verbose;

####
# Handling archive mode
####
my $tmp_dir = undef;
if ( defined $archive ) {

    # check archive permissions
    printError("Unable to read archive file $archive") unless -r $archive;

    $snap_dir = extractArchive( $archive, $uid, $gid, $root_dir );

    #Priority for archive option
    $root_dir = $snap_dir;
}

#Checking directory
my $current_dir = getcwd;
$root_dir = trim $current_dir if ( $root_dir =~ /^\.$/ );
print "Root directory : ==>$root_dir<==\n" if defined $verbose;
printError("Root dir doesnt exists or is empty")
  unless ( -d $root_dir || $root_dir eq "" );
print "Checking root_dir OK\n" if defined $verbose;

$snap_dir = trim $current_dir if ( $snap_dir =~ /^\.$/ );
print "Snap directory : ==>$snap_dir<==\n" if defined $verbose;
printError("Snapshot dir doesn t exist or is empty")
  unless ( -d $snap_dir || $snap_dir eq "" );
print "Checking snap_dir OK\n" if defined $verbose;

my @inputFileList = getInputFileLine($snap_dir);

# Pattern exclusion handling
my @exclude_patterns = ();
@exclude_patterns = split /,/, $exclude_pattern if ( $exclude_pattern ne "" );

my %user_infos  = getUserMap();
my %group_infos = getGroupMap();

my %used_users     = ();
my %used_groups    = ();
my %symbolic_links = ();
foreach (@inputFileList) {
    my $line = $_;

    # Removing empty line
    next if ( $line eq "" );

    printError("Unable to read item : $line") unless -r $line || -l $line;

    #Translation of all line starting by a ./something into a absolute path
    $line = File::Spec->rel2abs($line);

    #The root dir is excluded
    next if ( $line eq $root_dir );

    my $pattern_found = 0;
    foreach (@exclude_patterns) {
        if ( $line =~ /$_/ ) {
            $pattern_found = 1;
            print "* Pattern found : $pattern_found for $line\n\n "
              if defined $verbose;
            last;
        }
    }

    next if ( $pattern_found == 1 );

    my $line_chrooted = $line;

    # Removing root_dir entry
    next if ( $line_chrooted eq $root_dir );

    $line_chrooted =~ s/^$root_dir\///;
    print "OK for $line_chrooted" if defined $verbose;

    print "\n* Traitement de '$line'" if defined $verbose;

    #Symbolic link handling
    if ( -l $line ) {
        my $pointedItem = File::Spec->rel2abs( readlink($line) );
        $pointedItem =~ s/^$root_dir\///;
        print "\n * Symbolic link detected : /$line_chrooted => $pointedItem"
          if defined $verbose;

        $symbolic_links{ "/" . $line_chrooted } = $pointedItem;
        next;
    }
    die(" $line does nt exists") unless ( -e $line );

    my $statFile = stat($line);
    my $mode     = $statFile->mode;
    my $uid      = $statFile->uid;
    my $gid      = $statFile->gid;

    print "\n* UID $uid GID : $gid" if defined $verbose;
    $used_users{$uid}++;
    $used_groups{$gid}++;

    print "\n * USED USERS :",  join ',', keys %used_users  if defined $verbose;
    print "\n * USED GROUPS :", join ',', keys %used_groups if defined $verbose;

    print "\n* user=" . $user_infos{$uid}{'name'}   if defined $verbose;
    print "\n* group=" . $group_infos{$gid}{'name'} if defined $verbose;

    my $trueMode = sprintf( "%04o", $mode & 07777 );
    push @files, "./$line_chrooted";
    print "\n\t * $line into Tar ball....\n" if defined $verbose;
    print "\t * $line and $line_chrooted into Spec file....\n"
      if defined $verbose;

    my $final_path = substituteAliasDir("/$line_chrooted");

    my %tmpData = ();
    $tmpData{mode}   = $trueMode;
    $tmpData{file}   = escapeSpecialChars($line_chrooted);
    $tmpData{path}   = escapeSpecialChars($final_path);
    $tmpData{r_path} = $final_path;
    $tmpData{uid}    = $user_infos{$uid}{'name'};
    $tmpData{gid}    = $group_infos{$gid}{'name'};

    #File case
    if ( -f "$line" ) {
        push @instFiles, \%tmpData;

        my $isDoc    = isDocFile("/$line_chrooted");
        my $isConfig = isConfigFile("/$line_chrooted");

        # Fix bug if is config and is doc at the same time
        #Choice to be a config file
        $isDoc = 0 if ( $isDoc && $isConfig );

        push @defFiles, \%tmpData if ( !$isDoc && !$isConfig );
        push @defConfFiles, \%tmpData if ($isConfig);
        push @defDocFiles,  \%tmpData if ($isDoc);
    }

    # Directory case
    # Must not be a reserved directory
    if ( -d "$line" ) {
        $tmpData{comment} = 1 if isReservedDir("/$line_chrooted");
        $tmpData{isDir} = 1;
        push @instDirs, \%tmpData;

        push @defFiles, \%tmpData if ( !isReservedDir("/$line_chrooted") );
    }
}

print "\n * uniq uids :" . join ', ', keys %used_users  if defined $verbose;
print "\n * uniq gids :" . join ', ', keys %used_groups if defined $verbose;

#Handling group creation
my @group_creation = ();
foreach ( keys %used_groups ) {

    #Avoid root group creation
    next if ( $_ == 0 );
    push @group_creation, $group_infos{$_};
}

#Handling user creation
my @user_creation = ();
foreach ( keys %used_users ) {

    #avoid root account :)
    #Avoid root user creation
    next if ( $_ == 0 );
    next if ( $_ < 500 );
    next if ( $user_infos{$_}{'shell'} =~ /nologin/ );
    print "\n*" . $user_infos{$_}{'name'} . " in users $_" if defined $verbose;

    # For all non system account
    # password is the same than user name
    # WARNING : Security issues around this feature
    $user_infos{$_}{init} = 1;
    push @user_creation, $user_infos{$_};
}

my $pre_code = getScriptFileContent($pre_script);

#Handling symbolic link replacement as post install code
my $post_code = getScriptFileContent($post_script);

my $templDef = getSpecTemplate($templateName);

my $template = Text::Template->new(
    SOURCE     => "$templDef",
    TYPE       => 'STRING',
    DELIMITERS => [ "<", ">" ]
) or die "Couldn't construct template: $Text::Template::ERROR";

my %vars = (
    name              => "$Name",
    version           => "$Version",
    release           => "$Release",
    summary           => "$Summary",
    description       => "$Description",
    reqs              => \@reqs,
    packager          => "$Packager",
    vendor            => "$Vendor",
    vendor_url        => "$VendorUrl",
    archi             => "$Archi",
    distro            => "$Distro",
    multiple_packages => defined $multi,
    users             => \@user_creation,
    groups            => \@group_creation,

    #Pre_code must be list
    pre_code => "$pre_code",

    #Post_code must be list
    post_code => "$post_code",

    symbolic_links => \%symbolic_links,
    preun_code     => getScriptFileContent($preun_script),

    postun_code => getScriptFileContent($postun_script),

    build_code => getScriptFileContent($build_script),

    # must be information only
    listOfFiles => \@defFiles,

    # must be information only
    listOfDocFiles => \@defDocFiles,

    # must be information only
    listOfConfFiles => \@defConfFiles,

    instFiles => \@instFiles,
    instDirs  => \@instDirs,

    ChangeLog => $ChangeLog,

    # must be information only
    OldChangeLogs => getChangeLogs("$specDir/$Name.spec"),

    #Avoid system call for portability
    date => trim(`unset LANG && date +"%a %b %d %Y"`)
);

# for debug only
if ( defined $verbose ) {
    use Data::Dumper;
    print Dumper(%vars);
}

my $result = $template->fill_in( HASH => \%vars );

die "Couldn't fill in template: $Text::Template::ERROR"
  unless ( defined $result );

# Chrrooting in fact
if   ( $root_dir eq "" ) { chdir("/") }
else                     { chdir($root_dir); }

#generate Tarball
my $tar = Archive::Tar->new;
foreach my $file (@files) {
    $file =~ s/^\//\.\//;
    print "\n$file to Archive..." if defined $verbose;
    $tar->add_files($file);
}

$tar->write( "$srcDir/$vars{'name'}-$vars{'version'}.tar.gz", 1 );

#Writing spec file
open F, "> $specDir/$vars{'name'}.spec"
  or printError(
"Unable to open $specDir/$vars{'name'}.spec in write mode. please check permissions for this file or directory"
  );
print F $result if defined($result);
print $result if ( defined($result) && $verbose );
close F;

# Cleaning archive tmp dir
if ( defined $archive ) {

    # Create temporary dir
    my $tmp_dir = "/tmp/myrpm/$$";
    eval { rmtree($tmp_dir) };
    if ($@) {
        print "Couldn't create $tmp_dir: $@";
    }
}

#Compiling package

#Avoid system call for portability
my $cmd = "rpmbuild --quiet -ba --target=$Archi $specDir/$vars{'name'}.spec";

print "\n#Executing to build package : $cmd\n" if ($verbose);
print `$cmd`                                   if ($build);
exit 0;

sub printUsage($) {
    print `perldoc $0`;
    exit 0;
}

sub printError($) {
    my $message = join( ' ', @_ );
    print STDERR $message;

    exit 1;
}
__END__

=head1 Usage

myrpm.pl [OPTION]

myrpm.pl is a automatic spec file generator and builder.

Myrpm allow you to install freely software on a rpm compliant system 
and realize a binary package from a list of file. 

This program manages rigths and users. It s a simple tool that simplify 
packaging in chroot mode.

=head1 General Options

 -h, --help				: Print this help.
 -v, --verbose				: Print debug information, verbose mode.
 -m, --multiple				: Split into 3 packages : main, doc and config
 -b, --build				: Build the package automatically at the end.
 -a, --archive=filename			: RPM Creation based on a archive file
 -u, --uid=user id or name		: User id for archive file
 -g, --gid=user id or name		: Group id for archive file
 -n, --nodoc				: Avoid documentation file detection
 -c, --noconfig				: Avoid config file detection
 -s, --noreserved			: Avoid reserved directory
 -t, --template=filename		: Generate the spec skeleton from this template.
 -x, --exclude="pattern1,pattern2"	: Exclude some file patterns.
 -r, --root-directory=<directory>	: Root directory ( / by default ).
 -d, --directory=<directory>		: Directory where is the tree to package
                                  by default, list of files is build from the stdin data

=head1 Package Options 

 -N, --name=<name>			: Package name - This option is mandatory
 -V, --version=<version>		: Package version - This option is mandatory
 -R, --release=<release>		: Package release - This option is mandatory
 -C, --changelog=<changelog>		: Package changeLog
 -D, --description=<description>	: Package Description.
 -S, --summary=<summary>		: Package Summary.
 -P, --packager=<packager>		: Packager identity.
 -U, --vendor-url=<vendor url>		: Vendor URL.
 -O, --vendor=<vendor>			: Vendor name.
 -A, --architecture=<archi>		: Target architecture.
 -T, --distribution=<distro>		: Target distribution.
 --requires=<dependency>,...		: Dependency list.
 --build-script=<filename>		: Script filename to include in the %build session.
 --pre-script=<filename>		: Script filename to include in the %pre session.
 --post-script=<filename>		: Script filename to include in the %post session.
 --preun-script=<filename>		: Script filename to include in the %preun session.
 --postun-script=<filename>		: Script filename to include in the %postun session.

=head1 Examples 

=head2 Realize a kick rpm snapshot of /home/jmrenouard/myrpmBuildDir

myrpm.pl -v -d /home/jmrenouard/myrpmBuildDir -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1 -b

=head2 An other version

cd /home/jmrenouard/myrpmBuildDir && myrpm.pl -v -d . -r . -N toto -V 1.0 -R 1 -b

=head2 The same with UNIX tools interaction

cd /home/jmrenouard/myrpmBuildDir && find `pwd` -iname '*' -print | myrpm.pl -v -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1 -b

find /home/jmrenouard/myrpmBuildDir | myrpm.pl -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1

=head2 Explanations

This script performs the following operations :

Find build the list of all the files in /home/jmrenouard/myrpmBuildDir.

myrpm.pl packages all the files /home/jmrenouard/myrpmBuildDir  in a package with toto as name.

myrpm.pl consider /home/jmrenouard/myrpmBuildDir as the root of all the files so all this files will be installed from the root file system by the rpm program.


=head2 Repackage existing configuration

rpm -ql yum |  myrpm.pl -v -N yum -V 2.7 -R 1_jmr -b

=head2 Explanations

Rpm gives the list of the files in the yum package installed on the system.

myrpm.pl packages all the files in a package with yum as name and 1_jmr as release.

This is a new way to package modification on a installed system.


=head1 Configuration file samples

Myrpm tool is an ecology-friendly configurated.

=head2 Standard $HOME/.rpmmacros sample

 %_topdir	/home/jmrenouard/redhat
 %packager	Jean-Marie Renouard<jmrenouard.externe at pagesjaunes.fr>
 %vendor	Pages Jaunes
 %vendor_url	http://www.pagesjaunes.fr
 %distribution  Red Hat Enterprise 4
 %dist_tag      .1
 %_tmppath   	/var/tmp


=head1 Help to improve this tool

=head2 Submit bugs or remarks at http://code.google.com/p/myrpm/issues/list 

=head2 You can also contact me at Jean-Marie Renouard <jmrenouard at gmail.com>

=head1 Documentation française

=head1 Usage

myrpm.pl [OPTION]

myrpm.pl est un générateur automatique de fichier spec prêt à l'emploi.

Myrpm vous prmet d'installer des logiciel librement sur un système Linux compatible RPM 
et de réaliser des paquets RPMs binaires depuis une liste de fichiers. 

Ce programme gère les droits et les utilisaterus. C'est un outil simple qui simplifie le packaging
en mode non privilégié.

=head1 Options générales

 -h, --help				: Affichage de l'aide en ligne.
 -v, --verbose				: Mode verbeux, affichage d'information de deboggage.
 -b, --build				: Compilation automatique du package.
 -a, --archive=filename			: Création d'un RPM à partir d'une archive
 -u, --uid=user id or name		: Identifiant utilisateur pour l'archive
 -g, --gid=user id or name		: Identifiant de groupe pour l'archive
 -n, --nodoc				: Annulation de la detection des fichiers de documentation 
 -c, --noconfig				: Annulation de la detection des fichiers de configuration
 -s, --noreserved			: Annulation de la detection des repertoires réservés
 -m, --multiple 			: Séparation en 3 packets : principal, doc et config
 -t, --template=filename		: Spécification d'un fichier template aternatif.
 -x, --exclude="pattern1,pattern2"	: Exclusion de certaines formes de fichier.
 -r, --root-directory=<directory>	: Répertoire racine  ( / par défaut ).
 -d, --directory=<directory>		: Répertoire à packager.
                  Par défaut, la liste de fichiers est construite depuis le flux d'entrée standard.


=head1 Options du package RPM 

 -N, --name=<name>			: Nom du package - Option obligatoire.
 -V, --version=<version>		: Version du package - Option obligatoire.
 -R, --release=<release>		: Release du package - Option obligatoire.
 -C, --changelog=<changelog>		: ChangeLog du package
 -D, --description=<description>	: Description du package.
 -S, --summary=<summary>		: Résumé du package.
 -P, --packager=<packager>		: Identité du packageur.
 -U, --vendor-url=<vendor url>		: URL du fournisseur.
 -O, --vendor=<vendor>			: Nom du fournisseur.
 -A, --architecture=<archi>		: Architecture cible.
 -T, --distribution=<distro>		: Distribution cible.
 --requires=<dependency>,...		: Liste des dépendances.
 --build-script=<filename>		: Nom du script à inclure dans la session %build.
 --pre-script=<filename>		: Nom du script à inclure dans la session %pre.
 --post-script=<filename>		: Nom du script à inclure dans la session %post.
 --preun-script=<filename>		: Nom du script à inclure dans la session %preun.
 --postun-script=<filename>		: Nom du script à inclure dans la session %postun.

=head1 Exemples 

=head2 Réalisation rapide d'une image du répertoire /home/jmrenouard/myrpmBuildDir

myrpm.pl -v -d /home/jmrenouard/myrpmBuildDir -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1 -b

=head2 Une autre version

cd /home/jmrenouard/myrpmBuildDir && myrpm.pl -v -d . -r . -N toto -V 1.0 -R 1 -b

=head2 La même avec des interactions avec les outils UNIX

cd /home/jmrenouard/myrpmBuildDir && find `pwd` -iname '*' -print | myrpm.pl -v -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1 -b

find /home/jmrenouard/myrpmBuildDir | myrpm.pl -r /home/jmrenouard/myrpmBuildDir -N toto -V 1.0 -R 1

=head2 Explications

Le script réalise les opérations suivantes :

Find construit la liste de tous les fichiers contenus dans le répertoie /home/jmrenouard/myrpmBuildDir.

myrpm.pl packages  tous les fichiers du répertoie /home/jmrenouard/myrpmBuildDir dans le package ayant toto comme nom, 1.0 comme version et 1 comme release.

myrpm.pl considère /home/jmrenouard/myrpmBuildDir comme répertoire root ( / ) si bien que tous les fichiers seront installé à la racine par le programme rpm.


=head2 Repackager une configuration existante

rpm -ql yum |  myrpm.pl -v -N yum -V 2.7 -R 1_jmr -b

=head2 Explications

Rpm donne la liste des fichiers du package Yum installé sur le système.

myrpm.pl packages tous les fichiers de ce package dans un nouveau package avec yum comme nom.

Il s'agit d'un nouveau moyen de packager des modifications depuis un système installé.


=head1 Exemple de fichier de configuration

Myrpm utilise le fichier utilisateur pour configurer les valeurs par défaut.

=head2 Exemples de $HOME/.rpmmacros standard

 %_topdir	/home/jmrenouard/redhat
 %packager	Jean-Marie Renouard<jmrenouard.externe at pagesjaunes.fr>
 %vendor	Pages Jaunes
 %vendor_url	http://www.pagesjaunes.fr
 %distribution  Red Hat Enterprise 4
 %dist_tag      .1
 %_tmppath   	/var/tmp

=head1 Aide à l'amélioration du produit

=head2 Merci de soumettre les erreurs et les remarques sur http://code.google.com/p/myrpm/issues/list 

=head2 Vous pouvez contactez Jean-Marie Renouard <jmrenouard at gmail.com> pour plus de détails.