package Mkcd::Package;

our $VERSION = '0.0.4';

use File::NCopy qw(copy);       
use File::Path;       
use rpmtools;
use Mkcd::Tools qw(du cleanrpmsrate printDiscsFile);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(packageOutOfRpmsrate genDeps getLeaves getRPMsKeys getSize rpmVersionCompare);

=head1 NAME

Packages - mkcd module

=head1 SYNOPSYS

    require Mkcd::Functions;

=head1 DESCRIPTION

C<Mkcd::Functions> include the mkcd low level packages functions.

=head1 SEE ALSO

mkcd

=head1 COPYRIGHT

Copyright (C) 2000,2001 MandrakeSoft <warly@mandrakesoft.com>

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

my %ARCH = ( 
    i586 => 1,
    noarch => 1,
    k7 => 1,
    ppc => 1,
    ia64 => 1,
    i686 => 2,
    i486 => 2,
    i386 => 3
);

sub genDeps{
    my ($top,$reps,$deps,$VERBOSE,$TMP) = @_;
    $top or print "ERROR: no top dir defined\n" and return 0;
    -d $top or mkpath $top or die "Could not create $top\n";
    $VERBOSE and print "REPS @$reps ($top/depslist.ordered)\n";
    my $params = new rpmtools("sourcerpm");
    my @reps = @$reps;
    if ($deps || ! -f "$top/depslist.ordered") {
	map { $_ and $_ .= "/*.rpm"} @reps;
	$VERBOSE and print "MAP : @reps\n";
	my @rpms;
	my %done;
	foreach (map glob, @reps){
	    /src.rpm$/ and next;
	    m,([^/]+)$,;
	    $done{$1} and next;
	    push @rpms, $_;
	    $done{$1} = 1
	}
	$params->build_hdlist(1, 9,"$TMP/.mkcd_build_hdlist", "$top/hdlist.cz", @rpms);
	$params->clean();
	print "generating base files\n";
	if (-r "$top/provides") {
	    open F, "$top/provides";
	    $params->read_provides_files(\*F);
	    close F;
	}

	$params->read_hdlists("$top/hdlist.cz");
	$params->compute_depslist();

	my @unresolved = $params->get_unresolved_provides_files();
	if (@unresolved > 0) {
	    $params->clean();

	    $params->read_hdlists("$top/hdlist.cz");
	    $params->keep_only_cleaned_provides_files();
	    $params->read_hdlists("$top/hdlist.cz");
	    $params->compute_depslist();
	}
	# reorder the hdlist not needed for this
	# $params->build_hdlist(1, "$tmp/.mkcd_build_hdlist", "$top/hdlist.cz", map (glob, map( { $_ and $_ .= "/*.rpm"}  map( {ref and @$_ } @$reps))));
	print "writing $top/depslits.ordered\n";
	open F, ">$top/depslist.ordered" or die "unable to write depslist file $top/depslist.ordered\n";
	$params->write_depslist(\*F);
	close F;
	print "writing $top/provides\n";
	open F, ">$top/provides" or die "unable to write provides file $top/provides\n";
	$params->write_provides(\*F);
	close F;
    } else {
	# TODO must create a real read_depslist function that really recreate a depslist with a file.
	$params->read_provides_files("$top/provides");
	$params->read_hdlists("$top/hdlist.cz");
	#
	# FIXME read_hdlist is not enough and cannot be user to set params deps
	#	$params->read_depslist("$top/depslist.ordered");
	$params->compute_depslist();
	my @unresolved = $params->get_unresolved_provides_files();
	if (@unresolved > 0) {
	    $params->clean();
	    $params->read_hdlists("$top/hdlist.cz");
	    $params->keep_only_cleaned_provides_files();
	    $params->read_hdlists("$top/hdlist.cz");
	    $params->compute_depslist();
	}
    }
    return $params
}

sub packageOutOfRpmsrate{
    my ($rpmsrate) = @_;
    my $rate = cleanrpmsrate($rpmsrate);
    print join("\n",sort(keys %$rate)),"\n";
    1
}

