#!/usr/bin/perl -w

use strict;
use warnings;
use File::Basename;
use File::Path qw(make_path remove_tree);
use File::Temp qw/tempfile tempdir/;
use RPM::Source::Tools::RPM2CpioUnpack qw(rpm2cpio_unpack1 rpm2cpio_unpack2 rpm2cpio_fakeroot_unpack2);

use Test::Repocop::Workdir;
use Test::Repocop::Log;
use Test::Repocop::PkgId;
use Test::Repocop::Common;
use Test::Repocop::PkgId;
use Test::Repocop::SQL;
use Test::Repocop::RPMdb;
use Test::Repocop::TestDB;
use Test::Repocop::CLI::Base;
use Test::Repocop::CLI::Datadir;
our @ISA=qw/Test::Repocop::CLI/;
our @LONGOPT_POD2USAGE=qw/-verbose 1 -exitval 1/;

$Test::Repocop::Log::verbose=1;
my ($repocop_use_fakeroot,$repocop_opt_skip_big_binary,$repocop_opt_skip_big_source);
my ($repocop_opt_ext_tmpdir,$repocop_opt_big_tmpdir,$repocop_opt_big_binary);
my $repocop_opt_collect=1;
my $repocop_opt_posttest=1;
my $repocop_opt_distrotest=0;
my $repocop_opt_swift_collect;
my $opt_newer;
my @INPUT_LIST;
our @LONGOPT=(
    "fakeroot!"  => \$repocop_use_fakeroot,
    "collect!"  => \$repocop_opt_collect,
    "posttest!"  => \$repocop_opt_posttest,
    "distrotest!"  => \$repocop_opt_distrotest,
    "big-tmpdir=s"  => \$repocop_opt_big_tmpdir,
    "big-binary=s"  => \$repocop_opt_big_binary,
    "tmpdir=s"  => \$repocop_opt_ext_tmpdir,
    "skip-big-binary=s"  => \$repocop_opt_skip_big_binary,
    "skip-big-source=s"  => \$repocop_opt_skip_big_source,
    "swift|swift-collect!"  => \$repocop_opt_swift_collect,
    "newer=s"  => \$opt_newer,
);
__PACKAGE__->get_and_process_cli_options();

my $rundir=`pwd`;
chomp $rundir;

# global; we use it in exit_repocop
my $PKGTMPDIR;

my $tmpdir_template=$0.".XXXXXXXX";
$tmpdir_template=~s!^.*/!!;

$SIG{'INT'}  = \&sigexit_repocop;
$SIG{'QUIT'} = \&sigexit_repocop;
$SIG{'HUP'} = \&sigexit_repocop;

die "workdir $repocop_workdir does is not a directory!\n" if (-e $repocop_workdir && ! -d $repocop_workdir);

# TODO: makes sence in collect mode only
&process_options_collect();
&process_arguments();

# global; keeps options per test that can be configured in /options file
my %TestOptions;
my %TestFilePattern;
my @SourceTestPatterns;
my %DefaultOptions=qw/need_unpack 1/;

make_path($repocop_workdir,$repocop_metadatadir);
my $locker=Test::Repocop::Workdir::get_locker();
$locker->lock() or die "locking $repocop_workdir failed.\n";

my $repocop_latesttest_timestamp="$repocop_metadatadir/latest-test.timestamp";
# list of last packages that passed through tests
# we empty it there and create again at each run
my $repocop_lastrun_id_file="$repocop_metadatadir/last-run";
unlink $repocop_lastrun_id_file;
my @repocop_lastrun_ids;

#$ENV{'REPOCOP_CACHEDIR'}=$repocop_workdir;
$ENV{'REPOCOP_WORKDIR'}=$repocop_workdir;
my $testdb=Test::Repocop::TestDB->new();
$testdb->setup_environment();

foreach my $test (&Repocop::datadir::glob_tests('',@Repocop::datadir::tests_dir)) {
    my $testname=basename($test);
    &Test::Repocop::Common::mkdir_test_environment($testname);
}

&load_test_options_files();

