#!/usr/bin/perl -w
#
# which_deb
#
# Simple helper tool to find the appropriate version of a package in
# the archive to meet a requirement in the debian-cd build

use strict;
use List::Util qw{first};

my ($mirror, $codename, $pkg, $pth, $output, $text_out);

$mirror = shift;
$codename = shift;
$pkg = shift;
$output = shift;
$pth = "$mirror/dists/$codename";
$text_out = "";

my @components = qw(main);
push @components, 'contrib' if $ENV{CONTRIB};
push @components, 'non-free' if $ENV{NONFREE};
push @components, 'local' if $ENV{LOCAL};

if (!defined ($output)) {
    $output = "binary";
}

# Give preference to i386 and amd64, if specified
my @ARCHES;
if ( $ENV{ARCHES} ) {
    push @ARCHES, 'i386' if $ENV{ARCHES} =~ /(^|\s)i386(\s|$)/;
    push @ARCHES, 'amd64' if $ENV{ARCHES} =~ /(^|\s)amd64(\s|$)/;
    push @ARCHES, grep { !/^(source|i386|amd64)$/ } split /\s+/, $ENV{ARCHES};
}

# We seem to be building a source-only CD. Check for whatever binary
# arches exist in the archive; #695244
if (!@ARCHES) {
        my %found_arches;
        my $dh;
        for my $component(@components) {
                opendir ($dh, "$pth/$component");
                if ($dh) {
                        while (my $entry = readdir $dh) {
                                $entry =~ /^binary-(.*)/ and $1 !~ /all/ and $found_arches{$1} = 1;
                        }
                }
                close $dh;
        }
        if ($found_arches{"i386"}) {
                push @ARCHES, 'i386';
        }
        if ($found_arches{"amd64"}) {
                push @ARCHES, 'amd64';
        }
        for my $arch (sort keys %found_arches) {                
                push @ARCHES, $arch;
        }
}

sub grab_bin_info {
    my $pth = shift;
    my $arch = shift;
    my $pkgname = shift;
    my $old_split = $/;
    my $match;
    my $result = "";
    
    $/ = ''; # Browse by paragraph    

    for my $component ( @components ) {
        my $pgz = "$pth/$component/binary-$arch/Packages.gz";
        if ( $component eq 'local' and $ENV{LOCALDEBS} ) {
            $pgz = "$ENV{LOCALDEBS}/dists/$codename/local/binary-$arch/Packages.gz";
        }
        my $pxz = "$pth/$component/binary-$arch/Packages.xz";
        if ( $component eq 'local' and $ENV{LOCALDEBS} ) {
            $pxz = "$ENV{LOCALDEBS}/dists/$codename/local/binary-$arch/Packages.xz";
        }
        if (-e $pgz) {
            open(PFILE, "zcat $pgz |") or
                die "Failed to read Packages file $pgz";
	} elsif (-e $pxz) {
            open(PFILE, "xzcat $pxz |") or
                die "Failed to read Packages file $pxz";
	} else {
	    die "Can't find a working Packages file, tried $pgz and $pxz\n";
	}
	while (defined($match = <PFILE>)) {
	    if (($match =~ /^Package: \Q$pkgname\E$/m)) {
		$result = $match;
		close PFILE;
		return $result;
	    }
	}
	close PFILE;
    }
    return "";
}

sub grab_src_info {
    my $pth = shift;
    my $pkgname = shift;
    my $old_split = $/;
    my $match;
    my $result = "";
    
    $/ = ''; # Browse by paragraph    

    for my $component ( @components ) {
        my $pgz = "$pth/$component/source/Sources.gz";
        my $pxz = "$pth/$component/source/Sources.xz";

        if (-e $pgz) {
            open(PFILE, "zcat $pgz |") or
                die "Failed to read Sources file $pgz";
        } elsif (-e $pxz) {
            open(PFILE, "xzcat $pxz |") or
                die "Failed to read Sources file $pxz";
	} else {
	    die "Can't find a working Sources file, tried $pgz and $pxz\n";
	}
	while (defined($match = <PFILE>)) {
	    if (($match =~ /^Package: \Q$pkgname\E$/m)) {
		$result = "$result" . $match;
	    }
	}
	close PFILE;
    }
    return $result;
}

my $bin_deb = "";
my $pkgdata = "";
my $srcname = "";

if ($pkg eq "syslinux") {
    first { $pkgdata = grab_bin_info($pth, $_, "syslinux-common") } @ARCHES;
    if (length($pkgdata) < 3) {
        first { $pkgdata = grab_bin_info($pth, $_, "syslinux") } @ARCHES;
    }
} elsif ($pkg eq "delo") {
    $pkgdata = grab_bin_info($pth, "mipsel", $pkg);
} else { # Fallthrough for all other packages
    first { $pkgdata = grab_bin_info($pth, $_, $pkg) } @ARCHES;
}

if (length($pkgdata) > 2) {
    if ($output eq "binary") {
        $pkgdata =~ m/^Filename: (\S+)/m and $bin_deb = $1;
	$text_out = "$bin_deb\n";
    }
    elsif ($output eq "source") {
        $srcname = $pkg;
        $pkgdata =~ m/^Source: (\S+)/m and $srcname = $1;
        $pkgdata = grab_src_info($pth, $srcname);
        if (length($pkgdata) > 2) {
            my $dir;
            $pkgdata =~ m/^Directory: (\S+)/m and $dir = $1;
            # Explicitly use the md5 lines in the Sources stanza, hence the xdigit(32) here
            while ($pkgdata =~ m/^ ([[:xdigit:]]{32}) (\d+) (\S+)/msg) {
		$text_out = $text_out . "$dir/$3\n";
	    }
        }
    }
}

if (length($text_out) < 2) {
    die "which_deb: can't find $output file(s) for $pkg in $codename\n";
}

print $text_out;
