#!/usr/bin/perl -w

use strict;
use warnings;
use Carp;
use File::Path;

use Test::Repocop::Common;
use Test::Repocop::Options;
use Test::Repocop::TestDB;
use Test::Repocop::Metadata;
use Test::Repocop::ACLWrapper;
use Data::Array2ArrayMap::Hash::XSTree;

use RPM::Source::Editor;
use RPM::Source::TransformContainer 0.003;
use RPM::Source::Transformation::BaseTransformationSet;
use RPM::Source::Transformation::DiffWritePlayer;
use RPM::Source::Transformation::Factory::RaiseRelease;
use Test::Repocop::FixscriptFactory;

my ($diffmode,$nmumode,$reportmode,$output_unchanged);
my $report_by_leader=1;
my $report_by_packager=0;

$RPM::Source::Transformation::Factory::RaiseRelease::nextrel='qa';
$RPM::Source::Transformation::Factory::RaiseRelease::changelog='- NMU (by repocop). See http://www.altlinux.org/Tools/Repocop';

#$Repocop::arg::reportlevel='experimental';
&Test::Repocop::Options::get_common_options(
    'diff'        => \$diffmode,
    'nmu'         => \$nmumode,
    'write-report!'=> \$reportmode,
    RPM::Source::Transform->get_longopt,
);

&Test::Repocop::Options::die_if_nothing_to_report();

my $RPM2TEST=Data::Array2ArrayMap::Hash::XSTree->new();
my $RPM2NAME=Data::Array2ArrayMap::Hash::XSTree->new();

my $aclmap=Test::Repocop::ACLWrapper->new();
my $metadata=Test::Repocop::Metadata->new();
my $sourceid2specfilename=Test::Repocop::Metadata::sourceid2specfilename();
my $testdb=Test::Repocop::TestDB->new();
my $cache=$testdb->get_pkg_test_status_iterator();

# hack to process all known test results
undef %Repocop::arg::pkgtable;
while (my ($rpm,$test,$status)=$cache->iterate3_filtered()) {
    #print STDERR "$rpm:$test:$status\n";
    my $sourceid=$metadata->sourceid($rpm);
    my $name=$metadata->name($rpm);
    $RPM2TEST->append([$sourceid],[$test]);
    $RPM2NAME->append([$sourceid],[$name]);
}

my ($by_acl_dir,$by_test_dir,$by_nick_dir,$by_leader_dir,$qa_robot_report_dir);
if ($diffmode && $reportmode) {
    my $repocop_reportdir="$repocop_cachedir/reports/diff";
    my $outdir=$repocop_reportdir.'/by-srpm';
    $by_acl_dir=$repocop_reportdir.'/by-acl';
    $by_test_dir=$repocop_reportdir.'/by-test';
    $by_nick_dir=$repocop_reportdir.'/by-packager';
    $by_leader_dir=$repocop_reportdir.'/by-leader';
    $qa_robot_report_dir=$repocop_reportdir.'/qa-robot';

    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_by_transformation_dir=$by_test_dir;
    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_by_srpm_dir=$outdir;

    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_author_name='Repocop Q. A. Robot';
    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_author_email='repocop@altlinux.org';
    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_email_subject='repocop NMU';

    rmtree([$repocop_reportdir]);
    mkpath([$outdir, $by_acl_dir, $by_test_dir, $by_nick_dir, $qa_robot_report_dir]);
    mkpath([$by_leader_dir]) if $report_by_leader;
}

RPM::Source::TransformContainer->init_transformations();