# collect test names and mtimes
my $source_collect_ref;
my $binary_collect_ref;
my %collect_test_name;
my %collect_test_mtime;
my $latest_test_mtime;
my $latest_test_file;

if ($repocop_opt_collect) {

    $source_collect_ref = &calculate_collectors_info(\@Repocop::datadir::srcscripts_dir);
    $binary_collect_ref = &calculate_collectors_info(\@Repocop::datadir::pkgscripts_dir);

    # autodetect if we can run collect in swift mode
    if (not defined($repocop_opt_swift_collect)
	and defined($latest_test_mtime) # some tests are installed
	and -e $repocop_latesttest_timestamp) {
	my $repocop_lastrun_test_mtime=-M $repocop_latesttest_timestamp;
	 if ($repocop_lastrun_test_mtime <= $latest_test_mtime
	     or $repocop_lastrun_test_mtime - $latest_test_mtime < 0.00005) {
	     $repocop_opt_swift_collect=1;
	     &repocop_note('entering --swift mode...');
	 }
    }

    &init_repocop_databases() if not $repocop_opt_swift_collect;

    &Test::Repocop::RPMdb::connect_rpm_db("$repocop_test_dbdir/rpm.db");

    my $processed_rpm_ids=&Test::Repocop::RPMdb::get_all_rpm_db_ids() if $repocop_opt_swift_collect;

    foreach my $rpmarg (sort @INPUT_LIST) {
	if (-e $rpmarg) {
	    my $repocop_pkg_key=&Test::Repocop::PkgId::get_pkgid_from_rpm_file($rpmarg);
	    # mark the rpm as processed
	    push @repocop_lastrun_ids,$repocop_pkg_key;
	    if ($repocop_opt_swift_collect and $processed_rpm_ids->{$repocop_pkg_key}) {
		next;
	    } else {
		&process_rpm($rpmarg,$repocop_pkg_key);
	    }
	} else {
	    warn "rpm file $rpmarg does not exist :(";
	}
    }
    &write_lastrun_ids_file($repocop_lastrun_id_file,\@repocop_lastrun_ids);

    &call_posttests('done');

    system('touch', '--reference', $latest_test_file, $repocop_latesttest_timestamp)==0
	or die "touch -r $latest_test_file $repocop_latesttest_timestamp failed.\n"
	if $latest_test_file; # w/o tests $latest_test_file is undefined; redmine#1837
}

if (! -e "$repocop_test_dbdir/rpm.db") {
    die "Fatal: $repocop_test_dbdir/rpm.db not found. run repocop-run in collect mode first.\n";
}

if ($repocop_opt_posttest) {
    &call_posttests('posttest');
}
if ($repocop_opt_distrotest) {
    &call_posttests('distrotest');
}

&cleanup_on_repocop_exit();
$locker->unlock() or die "unlocking $repocop_workdir failed.\n";

#====================================================

sub process_options_collect {
    die "argument to --newer option, file $opt_newer not found.\n" if $opt_newer && ! -e $opt_newer;
    &__convert_megabytes('big-binary',\$repocop_opt_big_binary);
    &__convert_megabytes('skip-big-binary',\$repocop_opt_skip_big_binary);
    &__convert_megabytes('skip-big-source',\$repocop_opt_skip_big_source);

    # create temporary dirs if defined
    foreach ($repocop_opt_big_tmpdir, $repocop_opt_ext_tmpdir) {
	make_path($_) if $_ and not -d $_;
    }
    &repocop_note("Note: using fakeroot (slower).") if $repocop_use_fakeroot;
}

sub process_arguments {
    foreach my $rpmarg (@ARGV) {
	if ( -d "$rpmarg") {
	    open (RPMARGS_FILES, "ls -1 $rpmarg |grep -E -x '[^.].*[.]rpm\$' |") || die $!;
	    my $f;
	    while ($f=<RPMARGS_FILES>) {
		chomp $f;
		&_add_file_to_repocop_arg_pkg("$rpmarg/$f") if -e "$rpmarg/$f";
	    }
	    close RPMARGS_FILES;
	} else {
	    &_add_file_to_repocop_arg_pkg($rpmarg);
	}
    }
}

