#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;
use MDV::Repsys;
use MDV::Repsys::Remote;
use POSIX qw(getcwd);
use File::Temp qw(tempdir);

=head1 NAME

mdvsys - Tools to import and extract rpms from a svn

=head1 SYNOPSIS

    mdvsys [options] <action> ...

=head1 OPTIONS

The <action> specified on the command-line can be one of:

=over 4

=item create pkgname

Create a package directory on the subversion repository.

=item import rpmfile1 [[rpmfile2] ...]

Import one or more src.rpm directly into the subversion
repository.

=item getsrpm pkgname

Extract a source package from the subversion repository
into the current directory. The package name is prefixed by
@<rev>: where <rev> is the current subversion revision
unless the no-youri option in used. The prefixed source
package have a valid name to be uploaded by youri.

=item checkout pkgname [dir]

=item co pkgname [dir]

Checkout the "current" version of a package for the
subversion repository. A directory with the same name
than the package is created in dir. This new repository
contains a SPECS directory with the spec file, and a
SOURCES directory with the source files and patches of
the package.

=item commit [dir]

=item ci [dir]

Perform the same action than C<svn commit>, but check that the sources
listed in the specfile are in sync with the svn contents.

Currently you have to use the -m option to set the svn log message.

=item sync [dir]

Search the sources and patches used in the spec file, and 
perform the commands needed to add the new ones in the
repository, and remove the ones no more used from the
repository.

The changes are not commited.

=item build [pkgname]

Build a package. If a package name is given on the command
line, the latest version from the subversion repository is
built. If no package name is provided, the package of the
current directory is built.

=item stripcl [specfile]

Remove the changelog of the specfile and commit it into the svn.

If the --no-commit option is set, the commit part is not done.

=item info <pkgname>

Give information about pkgname from svn.

=item log <pkgname>

Generate %changelog about pkgname from svn.

=item submit <pkgname>

Submit packages to be built from svn.

=back

If no package name is given, mdvsys will try to deduce it from the
current working copy, if applicable, for the command log, submit, info
and getsrpm.

=cut

my %roptions;

=pod

Options can be one of:

=over 4

=item -v

Increase verbosity level.

=item -q

Be completly silent

=item -c <configfile>

Use this configuration file instead /etc/repsys.conf.

=item --no-commit

Commit into the svn will not be done.

This options has effect for import action.

=item -r <revision>

Work on a specific revision.

=item -m <message>

Set this message for commiting

=item --noyouri

Get the standard srpms file, without the '@rev:' prefix.

=back

=cut

GetOptions(
    'no-commit'  => \my $nocommit,
    'm=s'        => \$roptions{message},
    'r=s'        => \$roptions{revision},
    't|target=s' => \$roptions{target},
    'c|config=s' => \my $configfile,
    'd|dest=s'   => \$roptions{destdir},
    'noyouri'    => \my $noyouri,
    'v+'         => \my $verbosity,
    'q|quiet'    => \my $silent,
) or pod2usage(1);

my ($action, @args) = @ARGV;

if (!$action) {
    pod2usage(0);
}

my $exitstatus = 0;

$verbosity = $silent ? 0 : ++$verbosity;

MDV::Repsys::set_verbosity($verbosity);

