#!/usr/bin/perl

# Copyright (C) 1998  Richard Braakman
# 
# 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 of the License, 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, you can find it on the World Wide
# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

sub usage {
    print "Usage: $0 [-k] testset-directory testing-directory\n";
    exit 2;
}

# The -k option means do not stop after one failed test, but try
# them all and report all errors.

# Tests layout:
# Every test package is in a directory pkgname-version in the testset
# directory.  The lintian output that is expected for each package is
# in a file tags.pkgname in the testset directory.

# Running the tests:
# Each test package is copied to a subdirectory of the testing-directory,
# and built there.  Then lintian is run over the resulting .changes file,
# with its output redirected to tags.pkgname in the testing-directory.

# If the tags output is not identical to the tags.pkgname file in the
# testset-directory, then runtests will output the diff and exit with
# a failure code.

# The build output is directed to build.pkgname in the testing-directory.

# Exit codes:
# 0 - success
# 1 - one or more tests failed
# 2 - an error prevented proper running of the tests

# Turns out I might as well have written this in bash.  Oh well.

# --- Parse options, such as they are.
while ($#ARGV >= 0 && $ARGV[0] =~ m/^-/) {
    if ($ARGV[0] eq '-k') {
	$run_all_tests = 1;
    } else {
	usage;
    }
    shift;
}

# --- Parse directory arguments
if ($#ARGV != 1) {
    usage;
}

$testset = shift;
$rundir = shift;

# --- Set and unset environment variables that lintian is sensitive to
$LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
if (not $LINTIAN_ROOT) {
    use Cwd;
    $ENV{'LINTIAN_ROOT'} = $LINTIAN_ROOT = cwd();
}
delete $ENV{'LINTIAN_CFG'};
delete $ENV{'LINTIAN_LAB'};
delete $ENV{'LINTIAN_DIST'};
delete $ENV{'LINTIAN_UNPACK_LEVEL'};

# --- Set the ways to call lintian and dpkg-buildpackage
$lintian_options = '-I';
$dpkg_buildpackage_options = '-rfakeroot -us -uc';
$lintian_path = $ENV{LINTIAN_ROOT} . "/frontend/lintian";

# --- Display output immediately
$| = 1;

# --- Let's play.

-d $rundir
    or fail("test directory $rundir does not exist\n");

opendir(TESTDIR, $testset)
    or fail("cannot open $testset: $!\n");

for (readdir(TESTDIR)) {
    next if $_ eq '.' or $_ eq '..';
    next unless -d "$testset/$_";

    /^([A-Za-z0-9][A-Za-z0-9+.-]+)-([0-9a-zA-Z][0-9a-zA-Z+.:\-]*)/
	or fail("bad directory name $_\n");
    ($pkg, $ver) = ($1, $2);
    $pkgdir = $_;

    print "Running test $pkg $ver... ";

    runsystem_ok("rm -rf $rundir/$pkgdir");
    runsystem("cp -rp $testset/$pkgdir $rundir");
    runsystem("cd $rundir/$pkgdir && dpkg-buildpackage $dpkg_buildpackage_options >../build.$pkg 2>&1");
    runsystem_ok("$lintian_path $lintian_options $rundir/$pkg\_$ver*.changes >$rundir/tags.$pkg");
    $testok = runsystem_ok("cmp -s $rundir/tags.$pkg $testset/tags.$pkg");
    if ($testok) {
	print "done.\n";
    } else {
	print "FAILED:\n";
	runsystem_ok("diff -u $testset/tags.$pkg $rundir/tags.$pkg");
	exit 1 unless $run_all_tests;
    }
}
closedir(TESTDIR);

# --------------
sub fail {
    print STDERR @_;
    exit 2;
}

sub runsystem {
    system(@_) == 0
	or fail("failed: @_\n");
}

sub runsystem_ok {
    my $errcode = system(@_);
    $errcode == 0 or $errcode == (1 << 8)
	or fail("failed: @_\n");
    return $errcode == 0;
}