sub getLeaves {
    my ($depslist) = @_;
    open DEP, "$depslist" or die "Could not open $depslist\n";
    my @name;
    my %pkg;
    my $i = 0;
    foreach (<DEP>){
	chomp;
	my ($name, undef, @de) = split " ", $_;	
	($name, my $version, my $release) = $name =~ /(.*)-([^-]*)-([^-]*)/;
	if ($name){
	    foreach my $d (@de) {
		if ($d !~ s/^NOTFOUND_//) { 
		    my @t = split '\|',$d ; 
		    foreach my $t (@t) { if ($t !~ s/NOTFOUND_//) { $pkg{$name[$t]}++ }}
		}else { $pkg{$name[$d]}++}
	    }
	}
	$name[$i] = $name;
	$pkg{$name[$i]}++;
	$i++;
    }
    foreach (sort keys %pkg){
	print $pkg{$_} - 1, " $_\n";
    }
    1
}

sub getRpmsrate{
    print "ERROR: this function is deprecated\n";
    return 0;

    my ($rpmsrate,$reps,$tmp,$name,$VERBOSE) = @_;
    my $TMP = $tmp || $ENV{TMPDIR};
    my $tmprpmsrate = "$TMP/$name/rpmsrate";
    local *R; open R, ">$tmprpmsrate" or print "ERROR: cannot open temporary rpmsrate file $tmprpmsrate\n";
    my $rate = Mkcd::Tools::cleanrpmsrate($rpmsrate,*R,@$reps);
    close R;
    unlink "$rpmsrate" and copy "$tmprpmsrate", "$rpmsrate";
    local *R; open R, "$rpmsrate" or print "ERROR: cannot open rpmsrate file $rpmsrate\n";
#    my $rate;
#    my $data;
#    my $current;
#   my $max;
#    while (<R>){
#	s/#.*//; # comments
#	/^\s*$/ and next;
#	if (/^(\S+)/) {
#	    $current = $1;
#	    next
#	}
#	my ($indent,$r,$flags,$data) = /^(\s*)([1-5]?)(\s*(?:(?:!\s*)?[0-9A-Z_]+(?:"[^"]*")?(?:\s+(?:\|\|\s+)?)*)*\s*)(.*)$/;
#	$rate = $r > 0 ? $r : $rate;
#	$VERBOSE and print "getRpmsrate: current $current ($flags)\n";
#	$data or next;
#	my @k = split ' ', $data;
#	$VERBOSE and print "getRpmsrate @k ($rate)\n";
#	$rate > $max and $max = $rate;
#	@rate{@k} = map $rate, @k;
#	print "DEBUG @k\n";
#	push @{$section{$current}}, @k
#    }
    [$rate->[0],$rate->[1]];
}

# sub getreps{
#     my ($lists) = @_;
#    my @reps;
#    foreach my $i (@{$lists}){
#	my (undef,undef,undef,undef,@list) = @{$config[2][$i][0]};
#	foreach (@list){
#	    my $t = $config[1][$i];
#	    ref $t or next;
#	    foreach (@{$t->[1]}) { 
#		$VERBOSE and print "REPOSITORY $_->[1] -- $_->[2]\n";
#		push @{$reps[$i]} , $_->[0] }
#	}
#    }
#    return (\@reps)
#}

sub getRPMsKeys{
    my ($list,@hdlist) = @_;
    my %keys;
    foreach (@hdlist){
	my $packer = new packdrake($_);
	my $count = scalar keys %{$packer->{data}};
	print "$count files in archive, uncompression method is \"$packer->{uncompress}\"\n";
	foreach my $file (@{$packer->{files}}) {
	    if ($file =~ /(.*):(.*)/){
		$keys{rpm}{$1} = $2;
		$keys{key}{$2} = $1
	    }else{
		$keys{rpm}{$file} = $file;
		$keys{key}{$file} = $file
	    }
	    $list and printf "l %13c %s -> %s\n", ' ', $file, $packer->{data}{$file}[1]
	}
    }
    return \%keys
}

sub getSize{
    my ($group,$config,$VERBOSE) = @_;
    my $max;
    my $redeps;
    foreach my $listnumber (keys %{$group->{list}}){
	print "getSize list $listnumber\n";
	my $repnb;
	$group->{nodeps}{$listnumber} and next;
	#$config[1][$listnumber][2]{done} and next;
	my $testarch = join '|', keys %ARCH;
	foreach (@{$config->{list}[$listnumber]{packages}}) {
	    $repnb++;
	    my ($dir, @srpms) = @{$_};
	    $VERBOSE and print "getSize DIRECTORY $dir\n";
	    local *RPMS; opendir RPMS, $dir or print "WARNING: getSize: cannot open $dir\n" and next;
	    foreach (readdir RPMS){
		/(.*)\.rpm$/ or next;
		/src\.rpm$/ and next;
		my $rpm = $group->{rpmkey}{key}{$1} or print "$1 not in depslist, forcing rebuilt\n" and return 2;
		my $b = Mkcd::Tools::du("$dir/$_");
		$b or print "ERROR getSize: $rpm has a zero size\n";
		ref $group->{size}{$rpm}{$listnumber} and print "ERROR getSize: duplicate $rpm in list $listnumber, ignoring\n" and next;
		$group->{size}{$rpm}{$listnumber} = [$b,$dir,$repnb];
		push @{$group->{listrpm}{$listnumber}}, $rpm;
		$group->{listsize}{$listnumber}{rpm} += $b;
		$b > $max and $max = $b;
	    }
	    foreach $dir (@srpms){
		$VERBOSE and print "getSize DIRECTORY $dir\n";
		local *SRPMS; opendir SRPMS, $dir or print "WARNING: getSize: cannot open $dir\n" and next;
		foreach (readdir SRPMS){
		    /\.rpm$/ or next;
		    /($testarch)\.rpm$/ and next;
		    my ($srpm,$srpmname,$key);
		    if (($srpm,$srpmname) = /((.*)-[^-]*-[^-]*\.src)\.rpm$/){
			$key = $srpm;
		    }else {
			($key) = /(.*)\.rpm$/;
			my %header;
			tie %header, "RPM::Header", "$dir/$_" or print "ERROR getSize: $RPM::err" and next;
			$header{'SOURCERPM'} eq "(none)" or next;
			$srpmname = $header{'NAME'};
			$srpm = "$srpmname-$header{'VERSION'}-$header{'RELEASE'}.src";
		    }
		    $group->{rpmkey}{key}{$key} = $srpm; 
		    $group->{rpmkey}{rpm}{$srpm} = $key; 
		    my $b = Mkcd::Tools::du("$dir/$_");
		    $b or print "ERROR getSize: $srpm has a zero size\n";
		    ref $group->{size}{$srpm}{$listnumber} and print "ERROR getSize: duplicate $srpm in list $listnumber, ignoring\n" and next;
		    $group->{size}{$srpm}{$listnumber} = [$b,$dir,$repnb];
		    $group->{srpmname}{$srpmname} = $srpm;
		}
	    }
	}
    }
    $group->{maxsize} = $max;
    1
}

sub rpmVersionCompare{
    my ($pkg1, $pkg2) = @_;
    my ($n1,$v1,$r1,$a1) = $pkg1 =~ /^(.*)-([^-]+)-([^-]+)\.([^.]+)(\.rpm)?$/;
    my ($n2,$v2,$r2,$a2) = $pkg2 =~ /^(.*)-([^-]+)-([^-]+)\.([^.]+)(\.rpm)?$/;
    die "ERROR rpmVersionCompare: trying to compare version of two differently named packages ($pkg1,$pkg2)\n" if (!($n1 eq $n2)) ;
    my $ret = rpmtools::version_compare($v1,$v2);
    if ($ret){
	return $ret
    }else{
	$ret = rpmtools::version_compare($r1,$r2);
	if ($ret){
	    return $ret
	}else{
	    if($ARCH{$a1} < $ARCH{$a2}){
		return -1 
	    }elsif($ARCH{$a1} > $ARCH{$a2}){
		return 1
	    }else{
		return 0
	    }
	}
    }
}


1
