#!/usr/bin/perl -w

use strict;
use warnings;
use File::Find;
use RPM::Header;
use Getopt::Long;
use Pod::Usage;
use ALTLinux::ACL;

Getopt::Long::Configure("no_ignore_case");
my $months=6 ;
my $leadercount = 4;
my $timemin = time-3600*24*30.5*$months;

my $verbose=1;
my $help=0;
my $group=0;
my $user=1;
my $generate_acl=0;
my $allowed_only=1;
#my $keepgroup=1;

my $result = GetOptions (
    @ALTLinux::ACL::LONGOPT,
    "acl"  => \$generate_acl,
    "everybody"  => sub{$allowed_only=0},
    "group!"  => \$group,
    "user!"  => \$user,
    "count=i"  => \$leadercount,
    "months=i"  => \$months,
    "g"  => sub {$group=1},
    "G"  => sub {$group=0},
    "u"  => sub {$user=1},
    "U"  => sub {$user=0},
    "help"  => \$help,
    'quiet'=> sub {$verbose=0},
    "verbose+"  => \$verbose,
);

my @directories = @ARGV;

if ($help or ! @directories) {
    pod2usage();
}

map {-d $_ or die "argument is not a directory: $_\n"} @directories;

my $acl = ALTLinux::ACL->new();

find(\&wanted,  @directories);
sub wanted {
# $File::Find::dir  = /some/path/
# $_                = foo.ext
# $File::Find::name = /some/path/foo.ext
    my $filename=$_;
    return unless /\.src\.rpm$/ and not -l $_;
    my @stat=stat $filename;
#  0 dev      device number of filesystem
#  1 ino      inode number
#  2 mode     file mode  (type and permissions)
#  3 nlink    number of (hard) links to the file
#  4 uid      numeric user ID of file's owner
#  5 gid      numeric group ID of file's owner
#  6 rdev     the device identifier (special files only)
#  7 size     total size of file, in bytes
#  8 atime    last access time in seconds since the epoch
#  9 mtime    last modify time in seconds since the epoch
# 10 ctime    inode change time in seconds since the epoch (*)
# 11 blksize  preferred block size for file system I/O
# 12 blocks   actual number of blocks allocated
    my $rpmpath=$filename;
    my $rpmmtime = $stat[9];
    return if $rpmmtime < $timemin;
    #print "eval $rpmpath\n";
    my $header;
    eval {
	$header=new RPM::Header $rpmpath;
    };
    if ($@) {
	warn "$rpmpath skipped: $@\n" if $verbose;
	return;
    }
    my $changelogname=$header->{CHANGELOGNAME};
    my $changelogtime=$header->{CHANGELOGTIME};
    my $changelogtext=$header->{CHANGELOGTEXT};
    my $name=$header->{NAME};
    die "can't be: no name for $filename" unless $name;
    #print basename($rpmpath),"\n";
    my $count = 0;
    my $starttime = $changelogtime->[0];
    my $candidate = $changelogname->[0];
    my $user = ALTLinux::ACL::email2aclname($candidate);
    unless ($user) {
	warn "can't find candidate in $candidate";
	return;
    }
    my $oldleader= $acl->leader($name);
    # deprecated rpm
    unless ($oldleader) {
	warn "no leader for $name: the package looks deprecated.";
	return;
    }
    return if $oldleader eq '@nobody';
    $candidate=~/^.+\<(\S+)\s*(?:\@|at)\s*altlinux.*>/;
    my $pattern=$1;

    for (my $i=1;$i<@$changelogtime;$i++) {
	last if $changelogname->[$i]!~/\<$user\s*(?:\@|at)\s*altlinux/;
	$count++;
	$starttime = $changelogtime->[$i];
	#print "name i=$i: ", $changelogname->[$i],"\n";
	#print "time i=$i: ", ctime($changelogtime->[$i]);#,"\n";
	#print "text i=$i: ", $changelogtext->[$i],"\n";
    }
    return if $starttime> $timemin or $count < $leadercount -1;
    # robots
    return if $user eq 'cronbuild' or $user eq 'repocop';
    # it is robot too ;)
    return if $user eq 'viy' and $name =~ '^perl-';

    return if $acl -> is_leader($name, $user);
    return if $allowed_only and not $acl->is_authorized($name, $user);
    #print STDERR $acl->leader($name), ' -> ', $user, "\n";
    if (substr($oldleader, 0, 1) ne '@') {
	&print_acl($acl, $oldleader,$user,$name);
    } else {
	my %aclcheck = map {$_=>1} $acl->acl($name);
	unless ($aclcheck{$user}) {
	    if ($group) {
		&print_acl($acl, $oldleader,$user,$name);
	    } else {
		print STDERR $oldleader, ' group kept as leader; noticed ', $user, " ($name)", "\n" if $verbose;
	    }
	}
    }
}


sub print_acl {
    my ($acl, $oldleader,$user,$name)=@_;
    return unless $user;
    if ($generate_acl) {
	# ldv> Две команды add+leader это лишнее, достаточно просто leader.
	#print "ssh git.alt acl sisyphus $name add $user\n";
	print "ssh git.alt acl sisyphus $name leader $user\n";
	# explicitly list old leader in acl 
	# done automatically
	#print "ssh git.alt acl sisyphus $name add $oldleader\n" unless grep /^$oldleader$/ $acl->acl();
    } else {
	print $oldleader, ' -> ', $user, " ($name)", "\n";
    }
}

=head1	NAME

changelog2ALTLinuxACLleader - a tool for finding good leaders.

=head1	SYNOPSIS

B<changelog2ALTLinuxACLleader>
[B<-a|--acl>]
[B<-h|--help>]
[B<-c|--count> <minimal number of consequent changelog entries>]
[B<-m|--months> <period in months>]
[B<-g|--group>]
[B<-G|--no-group>]
[B<-u|--user>]
[B<-U|--no-user>]
[B<-v|--verbose>]
[B<-q|--quiet>]
[I<DIR>...] 

=head1	DESCRIPTION

B<changelog2ALTLinuxACLleader>

=head1	OPTIONS

=over

=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<-a, --acl>

Genarate acl commands ready to be used with git.alt

=item	B<-e, --everybody>

Everybody could be leader, not only permitted by acl.
for example, if acl is A @everybody then B can be added.
but if acl is A then B can't be added unless --everybody option is used.

=item	B<-c, --count> <number of changelog entries>

The minimal number of last subsequent changelog entries by the new leader.

=item	B<-m, --months> <number>

The minimal number of months the new leader should be the only one who builds the package.

=item   [B<-g|--group>], [B<-G|--no-group>]

Generate acl changes if leader is a group.
Default is do not generate (--no-group).


=item   [B<-u|--user>], [B<-U|--no-user>]

Generate acl changes if leader is a regular user, not a group.
Default is to generate (--user).

=back

=head1	AUTHOR

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

=head1	COPYING

Copyright (c) 2009 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

