#!/usr/bin/perl

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

#
# $Id: gendistrib,v 1.38 2005/03/14 12:47:05 rgarciasuarez Exp $
#

#- Copyright (C) 1999-2005 Mandrakesoft
#-
#- 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.

use strict;
use Cwd;
use URPM;
use URPM::Build;
use Getopt::Long;
use Distribconf::Build;

my $urpm = new URPM;
my $tempdir = -d $ENV{TMPDIR} ? $ENV{TMPDIR} : -d "$ENV{HOME}/tmp" ? "$ENV{HOME}/tmp" : "/tmp";
my $headers_dir = $tempdir . "/.build_hdlist";

sub usage {
	print STDERR <<EOF;
Usage: $0 [options] dir
dir should be the top level of distro
Options:
  --help              print this message and exit
  --compss file       path of compss file (default media/media_info/compss)
  --depslist file     path of depslist file
                      (default media/media_info/depslist.ordered)
  --hdlists file      path of hdlists file (default media/media_info/hdlists)
  --headersdir dir    put temporary files in this dir (default \$TMPDIR)
  --nobadrpm          don't stop on bad rpms
  --skipmissingdir    if a media dir is missing, ignore instead stoping
  --nochkdep          don't search for missing dependencies
  --noclean           keep cache files
  --provides file     path of provides file (default media/media_info/provides)
  --nomediainfo       don't create per-media media_info subdirectories
  --nomd5sum          don't generate MD5SUM files
  -s                  silent mode
EOF
}

my %urpmfiles;

GetOptions(
    'help|h' => sub { usage(); exit },
    'compss=s' => \$urpmfiles{compss},
    'depslist=s' => \$urpmfiles{depslist},
    'distrib=s' => \my $rootdistrib,
    'fermetagueule|s' => \my $nooutput,
    'hdlists=s' => \$urpmfiles{hdlists},
    'mediacfg=s' => \$urpmfiles{mediacfg},
    'headersdir=s' => \$headers_dir,
    'nobadrpm' => \my $dontdie,
    'skipmissingdir' => \my $skipmissingdir,
    'nochkdep' => \my $nochkdep,
    'noclean' => \my $noclean,
    'provides=s' => \$urpmfiles{provides},
    'nomediainfo' => \my $nomediainfo,
    'nomd5sum' => \my $nomd5sum,
);

my @root = grep { $_ } ($rootdistrib, @ARGV);

@root > 0 or do { usage(); exit 1 };

my $distrib = Distribconf::Build->new($root[0]);

$distrib->loadtree or die "$root[0] does not seems to be a distrib tree";

if (defined($urpmfiles{mediacfg})) {
    $distrib->parse_mediacfg($urpmfiles{mediacfg}) or die "Can't read $urpmfiles{mediacfg}";
} elsif (defined($urpmfiles{hdlists})) {
    $distrib->parse_hdlists($urpmfiles{hdlists}) or die "Can't read $urpmfiles{hdlists}";
} else {
    $distrib->parse_mediacfg || $distrib->parse_hdlists or die "Can't read the dsitrib config";
}

my %default_urpmfiles = (
    depslist => $distrib->getfullpath(undef, "infodir") . "/depslist.ordered",
    provides => $distrib->getfullpath(undef, "infodir") . "/provides",
    compss =>   $distrib->getfullpath(undef, "infodir") . "/compss",
    version =>  $distrib->getfullpath(undef, "VERSION"),
    md5sum =>   $distrib->getfullpath(undef, "infodir") . "/MD5SUM",
);

while (my ($k, $v) = each(%default_urpmfiles)) {
    $urpmfiles{$k} ||= $v;
}

$distrib->check(\*STDERR) unless $nooutput;