foreach my $file (@Repocop::arg::pkglist) {
    my ($srpmfile, $specfile, $sourceid);
    if ($file=~/\.rpm$/) {
	$srpmfile = $file;
	$sourceid=&Test::Repocop::Common::rpmfile2key($srpmfile);
    } elsif ($file=~/\.spec$/) {
	$specfile=$file;
	$sourceid=&Test::Repocop::Common::specfile2srcid($specfile);
    } else {
	warn "Invalid argument: $file: not a .rpm or .spec!\n";
	next;
    }

    unless ($sourceid =~ /src$/) {
	warn "$sourceid: not a src.rpm!\n" if $verbose;
	next;
    }
    my @tests=$RPM2TEST->get([$sourceid]);
    my @tests_with_fixscript=grep {$Test::Repocop::FixscriptFactory::test_with_fixscript{$_}} @tests;
    if (scalar @tests_with_fixscript) {
	print "$sourceid:\n";
	my @names=$RPM2NAME->get([$sourceid]);
	eval {
	    #---------------------------------------------------------
	    my $opt_transform=RPM::Source::TransformContainer->mk_opt();
	    my $rpmeditor=RPM::Source::Editor->new(
		SOURCERPM => $srpmfile,
		SPECFILE=> $specfile, 
		VERBOSE=> $verbose,
		);
	    if ($diffmode or $reportmode) {
		my $diffname=$sourceid;
		$diffname=~s/\.src$//;
		$opt_transform->{-diff_name}=$diffname;
		$opt_transform->{-diff_specname}=$sourceid2specfilename->{$sourceid};
		$opt_transform->{-diff_raise_release}=$nmumode ? 1 : 0;
	    }
	    $opt_transform->{-repocop_testnames}=\@names;
	    $opt_transform->{-repocop_pkgnames}=\@tests;
	    RPM::Source::TransformContainer->transform_once($rpmeditor,undef,$opt_transform);
	    #---------------------------------------------------------
	};
	warn "Got exception: $@" if $@;
    }
}

print STDERR "finished writing diffs\n" if $verbose;

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


=head1	NAME

repocop-fix-srpm - a tool that repairs srpm using repocop unit tests results.

=head1	SYNOPSIS

B<repocop-fix-srpm>
[B<--changelog> I<changelog entry>]
[B<--diff>]
[B<--nmu>]
[B<--packager> I<name email>]
[B<-h|--help>]
[B<-v|--verbose>]
[B<-q|--quiet>]
[B<-c|--cachedir> I<cachedir>]
[B<--et|--exclude-test> I<comma separated list of tests>]
[B<--it|--include-test> I<comma separated list of tests>]
[B<--ep|--exclude-packager> I<comma separated list of packager's nicks>]
[B<--ip|--include-packager> I<comma separated list of packager's nicks>]
[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<--ex|--except>] 
[B<-g|--given>] 
[B<-l|--last-run>] 
[B<--newer>] I<filename>
[B<-r|--report> <s[kip]|o[k]|w[arn]|f[ail]>]
[I<DIR>...] [I<FILE>...]

=head1	DESCRIPTION

B<repocop-fix-srpm> processes results of repocop unit tests, created with 
repocop-run command, stored in <cachedir> and use them to generate patches
or just repair source rpms.
Presize subset of tests can be selected using B<--include>
and B<--exclude> options.

=head1	OPTIONS

=over

=item	B<-c,--cachedir> I<dir>

Provides alternative location for cachedir. 
Repocop cachedir is a place where test results and 
packages metadata information are stored.

=item	B<--except>, B<--given>

Control processing of rpm arguments. 
B<--given> (default) means processing only given rpm arguments.
B<--except>  means processing all data except given rpm arguments.

=item	B<--et, --exclude-test> I<comma separated list of tests>

Report all processed tests exept the given excluded set.

=item	B<--it, --include-test> I<comma separated list of tests>

Report the given set of tests.

=item	B<--ep, --exclude-packager> I<comma separated list of tests>

=item	B<--it, --include-packager> I<comma separated list of tests>

Exclude/include packages according to Packager: tag.

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

=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<-l, --last-run>

Use the set of packages processed at last run as an argument.

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

Process packages newer then I<filename> only.
Note: this filtering does not apply to B<--last-run> option.

=item	B<--acl-file> I<file>

the argument is /path/to/Sisyphus/files/list/list.src.classic
This option is ALTLinux-specific. The file content is ACL db,
which is used to sort result by ALTLinux ACL.


=item	B<--changelog> I<changelog entry>

The specified value replaces default repocop-generated changelog.

=item	B<--diff>

Diff mode. In this mode only diffs are generated. By default, the generated diff
does not include changelog.

=item	B<--nmu>

Non-Maintainer Upload (NMU). Raise release. 
In diff mode it will force inclusion of 
new release and changelog into the generated diff.

=item	B<--packager> I<name email>

If spec file has no Packager: tag, the specified value will be used.

=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-2012 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

