#!/usr/bin/perl -w

use strict;
use warnings;
use Carp;
use File::Path qw(make_path remove_tree);
use File::Basename;
use autodie qw/link/;

use Test::Repocop::Log;
use Test::Repocop::Workdir;
use Test::Repocop::PkgId;
use Test::Repocop::ACLWrapper;

use RPM::Source::Editor 0.9216;
use RPM::Source::TransformContainer 0.008;
use RPM::Source::Transform;
use RPM::Source::Transformation::BaseTransformationSet;
use RPM::Source::Transformation::DiffWritePlayer;
use RPM::Source::Transformation::Factory::RaiseRelease;
use Test::Repocop::RepocopResource;
use Test::Repocop::FixscriptFactory;
our @ISA=qw/RPM::Source::Transform/;
#our @LONGOPT_POD2USAGE=qw/-verbose 1/;# -exitval 1

$RPM::Source::Transformation::Factory::RaiseRelease::nextrel='qa';
$RPM::Source::Transformation::Factory::RaiseRelease::defaultchangelog='- NMU (by repocop). See http://www.altlinux.org/Tools/Repocop';
$RPM::Source::Transformation::DiffWritePlayer::opt_use_diff_writer=1;
$RPM::Source::Transformation::DiffWritePlayer::opt_diff_write_unchanged=0;
$RPM::Source::Transformation::DiffWritePlayer::opt_diff_raise_release=0;
$RPM::Source::Transformation::DiffWritePlayer::opt_diff_digest_mode=1;
$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';

my $reportmode=1;
my $report_qa=1;
my $outdir;
my ($report_by_srpm,$report_by_test,$report_by_leader,$report_by_acl)=(1,1,1,1);
our @LONGOPT=(
    "outdir=s"  => \$outdir,
    "by-acl!"  => \$report_by_acl,
    "by-leader!"  => \$report_by_leader,
    "by-srpm!"  => \$report_by_srpm,
    "by-test!"  => \$report_by_test,
    'digest!'     => \$RPM::Source::Transformation::DiffWritePlayer::opt_diff_digest_mode,
    'nmu!'         => \$RPM::Source::Transformation::DiffWritePlayer::opt_diff_raise_release,
    'write-report!'=> \$reportmode,
);
__PACKAGE__->get_and_process_cli_options();

my ($by_test_dir,$by_acl_dir,$by_leader_dir,$qa_robot_report_dir);
my $repocop_diff_dir="$repocop_workdir/reports/diff";
if ($reportmode) {
    $outdir=$repocop_diff_dir.'/by-srpm';
    $by_acl_dir=$repocop_diff_dir.'/by-acl';
    $by_test_dir=$repocop_diff_dir.'/by-test';
    $by_leader_dir=$repocop_diff_dir.'/by-leader';
    $qa_robot_report_dir=$repocop_diff_dir.'/qa-robot';

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

    remove_tree($repocop_diff_dir);
    make_path($outdir, $by_test_dir);
} else {
    $outdir//=$repocop_diff_dir;
    $RPM::Source::Transformation::DiffWritePlayer::opt_diff_by_srpm_dir=$outdir;
    remove_tree($outdir);
    make_path($outdir);
}

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

&Test::Repocop::RepocopResource::process_arguments();

&repocop_note('finished writing diffs');

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