for ($action) {

    /^sync$/ and do {
        my $dir = $args[0] || getcwd();
        my $spec = (glob("$dir/SPECS/*.spec"))[0];
        if ($spec) {
            MDV::Repsys::set_rpm_dirs($dir);
            if (! MDV::Repsys::sync_source(
                $dir,
                (glob("$dir/SPECS/*.spec"))[0],
            )) {
                warn "Can't sync $dir:\n";
                warn MDV::Repsys::repsys_error() ."\n";
                $exitstatus = 1;
            }
        } else {
            warn "Can't find any specfile\n";
            $exitstatus = 1;
        }
        last;
    };

    my $repsys = MDV::Repsys::Remote->new(
        nocommit => $nocommit,
        configfile => $configfile,
    );
    $repsys or exit 1;
    $repsys->set_verbosity($verbosity);

    /^create$/ and do {
        my $pkgname = $args[0] or pod2usage(1);
        if (!$repsys->create_pkg($pkgname)) {
            warn $repsys->last_error() . "\n";
            warn "Can't create $pkgname\n";
            $exitstatus = 1;
        }
        last;
    };

    /^import$/ and do {
        $args[0] or pod2usage(1);
        foreach my $rpmfile (@args) {
            if (!$repsys->import_pkg(
                $rpmfile,
                %roptions,
            )) {
                warn $repsys->last_error() . "\n";
                warn "Can't import $rpmfile\n";
                $exitstatus = 1;
            }
        }
        last;
    };

    /^getsrpm$/ and do {
        if (! $args[0]) {
            my $package = $repsys->get_pkgname_from_wc();
            $args[0] = $package if $package;
        }
        if (! @args) {
            warn "No package given on the command line, and not in a checkout directory\n";
            $exitstatus = 1;
        }  
        foreach my $name (@args) {
            my ($r, $f) = $repsys->get_srpm(
                $name,
                %roptions,
            );
            if ($r) {
                if ($noyouri) {
                    print "$r $f\n";
                } else {
                    my $ysrpms = sprintf(
                        '@%d:%s',
                        $r, ($f =~ m:.*/+(.*\.src.rpm)$:)[0]
                    );
                    system('mv', $f, $ysrpms);
                    print "$ysrpms\n";
                }
            } else {
                warn $repsys->last_error() . "\n";
                warn "Can't extract $name\n";
                $exitstatus = 1;
            }
        }
        last;
    };

    /^(co|checkout)$/ and do {
        $args[0] or pod2usage(1);
        if (!$repsys->checkout_pkg(
            $args[0],
            $args[1],
            %roptions,
        )) {
            warn $repsys->last_error() . "\n";
            warn "Can't checkout $args[0]\n";
            $exitstatus = 1;
        }
        last;
    };

    /^(ci|commit)$/ and do {
        my $dir = $args[0] || getcwd();
        $repsys->commit(
            $dir,
            %roptions,
            callback => sub {
                $| = 1;
                print "According the specfile, some sources are not into svn\n";
                print "Do you want to sync first ? (Y/n) ";
                my $reply = <STDIN>;
                if ($reply =~ m/^(N|n)/) {
                    return;
                }
                1;
            },
        ) or do {
            warn $repsys->last_error() . "\n";
            warn "Can't commit $dir\n";
        }; 
        last;
    };

    /^log$/ and do {
        if (! $args[0]) {
            my $package = $repsys->get_pkgname_from_wc();
            $args[0] = $package if $package;
        }
        $args[0] or pod2usage(1);
        if (!$repsys->build_final_changelog($args[0])) {
            warn $repsys->last_error() . "\n";
            warn "Can't get changelog of $args[0]\n";
            $exitstatus = 1;
        }
        last;
    };

    /^tag$/ and do {
        if (!$repsys->tag_pkg(
            $args[0],
            %roptions,
        )) {
            warn $repsys->last_error() . "\n";
            warn "Can't tag $args[0]\n";
            $exitstatus = 1;
        }
        last;
    };

    /^build$/ and do {
        my $bdir;
        my $specfile;
        my $odir;
        if ($args[0]) {
            $bdir = tempdir();
            $repsys->checkout_pkg(
                $args[0],
                $bdir,
                 %roptions,
            ) or do {
                warn $repsys->last_error() . "\n";
                warn "Can't extract $args[0]\n";
                $exitstatus = 1;
                next;
            };
            $odir = File::Tempdir->new();
            $specfile = $repsys->get_final_spec(
                (glob("$bdir/SPECS/*.spec"))[0],
                %roptions, pkgname => $args[0],
                destdir => $odir->name(),
            ) or do {
                warn $repsys->last_error() . "\n";
                warn "can't get final specfile\n";
                $exitstatus = 1;
                next;
            };
        } else {
            $bdir = getcwd();
        }
        RPM4::setverbosity('INFO');
        MDV::Repsys::build(
            $bdir,
            'b',
            %roptions, specfile => $specfile,
        ) or do {
            warn ((MDV::Repsys::repsys_error() || "") . "\n");
            warn "Build failed\n";
            $exitstatus = 1;
        };
        RPM4::setverbosity('WARNING');
        last;
    };

    /^stripcl$/ and do {
        my $specfile = $args[0] || (glob("SPECS/*.spec"))[0];
        if (! ($nocommit ?
            MDV::Repsys::strip_changelog($specfile) :
            $repsys->splitchangelog($specfile))) {
            warn $repsys->last_error() . "\n";
            warn "Can't extract changelog";
            $exitstatus = 1;
        }
        last;
    };

    /^info$/ and do {
        $args[0] or $args[0] = $repsys->get_pkgname_from_wc(); 
        $args[0] or pod2usage(1);
        my %info = $repsys->get_pkg_info($args[0], %roptions);
        if ($info{last_rev}) {

            printf(<<EOF,
Package:       %s
Size:          %d
Last Revision: %s
Last author:   %s
EOF
                $args[0],
                $info{size} || 0,
                $info{last_rev} || 0,
                $info{last_author} || 'N/A',
            ) 
        } else {
            print $args[0] . " is not in svn.\n";
        }
        last;
    };

    /^submit$/ and do {
        $args[0] or $args[0] = $repsys->get_pkgname_from_wc(); 
        $args[0] or pod2usage(1);
        
        if (! $roptions{revision}) {
           my %info = $repsys->get_pkg_info($args[0], %roptions);
           $roptions{revision} = $info{last_rev};
        }

        if (! $roptions{revision}) {
            warn "Package $args[0] not in svn\n";
            $exitstatus = 1;
	    last;
        }

	if (! $repsys->submit($args[0], %roptions)) {
            #warn $repsys->last_error() . "\n";
            warn "Can't submit $args[0]\n";
            $exitstatus = 1;
	    last;
        }

        print "Package submitted!\n";
        last;
    };


    pod2usage(1);
}

exit($exitstatus);

__END__

=head1 AUTHORS

Olivier Thauvin <nanardon@mandriva.org>

=head1 SEE ALSO

L<repsys>

=cut