sub _add_file_to_repocop_arg_pkg {
    foreach (@_) {
	next if ($opt_newer and -e $_ and -M $opt_newer < -M $_);
	push @INPUT_LIST, $_;
    }
}


sub init_repocop_databases {
    # run sql database constructors
    make_path($repocop_test_dbdir);
    foreach my $sqlconstructor (&Repocop::datadir::glob_tests('init.sql*', @Repocop::datadir::tests_dir)) {
	my $testname=&Test::Repocop::Common::filepath2testname($sqlconstructor);
	my $repocop_test_db="$repocop_test_dbdir/$testname.db";
	&Test::Repocop::SQL::init_db($repocop_test_db,$sqlconstructor,$testname);
    }

    # run filesystem database constructors
    foreach my $testconstructor (&Repocop::datadir::glob_tests('init', @Repocop::datadir::tests_dir)) {
	my $testname=&Test::Repocop::Common::filepath2testname($testconstructor);
	&Test::Repocop::Common::set_test_environment($testname);
	if (-x $testconstructor) {
	    system($testconstructor)==0 || die "error: $testname/init exited abnormally\n";
	}
    }
}

sub calculate_collectors_info {
    my ($dirlist_ref)=@_;
    my @filelist;
    foreach my $test (&Repocop::datadir::glob_tests('test',@$dirlist_ref)) {
	my $testname = &Test::Repocop::Common::filepath2testname($test);
	if (! -x $test) {
	    &repocop_note("skipped $testname: not executable");
	} else {
	    push @filelist, $test;
	    my $_mtime = -M "$test";
	    $collect_test_mtime{$test} = $_mtime;
	    $collect_test_name{$test} = $testname;
	    if (not defined($latest_test_mtime) or $latest_test_mtime > $_mtime) {
		$latest_test_mtime = $_mtime;
		$latest_test_file = $test;
	    }
	}
    }
    return \@filelist;
}

sub call_posttests {
    my ($methodtype) = @_;
    chdir $rundir;
    my @postmethods = &Repocop::datadir::glob_tests($methodtype, @Repocop::datadir::tests_dir);
    return unless @postmethods;

    &repocop_note("preparing [$methodtype] methods");
    my @postmethodnames=map {&Test::Repocop::Common::filepath2testname($_)} @postmethods;
    $testdb->remove_test(@postmethodnames);
    
    foreach my $postmethod (@postmethods) {
	my $testname=&Test::Repocop::Common::filepath2testname($postmethod);
	&Test::Repocop::Common::set_test_environment($testname);
	&repocop_note("trying [$methodtype] $testname");
	if (-x $postmethod) {
	    my $timeofstart=time();
	    system($postmethod)==0 || die "error: $testname/$methodtype exited abnormally\n";
	    my $elapsedtime = time()-$timeofstart;
	    if ($elapsedtime>10) {
		&repocop_note("Note: [$methodtype] $testname took $elapsedtime secs");
	    }
	}
    }
}

sub cleanup_on_repocop_exit {
    chdir $rundir;
    &del_PKGTMPDIR();
    &Test::Repocop::Common::cleanup_test_environments(
	map { basename $_} &Repocop::datadir::glob_tests('',@Repocop::datadir::tests_dir)
    );
    &Test::Repocop::RPMdb::done_rpm_db();
}


sub sigexit_repocop {
    &repocop_note('exiting repocop (signal)...');
    &cleanup_on_repocop_exit();
    exit 10 ;
}

sub del_PKGTMPDIR {
    if (defined $PKGTMPDIR and -d $PKGTMPDIR) {
	system 'chmod', '-Rf', 'u+rwX', $PKGTMPDIR;
	remove_tree($PKGTMPDIR);
    }

}

sub write_lastrun_ids_file {
    my ($filename, $lastrun_ids_ptr)=@_;
    open (AFILE, '>>', $filename) || die "can't open $filename: $!";
    foreach my $line (@$lastrun_ids_ptr) {
	print AFILE $line, "\n";
    }
    close AFILE;
}