if ($reportmode) {
    die "input directory $outdir does not exist\n" if not -d $outdir;

    remove_tree(
	$by_acl_dir,
	$by_leader_dir,
	$qa_robot_report_dir,
	   );
    make_path($by_acl_dir) if $report_by_acl;
    make_path($by_leader_dir) if $report_by_leader;

    my %srcid;
    my $metadata=Test::Repocop::Metadata->new();
    my $aclmap=Test::Repocop::ACLWrapper->new();
    unless ($aclmap) {
	&repocop_note("acl is not available. Disabled reports by acl/leader.") if $report_by_leader or $report_by_acl;
	$report_by_leader=0;
	$report_by_acl=0;
    }
    foreach (glob "$outdir/*") {
	next unless -e $_ and -s $_; # skipping empty diffs
	&repocop_debug("linking $_");
	my $diffpath=$_;
	my $diffname=basename($_);
	my $id=&Test::Repocop::PkgId::patchname2srcid($diffname);
	$srcid{$id}=1;
	if ($aclmap and ($report_by_acl or $report_by_leader)) {
	    my $srcname=$metadata->name($id);
	    if (! defined($srcname)) {
		warn "source name is not defined for $id";
	    } else {
		my @acls=$aclmap->name2acl($srcname);
		# p8 does not have acls now
		if (scalar @acls) {
		    foreach my $acl (@acls) {
			mkdir "$by_acl_dir/$acl";
			link $diffpath, "$by_acl_dir/$acl/$diffname";
		    }
		    if ($report_by_leader and $acls[0]) {
			mkdir "$by_leader_dir/$acls[0]";
			link $diffpath, "$by_leader_dir/$acls[0]/$diffname";
		    }
		}
	    }
	}
    }

    # ------------ qa-robot support -------------------------
    if ($report_qa) {
	make_path($qa_robot_report_dir);
	open (my $fh, '>', $qa_robot_report_dir.'/diff.ls') || die "can't open $qa_robot_report_dir/patches.ls: $!";
	foreach (keys(%srcid)) {
	    print $fh $metadata->name($_),"\t",$_,"\n";
	}
	close ($fh);
    }
}

__END__

=head1	NAME

repocop-report-diff - a tool that generates patches using repocop unit tests results.

=head1	SYNOPSIS

B<repocop-report-diff>
[B<--nmu>]
[B<--write-report>]
[B<-h|--help>]
[B<-v|--verbose>]
[B<-q|--quiet>]
[B<--workdir> I<workdir>]
[B<--repocop-acl-file> I<file>]
[B<--repocop-acl-altlinux>
[B<--acl-branch I<sisyphus|p10|...>]
[B<--acl-expire> I<time>] ]
[B<--report> I<warn|fail|skip|experimental|ok>]
[B<--report-et|--report-exclude-test> I<comma separated list of tests>]
[B<--report-it|--report-include-test> I<comma separated list of tests>]
[B<--report-include-distrotests>]
[<src.rpm file or spec>/dir ...]

=head1	DESCRIPTION

B<repocop-report-diff> processes results of repocop unit tests, created with
repocop-run command, stored in I<repocop workdir> and creates patches for the
bugs whose tests have fixscripts.

=head1	OPTIONS

=over

=item  B<--diff>

Diff mode. In this mode only diffs are generated. By default, the generated dif
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<--write-report>

TODO create reports by-leader, by-test and so on.
TODO not yet implemented! use repocop-report-diff-by-acl.


=item	B<-r, --report> I<skip|experimental|ok|warn|fail>

The level of test results reported. Test results below this level
are not reported. Default is warn.

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

Include all tests exept the given excluded set.

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

Include the given set of tests.

=item	B<--report-include-distrotests>

Include all distrotests.



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

The file content is ACL db,
which is used to sort result by ACL.
The argument is generic acl file compatible with Sisyphus' list.src.classic.

Alternatively, you can provide B<--repocop-acl-altlinux>.

=item	B<--repocop-acl-altlinux>

This option is ALTLinux-specific. if provided, repocop use ALTLinux::ACL
(perl-ALTLinux-ACL is required). Also, the following options of ALTLinux::ACL
become available:

B<--acl-branch> I<sisyphus|p10|...>

Name of branch. Default is sisyphus.

B<--acl-expire> I<days>

Cache expiration time, float, in days. Default is 1/5 day.


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


=back

=head1	ARGUMENTS


List of src.rpm or .spec files or directories containing them.


=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