my @hdlists;
foreach ($distrib->listmedia) {
    $distrib->getvalue($_, 'askmedia') || $distrib->getvalue($_, 'suppl') and next;
    if (! -d ($distrib->getfullpath($_, 'path'))) {
        if ($skipmissingdir) {
            printf STDERR "Skipping missing media %s\n", $distrib->getpath($_, 'path') unless $nooutput;
            next;
        } else {
            die sprintf("Missing dir '%s' for media '%s'", $distrib->getpath($_, 'path'), $distrib->getvalue($_, 'name'));
        }
    }

    push @hdlists, {
        synthesis => $distrib->getfullpath($_, 'synthesis'),
        hdlist => $distrib->getfullpath($_, 'hdlist'),
        dir => $distrib->getpath($_, 'path'),
        descr => $distrib->getvalue($_, 'name'),
        mediainfo => $distrib->getfullpath(undef, 'infodir'),
        thismediainfo => $distrib->getfullpath($_, 'path') . "/media_info",
        synthesis2 => $distrib->getfullpath($_, 'path') . "/media_info/synthesis.hdlist.cz",
        hdlist2 => $distrib->getfullpath($_, 'path') . "/media_info/hdlist.cz",
        md5sum => $distrib->getfullpath($_, 'path') . "/media_info/MD5SUM",
    };
}

