#!/usr/bin/perl

eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell

use strict;
use warnings;
use MDV::Distribconf::Build;
use Getopt::Long;
use Pod::Usage;

my $VERSION = '0.02';

my %urpmfiles;

=head1 NAME

gendistrib - generates a mirror tree for a distribution

=head1 SYNOPSIS

    gendistrib [options] directory

=head1 OPTIONS

=over 4

=item --blind

Always rebuild indexes, without checking whether it's needed.

=item --compss file

Path of F<compss> file (defaults to F<media/media_info/compss>).

=item --depslist file

Path of F<depslist> file (defaults to F<media/media_info/depslist.ordered>).

=item --destdir dir

Create all new files in the specified directory. All subdirectories should
exist. This option is mostly useful for testing, or while using a read-only
repository.

=item --hdlists file

Path of the F<hdlists> file (defaults to F<media/media_info/hdlists>)

=item --headersdir dir

Put temporary files in this directory (defaults to TMPDIR).

=item --mediacfg file

Use the specified F<media.cfg> file (defaults to F<media/media_info/media.cfg>).

=item --nobadrpm

Don't abort when encountering bad rpms.

=item --chkdep

Search for missing dependencies.

=item --noclean

Keep cache files.

=item --noemptymedia

Stop and abort if an empty media is found.

=item --nomd5sum

Don't generate MD5SUM files.

=item --nomediainfo

Don't create per-media F<media_info> subdirectories.

=item --provides file

Path of F<provides> file (defaults to F<media/media_info/provides>)

=item --skipmissingdir

If a media dir is missing, ignore it instead of aborting.

=item -s

Silent mode.

=back

=cut

GetOptions(
    'blind'          => \my $blind,
    'compss=s'       => \$urpmfiles{compss},
    'depslist=s'     => \$urpmfiles{depslist},
    'destdir=s'      => \my $destdir,
    'hdlists=s'      => \$urpmfiles{hdlists},
    'headersdir=s'   => \my $headers_dir,
    'help|h'         => \&usage,
    'mediacfg=s'     => \$urpmfiles{mediacfg},
    'nobadrpm'       => \my $dontdie,
    'nochkdep'       => \my $nochkdep,           # compatibility, default now
    'chkdep'         => \my $chkdep,
    'noclean'        => \my $noclean,
    'noemptymedia'   => \my $noemptymedia,
    'nomd5sum'       => \my $nomd5sum,
    'nomediainfo'    => \my $nomediainfo,
    'provides=s'     => \$urpmfiles{provides},
    'skipmissingdir' => \my $skipmissingdir,
    's'              => \my $nooutput,
    'v|version' => sub { warn "$0 version $VERSION\n"; exit 0 },
    'h|help' => sub { pod2usage(0) },
    'fork'   => \my $fork,
) or pod2usage();

my @distrib;

foreach (@ARGV) {
    my $mdg = MDV::Distribconf::Build->new($_);
    if ( !$mdg->loadtree() ) {
        printf STDERR "%s seems to no contains any distrib... skipping\n",
          $mdg->getfullpath( undef, 'root' );
        next;
    }
    else {

        if ( defined( $urpmfiles{mediacfg} ) ) {
            $mdg->parse_mediacfg( $urpmfiles{mediacfg} ) or do {
                print STDERR "Can't read $urpmfiles{mediacfg}\n";
                next;
            };
        }
        elsif ( defined( $urpmfiles{hdlists} ) ) {
            $mdg->parse_hdlists( $urpmfiles{hdlists} ) or do {
                print STDERR "Can't read $urpmfiles{hdlists}\n";
                next;
            };
        }
        else {
            $mdg->parse_mediacfg || $mdg->parse_hdlists or do {
                print STDERR "Can't read the distrib config\n";
                next;
            };
        }

        # Error which are fatale
        my @fatal = qw(SAME_INDEX);
        push( @fatal, 'MISSING_MEDIADIR' ) unless ($skipmissingdir);
        my @IGNORE = qw(MISSING_INDEX);
        my ( @fatalerrors, @errors, $have_misssing_dir )
          ;    # fatales error show at the end
        $mdg->check(
            sub {
                my %info = @_;
                grep { $_ eq $info{errcode} } @IGNORE and return;
                $have_misssing_dir = 1
                  if ( $info{errcode} eq 'MISSING_MEDIADIR' );
                if ( grep { $_ eq $info{errcode} } @fatal ) {
                    push( @fatalerrors, "$info{level}: $info{message}" );
                }
                else {
                    push( @errors, "$info{level}: $info{message}" )
                      unless ($nooutput);
                }
            }
        );
        if ( @errors || @fatalerrors ) {
            printf STDERR "Errors found while checking %s:\n", $mdg->{root};
            print "$_\n" foreach (@errors);
        }
        if (@fatalerrors) {
            printf STDERR <<EOF;

Fatal error detected, continue is likely to produce an invalid tree.
Fix this erreur in media.cfg and retry:
EOF
            print STDERR "$_\n" foreach (@fatalerrors);
            print STDERR
              "(Missing directory can ignore with --skipmissingdir.)\n"
              if ($have_misssing_dir);
            print STDERR "skipping...\n";
            next;
        }
    }

    push( @distrib, $mdg );
}

