fixed up several broken URLs (minor but annoying)
[gitolite.git] / src / commands / rsync
blobc7b25d187800057eb060c85b364eb3b12ba689ab
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
5 use lib $ENV{GL_LIBDIR};
6 use Gitolite::Easy;
8 =for admins
10 BUNDLE SUPPORT
12 (1) For each repo in gitolite.conf for which you want bundle support (or
13 '@all', if you wish), add the following line:
15 option bundle = 1
17 Or you can say:
19 option bundle.ttl = <number>
21 A bundle file that is more than <number> seconds old (default value
22 86400, i.e., 1 day) is recreated on the next bundle request. Increase
23 this if your repo is not terribly active.
25 Note: a bundle file is also deleted and recreated if it contains a ref
26 that was then either deleted or rewound in the repo. This is checked
27 on every invocation.
29 (2) Add 'rsync' to the ENABLE list in the rc file
31 =cut
33 =for usage
34 rsync helper for gitolite
36 BUNDLE SUPPORT
38 Admins: see src/commands/rsync for setup instructions
40 Users:
41 rsync git@host:repo.bundle .
42 # downloads a file called "<basename of repo>.bundle"; repeat as
43 # needed till the whole thing is downloaded
44 git clone repo.bundle repo
45 cd repo
46 git remote set-url origin git@host:repo
47 git fetch origin # and maybe git pull, etc. to freshen the clone
49 NOTE on options to the rsync command: you are only allowed to use the
50 "-v", "-n", "-q", and "-P" options.
52 =cut
54 usage() if not @ARGV or $ARGV[0] eq '-h';
56 # rsync driver program. Several things can be done later, but for now it
57 # drives just the 'bundle' transfer.
59 if ( $ENV{SSH_ORIGINAL_COMMAND} =~ /^rsync --server --sender (?:-[vn]*(?:e\d*\.\w*)? )?\. (\S+)\.bundle$/ ) {
61 my $repo = $1;
62 $repo =~ s/\.git$//;
64 # all errors have the same message to avoid leaking info
65 can_read($repo) or _die "you are not authorised";
66 my %config = config( $repo, "gitolite-options.bundle" ) or _die "you are not authorised";
68 my $ttl = $config{'gitolite-options.bundle.ttl'} || 86400; # in seconds (default 1 day)
70 my $bundle = bundle_create( $repo, $ttl );
72 $ENV{SSH_ORIGINAL_COMMAND} =~ s( \S+\.bundle)( $bundle);
73 trace( 1, "rsync bundle", $ENV{SSH_ORIGINAL_COMMAND} );
74 Gitolite::Common::_system( split ' ', $ENV{SSH_ORIGINAL_COMMAND} );
75 exit 0;
78 _warn "Sorry, you are only allowed to use the '-v', '-n', '-q', and '-P' options.";
79 usage();
81 # ----------------------------------------------------------------------
82 # helpers
83 # ----------------------------------------------------------------------
85 sub bundle_create {
86 my ( $repo, $ttl ) = @_;
87 my $bundle = "$repo.bundle";
88 $bundle =~ s(.*/)();
89 my $recreate = 0;
91 my ( %b, %r );
92 if ( -f $bundle ) {
93 %b = map { chomp; reverse split; } `git ls-remote --heads --tags $bundle`;
94 %r = map { chomp; reverse split; } `git ls-remote --heads --tags .`;
96 for my $ref ( sort keys %b ) {
98 my $mtime = ( stat $bundle )[9];
99 if ( time() - $mtime > $ttl ) {
100 trace( 1, "bundle too old" );
101 $recreate++;
102 last;
105 if ( not $r{$ref} ) {
106 trace( 1, "ref '$ref' deleted in repo" );
107 $recreate++;
108 last;
111 if ( $r{$ref} eq $b{$ref} ) {
112 # same on both sides; ignore
113 delete $r{$ref};
114 delete $b{$ref};
115 next;
118 `git rev-list --count --left-right $b{$ref}...$r{$ref}` =~ /^(\d+)\s+(\d+)$/ or _die "git too old";
119 if ($1) {
120 trace( 1, "ref '$ref' rewound in repo" );
121 $recreate++;
122 last;
127 } else {
128 trace( 1, "no bundle found" );
129 $recreate++;
132 return $bundle if not $recreate;
134 trace( 1, "creating bundle for '$repo'" );
135 -f $bundle and ( unlink $bundle or die "a horrible death" );
136 system("git bundle create $bundle --branches --tags >&2");
138 return $bundle;
141 sub trace {
142 Gitolite::Common::trace(@_);