sub process_rpm {
    my ($rpmarg,$repocop_pkg_key)=@_;
    &repocop_note("processing $rpmarg");
    $repocop_pkg_key//=&Test::Repocop::PkgId::get_pkgid_from_rpm_file($rpmarg);
    $rpmarg=$rundir.'/'.$rpmarg unless $rpmarg=~m!^/!;

    $ENV{'REPOCOP_PKG'}=$rpmarg;
    $ENV{'REPOCOP_PKG_KEY'}=$repocop_pkg_key;

    my $lazyrhref = LazyRPMFileHeader->new($rpmarg);
    my $is_source= &Test::Repocop::PkgId::pkgid_is_source($repocop_pkg_key); #$rhref->is_source();
    my $testfiles_ref=$is_source ? $source_collect_ref : $binary_collect_ref;
    my $is_set_environment_vars=0;
    my $is_pkg_unpacked=0;
    my $is_ls_created=0;
    my $is_tmpdir_created=0;
    my $lsfile;

    unless ($testdb->is_test_performed($repocop_pkg_key,'rpm')) {
	&repocop_note("trying rpm");
	&Test::Repocop::RPMdb::add_rpm_metadata($lazyrhref->get_rhref(),$repocop_pkg_key);
	$testdb->set_test_mtime($repocop_pkg_key,'rpm');
    }

    foreach my $testexecutable (@$testfiles_ref) {
	my $testname=$collect_test_name{$testexecutable};
	my $testmtime=$collect_test_mtime{$testexecutable};

	&Test::Repocop::Common::set_test_environment($testname);
	if ($testdb->is_test_performed($repocop_pkg_key,$testname)) {
	    if ($testdb->get_test_mtime($repocop_pkg_key,$testname) < $testmtime) {
	        # tests are already performed
		&repocop_note2("skipped $testname (cached)");
 		next;
	    } else {
		$testdb->clear_test_result_and_mtime($repocop_pkg_key,$testname);
		&repocop_note("cache for $testname is obsolete - run again");
	    }
	}

	unless ($is_set_environment_vars) {
	    &set_environment_vars($lazyrhref->get_rhref(), $is_source);
	    $is_set_environment_vars=1;
	}

	# unpack rpm only if required to speed up skipping
	if (!$is_pkg_unpacked && &get_test_option($testname,'need_unpack')) {
	    if (!$is_tmpdir_created) {
		&create_pkgtmpdir($rpmarg);
		$lsfile = $PKGTMPDIR.'/.ls';
		$is_tmpdir_created=1;
	    }
	    if ($TestFilePattern{$testname}) {
		unless ($is_ls_created) {
		    #system("rpmquery -lp '$rpmarg' > '$PKGTMPDIR/.ls'") && die "rpmquery failed on $rpmarg";
		    open my $fh, '>', $lsfile or die "Can't write to $lsfile: $!";
		    my $filenamesref=$lazyrhref->get_rhref()->filenames();
		    if ($filenamesref) {
			foreach my $rfile (@$filenamesref) {
			    print $fh $rfile, "\n";
			}
		    }
		    close $fh;
		    $is_ls_created=1;
		}
		# grep -P == pcregrep
		# unfortunately, with grep 3.7
		# grep: параметр -P поддерживает только одиночный шаблон
		if (system('grep', '-E','-q','-f', $TestFilePattern{$testname}, $lsfile)!=0) {
		    # no need to unpack or call the collector;
		    $testdb->set_test_mtime($repocop_pkg_key,$testname);
		    next; # go to next test
		}
	    }
	    if (
		($is_source and $repocop_opt_skip_big_source and -s $rpmarg > $repocop_opt_skip_big_source) or
		(not $is_source and $repocop_opt_skip_big_binary and -s $rpmarg > $repocop_opt_skip_big_binary)
		) {
		&repocop_note("postponed $testname (too big rpm file)");
		next; # go to next test
	    }
	    unless (&unpack_rpm($rpmarg, $lazyrhref->get_rhref(), $is_source)) {
		&repocop_note("Note: PKGTMPDIR=$PKGTMPDIR.");
		die "unpacking $rpmarg failed\n";
	    }
	    $is_pkg_unpacked=1;
	}
	&repocop_note("trying $testname");
	if ($is_pkg_unpacked and $repocop_use_fakeroot and not $is_source) {
	    system qw!fakeroot -i ../.fakedata --!, $testexecutable;
	} else {
	    system $testexecutable;
	}
	$testdb->set_test_mtime($repocop_pkg_key,$testname);
    }
    chdir $rundir;
    &del_PKGTMPDIR();
}

