summaryrefslogtreecommitdiff
blob: d74a8a4923b3d9a8861fda0737e25f271d4b332c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell
use strict;
use SVN::Core '0.32';
use SVN::Mirror;

=head1 NAME

svm - command line interface for remote Subversion repository mirroring

=head1 SYNOPSIS

    # the svn repository for svm to use
    % setenv SVMREPOS ~/svm

    # set the path mirror/svn to mirror official subversion trunk
    % svm init mirror/svn http://svn.collab.net/repos/svn/trunk

    # run the actual mirroring
    # flatten the changesets between revision 1 thru 6000
    % svm sync mirror/svn 6000

    # merge back changes in local branch
    % svn cp file://$SVMREPOS/mirror/svn file://$SVMREPOS/svn-local
    # make some changes and then merge back to source repository
    % svm mergeback mirror/svn svn-local

=head1 DESCRIPTION

F<svm> mirrors remote repository accissible via L<SVN::Ra> interface
to a local repository.

=head1 COMMANDS

=over

=item init B<path> B<url>

Initialize the B<path> in svm repository to mirror from B<url>.

=item sync B<path> B<[sync_to]>

Invoke the synchronization of B<path> in svm repository according the
how it is initialized.

=back

=cut

my $repospath = $ENV{SVMREPOS} || $ENV{HOME}.'/svn/svm';
my $auth = SVN::Core::auth_open ([SVN::Client::get_simple_provider,
				  SVN::Client::get_ssl_server_trust_file_provider,
				  SVN::Client::get_username_provider]);

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

sub init {
    die "$0 init <path> <source>" unless $#_ == 1;
    my ($path, $source) = @_;
    my $m = SVN::Mirror->new(target_path => $path, target => $repospath,
			     auth => $auth,
			     source => $source, target_create => 1);
    $m->init;
}

sub ls {
    my $m = SVN::Mirror->new(target => $repospath);

    $m->list;
}

sub can_continue {
    $_ = $@;
    return 1 if
	m/Connection reset by peer/ ||
	m/connection timed out/;
}

sub unlock {
    my $path = shift;
    my $what = shift;
    my $pool = SVN::Pool->new_default;
    my $m = SVN::Mirror->new(target_path => $path, target => $repospath,
			     pool => $pool, auth => $auth,
			     get_source => 1);

    $m->unlock($what);

}

sub sync {
    my $path = shift;
    my $skip_to = shift;
    my $pool = SVN::Pool->new_default;
    my $m = SVN::Mirror->new(target_path => $path, target => $repospath,
			     pool => $pool, auth => $auth,
			     get_source => 1, skip_to => $skip_to);

    while (1) {
	eval {
	    $m->init;
	    $m->run;
	};
	last unless $@;

	warn $@;
	$m->{pool} = SVN::Pool->new_default;
	$m = SVN::Mirror->new(%$m);
	last unless can_continue;
	print "retry...\n";
	sleep 5;
    }

}

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

my $cmd = shift || 'help';

die "command not recognized" unless main->can($cmd);

no strict 'refs';

&$cmd(@ARGV);

=head1 AUTHORS

Chia-liang Kao E<lt>clkao@clkao.orgE<gt>

=head1 COPYRIGHT

Copyright 2003 by Chia-liang Kao E<lt>clkao@clkao.orgE<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