sub clean_cache {
    unless ($noclean) {
	system($ENV{LD_LOADER} ? $ENV{LD_LOADER} : @{[]}, "rm", "-rf", $headers_dir);
	mkdir $headers_dir
	    or print STDERR qq(Can't create directory "$headers_dir": $!\n);
    }
}

clean_cache();

foreach (0..$#hdlists) {
    my $e = $hdlists[$_];
    my $r;

    #- try to find the right repository where can be found the directory
    #- listed in the hdlist file.
    #- if the number of root is equal the number of medium, assume a medium
    #- foreach root, else try to find a valid root containing the medium.
    $r ||= $root[0];
    if (scalar(@hdlists) == scalar(@root)) {
	$r = $root[$_];
    } else {
	foreach (@root) {
	    -d "$_/$e->{dir}" and $r = $_, last;
	}
    }

    #- fake build of architecture dependent directory.
    my @files;
    if ($e->{dir} =~ /%{ARCH}/) {
	foreach my $arch (qw(i686 i586 i486 i386 k8 k7 k6 amd64 amd32 x86_64 x86_32 ia64 ia32
                             ppc sparc sparc32 sparc64 alpha noarch)) {
	    my $dir = $e->{dir};
	    $dir =~ s|%{ARCH}|$arch|g;
	    push @files, glob("$r/$dir/*.$arch.rpm");
	}
    } else {
	push @files, glob("$r/$e->{dir}/*.rpm");
    }
    @files or die "unable to find rpm files in $e->{dir}\n";

    print STDERR "parsing rpm files in directory $r/$e->{dir}\n" unless $nooutput;
    my @headers = $urpm->parse_rpms_build_headers(
	dir  => $headers_dir,
	rpms => \@files,
	dontdie => $dontdie,
	silent => $nooutput,
    );
    $e->{headers} = \@headers;
}

#- clean everything to start second pass.
print STDERR "clean data for second pass\n" unless $nooutput;
$urpm->unresolved_provides_clean;

#- temporary file where to build hdlists
my $temp_hdlist = $tempdir . '/hdlist' . $$;
foreach (0..$#hdlists) {
    my $e = $hdlists[$_];

    print STDERR qq(parsing headers for "$e->{descr}"\n) unless $nooutput;
    my ($start, $end) = $urpm->parse_headers(dir     => $headers_dir,
					     headers => $e->{headers},
				             dontdie => $dontdie,
					     silent  => $nooutput);

    print STDERR "computing deps\n" unless $nooutput;
    $urpm->compute_deps;

    print STDERR qq(building hdlist for medium "$e->{descr}"\n) unless $nooutput;
    unlink $temp_hdlist;
    $urpm->build_hdlist(start  => $start,
			end    => $end,
			dir    => $headers_dir,
			hdlist => $temp_hdlist,
			ratio  => 9);
    system('/bin/mv', $temp_hdlist, $e->{hdlist});

    print STDERR qq(building synthesis for medium "$e->{descr}"\n) unless $nooutput;
    $urpm->build_synthesis(start     => $start,
			   end       => $end,
			   synthesis => $e->{synthesis});

    unless ($nomediainfo && $nomd5sum) {
	if (! -d $e->{mediainfo}) {
	    mkdir $e->{mediainfo}, 0755
		or print STDERR qq(Can't create directory "$e->{mediainfo}": $!\n);
	}
    }

    unless ($nomediainfo) {
	if (! -d $e->{thismediainfo}) {
	    mkdir $e->{thismediainfo}, 0755
		or print STDERR qq(Can't create directory "$e->{thismediainfo}": $!\n);
	}
	print STDERR qq(link alternate locations of synthesis and hdlists\n) unless $nooutput;
	unlink $e->{hdlist2}, $e->{synthesis2};
	link $e->{hdlist}, $e->{hdlist2}
	    or print STDERR qq(link failed for "$e->{hdlist2}": $!\n);
	link $e->{synthesis}, $e->{synthesis2}
	    or print STDERR qq(link failed for "$e->{synthesis2}": $!\n);
    }

    unless ($nomd5sum) {
	print STDERR qq(generate media-specific MD5SUM in $e->{thismediainfo}\n);
	my $here = getcwd();
	chdir $e->{thismediainfo};
	my $md5sum = `/usr/bin/md5sum hdlist* synthesis*`;
	if (open my $md5sumfh, '>', $e->{md5sum}) {
	    print $md5sumfh $md5sum;
	    close $md5sumfh;
	} else {
	    print STDERR qq(Can't create "$e->{md5sum}": $!\n);
	}
	chdir $here;
    }
}

clean_cache();

print STDERR "building base files\n" unless $nooutput;
$urpm->build_base_files(
    depslist => $urpmfiles{depslist},
    provides => $urpmfiles{provides},
    compss   => $urpmfiles{compss},
);

my $infodir = $distrib->getpath(undef, 'root') . '/' . $distrib->getpath(undef, 'infodir');
if (-f $infodir . '/media.cfg') {
    if (! -f $infodir . '/hdlists' || ((stat($infodir . '/media.cfg'))[9] > (stat($infodir . '/hdlists'))[9])) {
	print STDERR "Write hdlists file\n" unless $nooutput;
	$distrib->write_hdlists;
    }
}

#- safety cleaning
unlink $urpmfiles{md5sum};
unless ($nomd5sum) {
    my $here = getcwd();
    chdir $distrib->getpath(undef, 'root') . "/" . $distrib->getpath(undef, 'infodir');
    my $md5sum = `/usr/bin/md5sum hdlist* synthesis*`;
    if (open my $md5sumfh, '>', $urpmfiles{md5sum}) {
	print $md5sumfh $md5sum;
	close $md5sumfh;
    } else {
	print STDERR qq(Can't create "$urpmfiles{md5sum}": $!\n);
    }
    chdir $here;
}

print STDERR "Building version file\n" unless $nooutput;
$distrib->write_version($urpmfiles{version});

#- check if there are NOTFOUND in dependencies, check if they are in other media, warn the user.
if ($nooutput || !$nochkdep) {
    foreach (0 .. $#{$urpm->{depslist}}) {
        my $pkg = $urpm->{depslist}[$_];

        foreach (split " ", $urpm->{deps}[$_]) {
	    /NOTFOUND_(.*)/ or next;
	    print STDERR $pkg->fullname . " requires [$1] which\n";
	    if ($urpm->{provides}{$1}) {
	        print STDERR "  is available on packages not listed in this medium or previous medium:\n";
	        foreach (keys %{$urpm->{provides}{$1}}) {
		    my $dep_pkg = $urpm->{depslist}[$_];
		    print STDERR "    " . $dep_pkg->fullname . "\n";
	        }
	    } else {
	        print STDERR "  is not available in any medium listed\n";
	        if (/NOTFOUND_(\D*)(\d+[\.\-\d]*)?(.*)?\.so\./) {
		    my $re = (quotemeta $1) . '(\d+[\.\-\d]*)' . (!$2 && "?") . '\.so\.';
		    foreach (keys %{$urpm->{provides}}) {
		        /$re/ or next;
		        print STDERR "  but a similar provides is available as [$_], need rebuild ?\n";
		    }
	        }
            }
        }
    }
}