sub set_environment_vars {
    my ($rhref, $is_source)=@_;
    foreach my $tag ('NAME','VERSION','RELEASE','EPOCH','ARCH') {
	my $tagval=$rhref->{$tag};
	$tagval='' unless defined $tagval;
	$ENV{'REPOCOP_PKG_'.$tag}=$tagval;
    }
    unless ($is_source) {
	my $srcname=$rhref->{'SOURCERPM'};
	$srcname=~s/-[^-]+-[^-]+\.src\.rpm$//;
	$ENV{'REPOCOP_PKG_SOURCE_NAME'}=$srcname;
    }
}

sub create_pkgtmpdir {
    my ($rpmarg)=@_;
    my @tempdir_opt;
    if ($repocop_opt_big_tmpdir and $repocop_opt_big_binary and (-s $rpmarg >$repocop_opt_big_binary)) {
	push @tempdir_opt, DIR => $repocop_opt_big_tmpdir;
    } elsif ($repocop_opt_ext_tmpdir) {
	push @tempdir_opt, DIR => $repocop_opt_ext_tmpdir;
    } else {
	push @tempdir_opt, TMPDIR => 1;
    }

    # global; we use it in exit_repocop
    $PKGTMPDIR = tempdir( $tmpdir_template, @tempdir_opt, CLEANUP=>1);
    die "can't create temporary directory!" unless $PKGTMPDIR;
    my $chrootdir="$PKGTMPDIR/chroot";
    make_path($chrootdir);
    $ENV{'RPM_BUILD_ROOT'}=$chrootdir;
    $ENV{'REPOCOP_PKG_ROOT'}=$chrootdir;
}

sub unpack_rpm {
    my ($rpmarg, $rhref,$is_source)=@_;
    my $chrootdir="$PKGTMPDIR/chroot";
    die "can't change directory to ",$chrootdir unless chdir $chrootdir;

    &repocop_note("unpacking...");
    if ($is_source) {
	my $specname;
	my $total_files=scalar(@{$rhref->{'FILEFLAGS'}});
	#SPEC files have flag 32
	for (my $i=0;$i<$total_files;$i++) {
	    $specname = $rhref->{'BASENAMES'}[$i] if (@{$rhref->{'FILEFLAGS'}}[$i] == 32);
	}
	my %unpack_add;
	if (@SourceTestPatterns) {
	    foreach my $srcfile (@{$rhref->{'BASENAMES'}}) {
		foreach my $pattern (@SourceTestPatterns) {
		    $unpack_add{$srcfile}=1 if $srcfile=~/$pattern/;
		}
	    }
	}
	#print STDERR "extra unpack: ".join(" ",keys(%unpack_add)),"\n" if %unpack_add;
	my @unpack_files=($specname, keys(%unpack_add));
	&rpm2cpio_unpack2($rpmarg,\@unpack_files) || die 'rpm2cpio failed on srpm ',$rpmarg;
	$ENV{'REPOCOP_PKG_SPECFILE'}="$chrootdir/$specname";
    } else {
	if ($repocop_use_fakeroot) {
	    unless (&rpm2cpio_fakeroot_unpack2($rpmarg,'../.fakedata')) {
		warn 'rpm2cpio (via fakeroot) failed on ',$rpmarg;
		chdir $rundir;
		return 0;
	    }
	} else {
	    unless (&rpm2cpio_unpack1($rpmarg)) {
		warn "rpm2cpio failed on $rpmarg. Trying fakeroot...\n";
		chdir $rundir;
		&del_PKGTMPDIR();
		&create_pkgtmpdir($rpmarg);
		$chrootdir=$PKGTMPDIR.'/chroot';
		die "can't change directory to ",$chrootdir unless chdir $chrootdir;
		unless (&rpm2cpio_fakeroot_unpack2($rpmarg,'../.fakedata')) {
		    warn 'rpm2cpio (via fakeroot) failed on ',$rpmarg;
		    chdir $rundir;
		    return 0;
		}
	    }
	}
    }
    return 1;
}

