#!/usr/bin/perl -w
use strict;
use lib qw{.} ;
use SVN::Core '0.32';
use SVN::Push;
use Getopt::Long ;


=head1 NAME

svnpush - command line interface for remote Subversion repository push

=head1 SYNOPSIS

    % svnpush init http://hosta/path http://hostb/path

    # run the actual mirroring
    % svnpush push http://hosta/path http://hostb/path

=head1 DESCRIPTION

F<svnpush> push a repository to another repository or parts of a
repository to another repository

=head1 COMMANDS

=over

=item init B<srcurl> B<desturl> 

Initialize the B<desturl> repository to be pushed from B<srcurl>. 

=item check B<srcurl> B<desturl> 

Check if B<desturl> repository was pushed from B<srcurl> and if it is
up to date. 

=item push [options] B<srcurl> B<desturl> 

Invoke the push of B<srcurl> to B<desturl>

Possible options:

=over

=item -c --create

Initialzie B<desturl> for pushing if not already done

=item -m --message=<text>

Use <text> for B<every> commit that is done during push

=item -r --revision=<from>:<to>

Push only changes between (including) the two given revision.
Revision can also be C<HEAD> which means the newest revision in
the repository.

=back

=item walk [options] B<srcurl> B<desturl> B<regex> B<repos1> .. B<reposN> 

Invoke the push of for all reositories underneath B<srcurl> to B<desturl> 
given with as B<repos1> .. B<reposN>. Only directories matching B<regex>
are replicated.

Possible options:

=over

=item -c --create

Initialzie B<desturl> for pushing if not already done

=item -m --message=<text>

Use <text> for B<every> commit that is done during push

=back


=back

=cut

# --------------------------------------------------------------------------

sub do_help {
    require Pod::Text;
    my $parser = Pod::Text->new (sentence => 0, width => 78);
    $parser->parse_from_file ($0, '-' );
}

# --------------------------------------------------------------------------

sub do_init {
    die "$0 init <source> <target>" unless $#_ == 1;
    my ($source, $target) = @_;
    my $m = SVN::Push->new( target  => $target,
                       		source  => $source);
    $m -> create_target ;
}

# --------------------------------------------------------------------------

sub opt_walk { return ('create|c', 'message|m:s') }

sub do_walk 
    {
    die "$0 walk [--create] [--message=<text>] <source> <target> <pattern> [<repos1> .. <reposN>]\n" unless $#_ >= 2;
    my ($options, $source, $target, $pattern, $logmsg) = @_;
    my $m = SVN::Push::walk($source, $target, $pattern, [@_[3..$#_]],
                             $options -> {create}, $options -> {message}) ;
    }

# --------------------------------------------------------------------------

sub opt_push { return ('create|c', 'message|m:s', 'revision|r:s') }


sub do_push 
    {
    die "$0 push [--create] [--message=<text>] [--revision=<from>:<to>] <source> <target>\n" unless $#_ >= 2;
    my ($options, $source, $target) = @_;

    my %revs ;
    if ($options -> {revision})
	{
        my ($start, $end) = split (/:/, $options -> {revision}, 2) ;	
	%revs = (startrev => $start, endrev => $end) ;
	}

    my $m = SVN::Push->new( target  => $target,
                       	    source  => $source,
			    %revs,
                       	    logmsg  => $options -> {message});

    if ($m->init ($options -> {create}) > 0)
    	{
    	$m->run;
    	}
    }

# --------------------------------------------------------------------------

sub do_check 
    {
    die "$0 check <source> <target>\n" unless $#_ >= 2;
    my ($options, $source, $target) = @_ ;
    my $m = SVN::Push->new(target => $target,
                           source => $source);

    $m->init;
    }

# --------------------------------------------------------------------------

sub mergeback {
    my ($path, $branch_path, $repospath, $rev) = @_;
    my $pool = SVN::Pool->new_default;
	
    my $m = SVN::Push->new(target_path => $path, target => $repospath,
			     pool => $pool, 
			     get_source => 1);
    $m->init;
    $m->mergeback ($rev-1, $branch_path, $rev);
}

# --------------------------------------------------------------------------

my $cmd = shift || 'help';

my $cmdsub = "do_$cmd" ;
my $cmdopt = "opt_$cmd" ;

die "Command not recognized. Try $0 help\n" unless main->can($cmdsub);

no strict 'refs';

my %options ;
if (main -> can ($cmdopt))
    {
    eval { Getopt::Long::Configure ('bundling') } ;
    $@ = "" ;
    my $ret = GetOptions (\%options, &$cmdopt()) ;
    }


&$cmdsub(\%options, @ARGV);


=head1 AUTHORS

Gerald Richter E<lt>richter@dev.ecos.deE<gt>

=head1 CREDITS

A lot of ideas and code is taken from SVN::Mirror by
Chia-liang Kao E<lt>clkao@clkao.orgE<gt>

=head1 COPYRIGHT

Copyright 2004 by Gerald Richter E<lt>richter@dev.ecos.deE<gt>

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>

=cut

1;