foreach my $mdg (@distrib) {
    printf(
        "\nReindexing distrib in %s (%s for %s)\n",
        $mdg->getpath( undef, 'root' ),
        $mdg->getvalue( undef, 'version' ),
        $mdg->getvalue( undef, 'arch' ),
    ) unless ($nooutput);

    $mdg->load_all_medias();

    my $mustdie = 0;
    if ($fork) {
        $mdg->push_temp_files();
        $mdg->link_index_to_distrib();
        my $pid = fork();
        if ( defined($pid) ) {
            if ($pid) {
                $mdg->{noclean} = 1;
                next;
            }
            else {
                $mustdie = 1;
            }
        }
    }

    if ( $mdg->list_unsynch_medias() ) {
        printf "Performing second pass (%s for %s)\n",
          $mdg->getvalue( undef, 'version' ), $mdg->getvalue( undef, 'arch' )
          unless ($nooutput);

        $mdg->populate_all_medias();

        $mdg->generate_base_files();

        $mdg->push_temp_files();

        $mdg->link_index_to_distrib();
        $mdg->rebuild_md5();
        $mdg->set_all_medias_size();
        $mdg->write_mediacfg();
        $mdg->write_hdlists();
        $mdg->write_productid();
        $mdg->write_version();
    }
    else {
        print "No media change, end\n" unless ($nooutput);
    }

    if ($mustdie) {
        exit(0);
    }
}

__END__

=head1 DESCRIPTION

F<gendistrib> is a tool that helps to generate the structure of a Mandriva
RPM repository, compatible with Mandriva tools (F<urpmi>, F<rpmdrake>,
etc.)

=head2 General Structure of a Repository

A typical repository, under a root directory F</ROOT/>, has the following
structure:

    ROOT/ - media/
	    |- contrib/
	    |   `- media_info/
	    |- main/
	    |   `- media_info/
	    `- media_info/

In this example, we have two media, called I<main> and I<contrib>. The
RPMs packages are placed in the F<main> and F<contrib> subdirectories.
Repository metadata is contained in the top-level F<media_info> directory.
Per-media metadata are contained in the F<main/media_info> and
F<contrib/media_info> subdirectories.

=head2 Configuration of the distribution tree

Before using F<gendistrib>, you must create a file F<media_info/media.cfg>
to describe your repository. (An empty file will work, but this isn't
recommended.) The syntax of this file is reminiscent of F<.ini> files.

A first section C<[media_info]> contains global information about the
repository:

    [media_info]
    version=2006.0
    branch=Cooker
    arch=i586

Then, supply one section per media.

    [main]
    hdlist=hdlist_main.cz
    name=Main

Here, the C<hdlist> parameter specifies what will be the name of the
hdlist file in the top-level F<media_info> directory. C<name> is a human
readable label for the media.

=head2 Operation

F<gendistrib> should be passed the F<ROOT> directory as parameter. It will
then generate the hdlist and synthesis files and all other files needed
for proper repository operation.

F<gendistrib> will also verify any broken dependencies in your repository
and report them.

=head1 SEE ALSO

genhdlist(1), and MDV::Distribconf(3) for description of the format of the
F<media.cfg> file.

=head1 COPYRIGHT

Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA

Copyright (C) 2005, 2006 Mandriva SA

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

=cut