sub get_test_option {
    my ($testname, $optionname)=@_;
    return $TestOptions{$testname}{$optionname} if defined $TestOptions{$testname} and defined $TestOptions{$testname}{$optionname};
    return $DefaultOptions{$optionname};
}

sub load_test_options_files {
    local $_;
    foreach my $patternfile (&Repocop::datadir::glob_tests('filepattern',@Repocop::datadir::tests_dir)) {
	my $testname=&Test::Repocop::Common::filepath2testname($patternfile);
	$TestFilePattern{$testname}=$patternfile;
    }

    foreach my $patternfile (&Repocop::datadir::glob_tests('filepattern',@Repocop::datadir::srcscripts_dir)) {
	my $testname=&Test::Repocop::Common::filepath2testname($patternfile);
	my @patterns;
	open (PATFILE, '<', $patternfile) || die "can't open patterns file $patternfile: $!";
	while (<PATFILE>) {
	    chomp;
	    next if /^\s*(?:\#|$)/;
	    push @patterns,$_;
	}
	close(PATFILE);
	push @SourceTestPatterns, @patterns;
    }

    foreach my $optionsfile (&Repocop::datadir::glob_tests('options',@Repocop::datadir::tests_dir)) {
	my $testname=&Test::Repocop::Common::filepath2testname($optionsfile);
	my %options;
	open (OPTFILE, '<', $optionsfile) || die "can't open options file $optionsfile: $!";
	while (<OPTFILE>) {
	    next if /^\s*(?:\#|$)/;
	    if (/^\s*(\S+)\s*=\s*(\S+)\s*$/) {
		$options{$1}=$2;
	    } else {
		warn "unrecognized line $_ in options file $optionsfile\n";
	    }
	}
	close(OPTFILE);
	$TestOptions{$testname}=\%options;
    }
}

sub __convert_megabytes {
    my ($optname, $valptr)=@_;
    return unless $$valptr;
    die "$optname: invalid arg $$valptr: should be a number or a number[kb|mb|gb]" unless $$valptr=~/^\d+[KkMmGg]?[Ii]?[Bb]?$/;
    if ($$valptr=~s/([KkMmGg])?[Ii]?[Bb]?$//) {
	if ($1 eq 'K' or $1 eq 'k') {
	    $$valptr *= 1024;
	} elsif ($1 eq 'M' or $1 eq 'm') {
	    $$valptr *= 1048576;
	} elsif ($1 eq 'G' or $1 eq 'g') {
	    $$valptr *= 1073741824;
	}
    }
}

package LazyRPMFileHeader;

use strict;
use warnings;
use RPM::Header;

sub new {
    my ($class,$rpmfile)=@_;
    my $self=[$rpmfile,undef];
    return bless $self;
}

sub get_rhref {
    my $self=shift;
    return $self->[1] if $self->[1];
    $self->[1] = new RPM::Header $self->[0];
    return $self->[1];
}

__END__

=head1	NAME

repocop-run - run unit tests against the repo or a given set of RPM packages

=head1	SYNOPSIS

B<repocop-run>
[B<-f|--fakeroot> ]
[B<--no-fakeroot> ]
[B<--collect> ]
[B<--no-collect> ]
[B<--posttest> ]
[B<--no-posttest> ]
[B<--skip-big-binary> I<size>]
[B<--skip-big-source> I<size>]
[B<--newer>] I<filename>
[B<-h|--help>]
[B<-v|--verbose>]
[B<-q|--quiet>]
[B<--workdir> I<workdir>]
[B<--pkgcollectors-dir> I<comma separated list of local collectors' dirs>]
[B<--srccollectors-dir> I<comma separated list of local collectors' dirs>]
[B<--pkgtests-dir> I<comma separated list of local tests' dirs>]
[B<--srctests-dir> I<comma separated list of local tests' dirs>]
[B<--exclude-test> I<comma separated list of tests>]
[B<--include-test> I<comma separated list of tests>]
[I<DIR>...] [I<FILE>...]

=head1	DESCRIPTION

B<repocop-run> collects the data to repocop database and executes a set
of tests against each RPM package given on the command line.
Precise subset of tests can be selected using B<--include-test>
and B<--exclude-test> options.
Note that repocop tests are packaged separately. It is recommended to install
repocop-unittests-local metapackage.

=head1 ARGUMENTS

Each I<FILE> is treated as RPM package.  Each I<DIR> is listed with C<*.rpm>
pattern, and all RPM files found are processed.


=head1	OPTIONS

=over

=item	B<-f,--fakeroot>

Always use fakeroot for unpacking rpms.
(note: there are stability issues with some versions of fakeroot).
It is slower and required only for tests that check ownership and so on.

=item	B<--no-fakeroot>

Do not use fakeroot for unpacking rpms (default).

=item	B<-f,--collect>

run package processing collectors and tests (default)

=item	B<--no-collect>

Skip package processing collectors and tests.

=item	B<-f,--posttest>

run post collectors and tests after package processing (default).

=item	B<--no-posttest>

Skip running post collectors and tests after package processing.

=item	B<-f,--distrotest>

run context dependent distro tests after package processing.

=item	B<--no-distrotest>

Skip running context dependent distro tests after package processing (default).

=item	B<--tmpdir> I<path>

Set default temporary dir to be at I<path>.

=item	B<--big-tmpdir> I<path>

Set the temporary dir for big files to be at I<path>.

=item	B<--big-binary> I<size>

If the binary rpm's size is bigger than I<size>, big-tmpdir is used instead of default temporary dir.
kb, mb, gb, Kb,Mb, Gb, k, m, g suffixes are allowed.

=item	B<--skip-big-binary> I<size>

Skip unpacking binary rpms bigger than I<size>. kb, mb, gb, Kb,Mb, Gb, k, m, g suffixes are allowed.

=item	B<--skip-big-source> I<size>

Skip unpacking source rpms bigger than I<size>. kb, mb, gb, Kb,Mb, Gb, k, m, g suffixes are allowed.

=item	B<--newer> I<filename>

Process packages newer then I<filename> only.

=item	B<--swift|--swift-collect>

Swift collect mode. Repocop needs to re-test packages in case some of
the collectors or collecting tests changed. B<--swift|--swift-collect> tells
repocop that the databases are properly initialized and collectors did not change
so there is no need to re-check already tested packages.

By default, repocop autodetects normal or swift mode.

=item	B<--workdir> I<dir>

Provides alternative location for the Repocop workdir. Repocop workdir
is a place where test results and packages metadata information are stored.
Default is I<~/.repocop>.

=item	B<-h, --help>

Display this help and exit.

=item	B<-v, --verbose>, B<-q, --quiet>

Verbosity level. Multiple -v increase the verbosity level, -q sets it to 0.



=item [B<--pkgcollectors-dir> I<comma separated list of local collectors' dirs>]

=item [B<--srccollectors-dir> I<comma separated list of local collectors' dirs>]

=item [B<--pkgtests-dir> I<comma separated list of local tests' dirs>]

=item [B<--srctests-dir> I<comma separated list of local tests' dirs>]

Append user's local tests and collectors to repocop.
Those options do not disable or override loading of default tests
found in /usr/lib*/repocop and /usr/share/repocop.

=item [B<--exclude-test> I<comma separated list of tests>]

=item [B<--include-test> I<comma separated list of tests>]

Include/exclude tests for repocop-run.
Those options accept all kinds of repocop tests, including unittests, collectors and distrotests.


=back

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	ACKNOWLEGEMENTS

To Alexey Torbin <at@altlinux.org>, whose qa-robot package
had a strong influence on repocop.

=head1	COPYING

Copyright (c) 2008-2022 Igor Vlasenko, ALT Linux Team.

This 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.

=cut
