#!/usr/bin/perl
-our $VERSION = '2014.01.28';
+our $VERSION = '2014.04.29';
# License
# This file is a git-remote-helpers(1) to use a gpg(1)
# as a cryptographic layer below git(1)'s objects.
croak("\e[31mERROR\e[m ", @_, "\n\t");
}
# System utilities
- sub rm ($) {
- my ($file) = @_;
- debug(sub{"file="},$file);
- unlink($file)
- or error("rm $file");
- }
- sub mkdir ($) {
- my ($dir) = @_;
- debug(sub{"dir=\"$dir\"\n"});
- File::Path::make_path($dir, {verbose=>0, error => \my $error});
- if (@$error) {
- for my $diag (@$error) {
- my ($dir, $message) = %$diag;
- if ($dir eq '') {
- print "general error: $message\n";
- }
- else {
- print "problem mkdir $dir: $message\n";
+ sub rm (@) {
+ foreach my $file (@_) {
+ debug(sub{"file=$file\n"});
+ if (-e $file) {
+ unlink($file)
+ or error("rm $file");
+ }
+ }
+ }
+ sub mkdir (@) {
+ foreach my $dir (@_) {
+ debug(sub{"dir=$dir\n"});
+ File::Path::make_path($dir, {verbose=>0, error => \my $error});
+ if (@$error) {
+ for my $diag (@$error) {
+ my ($dir, $message) = %$diag;
+ error("dir=$dir: $message");
}
}
}
}
sub grg_decrypt_symmetric ($$$;$) {
my ($ctx, $key, $run) = @_;
- debug(sub{'ctx='}, $ctx);
- debug(sub{'key='}, $key);
$run = sub {return @_} unless defined $run;
IPC::Run::run($run->([@{$ctx->{config}->{gpg}}
, '--batch', '--no-default-keyring', '--keyring', '/dev/null', '--secret-keyring', '/dev/null'
return $clear;
}
# grg remote I/O
- sub grg_remote_fetch_file ($$$) {
- my ($ctx, $files, $fetch_files) = @_;
+ sub grg_remote_fetch_file ($) {
+ my ($ctx) = @_;
# NOTE: avoid File::Copy::copy().
- while (my ($file, undef) = each %$fetch_files) {
+ while (my ($file, undef) = each %{$ctx->{remote}->{fetch}}) {
my $path = File::Spec->catfile($ctx->{remote}->{uri}->file, $file);
- debug(sub{'test path='}, $path);
if (-r $path) {
- my $h = $fetch_files->{$file};
+ my $h = $ctx->{remote}->{fetch}->{$file};
$h->{path} = $path;
$h->{preserve} = 1;
}
}
return 1;
}
- sub grg_remote_fetch_rsync ($$$) {
- my ($ctx, $files, $fetch_files) = @_;
+ sub grg_remote_fetch_rsync ($) {
+ my ($ctx) = @_;
my $uri = $ctx->{remote}->{uri}->clone;
- $uri->scheme(undef);
- $uri->fragment(undef);
- $uri->query(undef);
- $uri = $uri->as_string;
+ my @src;
+ if ($uri->opaque =~ m{^//}) {
+ $uri->fragment(undef);
+ $uri->query(undef);
+ @src = map { $uri->path($_); $uri->as_string; }
+ (keys %{$ctx->{remote}->{fetch}});
+ }
+ else {
+ my ($authority, $path, $fragment)
+ = $uri->as_string =~ m|^rsync:(?:([^/#:]+):)?([^?#]*)(?:#(.*))?$|;
+ @src = map { "$authority:$path/$_" }
+ (keys %{$ctx->{remote}->{fetch}});
+ }
IPC::Run::run([@{$ctx->{config}->{rsync}}
- , '--verbose', '--ignore-times', '--inplace', '--progress'
- , (map { File::Spec->catfile($uri, $_) } @$files)
+ , '-i', '--ignore-times', '--inplace', '--progress'
+ , @src
, $ctx->{'dir-cache'}.'/']
, '>&2')
}
- sub grg_remote_fetch_sftp ($$$) {
- my ($ctx, $files, $fetch_files) = @_;
+ sub grg_remote_fetch_sftp ($) {
+ my ($ctx) = @_;
IPC::Run::run([@{$ctx->{config}->{curl}}
, '--show-error'
, '--output', File::Spec->catfile($ctx->{'dir-cache'}, '#1')
- , File::Spec->catfile($ctx->{remote}->{uri}, '{'.join(',',@$files).'}') ])
+ , $ctx->{remote}->{uri}->as_string.'/'.'{'.join(',', (keys %{$ctx->{remote}->{fetch}})).'}' ]
+ , '>&2')
}
sub grg_remote_fetch ($$) {
my ($ctx, $files) = @_;
debug(sub{'files='}, $files);
my $scheme = $ctx->{remote}->{uri}->scheme;
- my $fetch_files = {map { $_ => { path => File::Spec->catfile($ctx->{'dir-cache'}, $_), preserve => 0 } } @$files};
+ $ctx->{remote}->{fetch}
+ = {map { $_ =>
+ { path => File::Spec->catfile($ctx->{'dir-cache'}, $_)
+ , preserve => 0 }
+ } @$files};
my $fct =
{ file => \&grg_remote_fetch_file
, rsync => \&grg_remote_fetch_rsync
}->{$scheme};
error("URL scheme not supported: `$scheme'")
unless $fct;
- debug(sub{'fetch_files='}, $fetch_files);
- $fct->($ctx, $files, $fetch_files)
- or $fetch_files = {};
- debug(sub{'fetch_files='}, $fetch_files);
- return $fetch_files;
+ $fct->($ctx)
+ or $ctx->{remote}->{fetch} = {};
+ return $ctx->{remote}->{fetch};
}
sub grg_remote_init_file ($) {
my ($ctx) = @_;
}
sub grg_remote_init_rsync ($) {
my ($ctx) = @_;
- my $tmp = File::Temp->tempdir(CLEANUP => 1);
- my $path = $ctx->{remote}->{uri}->path;
- my $uri = $ctx->{remote}->{uri}->clone;
- $uri->fragment(undef);
- $uri->path(undef);
- $uri->query(undef);
+ my $tmp = File::Temp->tempdir('grg_rsync_XXXXXXXX', CLEANUP => 1);
+ my $uri = $ctx->{remote}->{uri}->clone;
+ my ($path, $dst);
+ if ($uri->opaque =~ m{^//}) {
+ $uri->fragment(undef);
+ $uri->query(undef);
+ $path = $uri->path;
+ $dst = $uri->as_string;
+ }
+ else {
+ my ($authority, $fragment);
+ ($authority, $path, $fragment)
+ = $uri->as_string =~ m|^rsync:(?:([^/#:]+):)?([^?#]*)(?:#(.*))?$|;
+ $dst = "$authority:";
+ }
&mkdir(File::Spec->catdir($tmp, $path));
IPC::Run::run([@{$ctx->{config}->{rsync}}
- , '--verbose', '--recursive', '--relative'
+ , '-i', '--recursive', '--relative'
, '--exclude=*', '.'
- , File::Spec->catfile($uri->as_string)]
+ , $dst]
+ , '>&2'
, init => sub { chdir $tmp or die $!; })
}
sub grg_remote_init_sftp ($) {
my ($ctx) = @_;
- my $path = $ctx->{remote}->{uri}->path;
my $uri = $ctx->{remote}->{uri}->clone;
+ my ($path) = $uri->path =~ m|^/?(.*)$|;
$uri->fragment(undef);
$uri->path(undef);
$uri->query(undef);
IPC::Run::run([@{$ctx->{config}->{curl}}
, '--show-error', '--ftp-create-dirs'
, '-Q', "+mkdir ".$path
- , $uri->as_string])
+ , $uri->as_string]
+ , '>&2')
}
sub grg_remote_init ($) {
my ($ctx) = @_;
or error("remote init failed");
return;
}
- sub grg_remote_push_file ($$) {
- my ($ctx, $files) = @_;
+ sub grg_remote_push_file ($) {
+ my ($ctx) = @_;
my $ok = 1;
- foreach my $file (@$files) {
+ foreach my $file (@{$ctx->{remote}->{push}}) {
my $src = File::Spec->catfile($ctx->{'dir-cache'}, $file);
my $dst = File::Spec->catfile($ctx->{remote}->{uri}->file, $file);
debug(sub{"File::Copy::move('$src', '$dst')\n"});
}
return $ok;
}
- sub grg_remote_push_rsync ($$) {
- my ($ctx, $files) = @_;
- my $uri = $ctx->{remote}->{uri}->clone;
- $uri->fragment('');
- $uri->query('');
+ sub grg_remote_push_rsync ($) {
+ my ($ctx) = @_;
+ my $uri = $ctx->{remote}->{uri}->clone;
+ $uri->fragment(undef);
+ $uri->query(undef);
+ my ($path, $dst);
+ if ($uri->opaque =~ m{^//}) {
+ $uri->fragment(undef);
+ $uri->query(undef);
+ $dst = $uri->as_string;
+ }
+ else {
+ my ($authority, $path, $fragment)
+ = $uri->as_string =~ m|^rsync:(?:([^/#:]+):)?([^?#]*)(?:#(.*))?$|;
+ $dst = "$authority:$path/";
+ }
IPC::Run::run([@{$ctx->{config}->{rsync}}
- , '--verbose', '--relative'
- , @$files
- , $uri->as_string])
+ , '-i', '--relative'
+ , (@{$ctx->{remote}->{push}})
+ , $dst]
+ , '>&2'
+ , init => sub { chdir $ctx->{'dir-cache'} or die $!; });
}
- sub grg_remote_push_sftp ($$) {
- my ($ctx, $files) = @_;
- my $uri = $ctx->{remote}->{uri}->clone;
- $uri->fragment('');
- $uri->query('');
+ sub grg_remote_push_sftp ($) {
+ my ($ctx) = @_;
+ my $uri = $ctx->{remote}->{uri}->clone;
+ $uri->fragment(undef);
+ $uri->query(undef);
IPC::Run::run([@{$ctx->{config}->{curl}}
, '--show-error', '--ftp-create-dirs', '--upload-file'
- , '{'.join(',', @$files).'}'
- , $uri->as_string.'/'])
+ , File::Spec->catfile($ctx->{'dir-cache'},'{'.join(',', @{$ctx->{remote}->{push}}).'}')
+ , $uri->as_string.'/']
+ , '>&2')
}
sub grg_remote_push ($) {
my ($ctx) = @_;
}->{$scheme};
error("URL scheme not supported: `$scheme'")
unless $fct;
- $fct->($ctx, $ctx->{remote}->{push})
+ $fct->($ctx)
or error("remote push failed");
+ rm(map {File::Spec->catfile($ctx->{'dir-cache'}, $_)} @{$ctx->{remote}->{push}});
return 1;
}
sub grg_remote_remove ($) {
, sub { return (@_, '<', \$pack_data); });
error("pack data hash differs from pack manifest hash")
unless $pack_hash eq $manifest_pack->{hash};
- rm($pack_fetched)
+ rm($pack_fetched->{path})
unless $pack_fetched->{preserve};
IPC::Run::run(['git', 'index-pack', '-v', '--stdin']
, '<', \$pack_data
, keys => {}
, packs => {}
, refs => {}
- , version => undef
+ , version => $VERSION
};
my $fetched = grg_remote_fetch($ctx, [$ctx->{'manifest-file'}]);
my $crypt = $fetched->{$ctx->{'manifest-file'}}->{path};
}
}
else {
- debug(sub{'ctx='}, $ctx);
if ($ctx->{command} eq 'push' or $ctx->{command} eq 'list for-push') {
$ctx->{remote}->{checked} = 0;
}
my ($ctx, $command) = @_;
$ctx->{command} = $command;
grg_connect($ctx);
- while (my ($ref, $obj) = each %{$ctx->{manifest}->{refs}}) {
- gpg_command_answer("$obj $ref");
+ my $manifest_refs = $ctx->{manifest}->{refs};
+ while (my ($ref, $obj) = each %$manifest_refs) {
+ if ($obj =~ m|^ref: *(.*) *$|) {
+ $obj = $manifest_refs->{$1};
+ }
+ gpg_command_answer("$obj $ref")
+ if defined $obj;
};
gpg_command_answer("");
}
foreach my $ref (@$push_refs) {
$manifest_refs->{$ref->{dst}} = $ref->{src_obj};
}
- $manifest_refs->{HEAD}
- = $push_refs->[-1]->{src_obj}
- unless exists $manifest_refs->{HEAD}
- or @$push_refs == 0;
+ $manifest_refs->{HEAD} = 'ref: refs/heads/master'
+ unless defined $manifest_refs->{HEAD};
grg_manifest_push($ctx);
grg_disconnect($ctx);
}
&mkdir($ctx->{'dir-cache'});
}
else {
- $ctx->{'dir-cache'} = File::Temp->tempdir(CLEANUP => 1);
+ $ctx->{'dir-cache'} = File::Temp->tempdir('grg_cache_XXXXXXXX', CLEANUP => 1);
}
debug(sub{"ctx="},$ctx);
grg_commands($ctx);
=head2 Via rsync(1)
-=item git remote add $remote gpg::rsync://${user:+$user@}$host/$path
+=item git remote add $remote gpg::rsync:${user:+$user@}$host:$path
+
+=item git remote add $remote gpg::rsync://${user:+$user@}$host${port:+:$port}/$path
=head2 Via curl(1)
-=item git remote add $remote gpg::sftp://${user:+$user@}$host/$path
+=item git remote add $remote gpg::sftp://${user:+$user@}$host${port:+:$port}/$path
=head2 Via File::Copy(3pm)
=over 8
-=item B<grg.curl>
+=item B<grg.curl>, B<remote.$remote.curl>
-=item B<grg.gpg>
+=item B<grg.gpg>, B<remote.$remote.gpg>
-=item B<grg.keys>
+=item B<grg.keys>, B<remote.$remote.keys>
-=item B<grg.hidden-keys>
+=item B<grg.hidden-keys>, B<remote.$remote.hidden-keys>
-=item B<grg.manifest-hash-algo>
+=item B<grg.manifest-hash-algo>, B<remote.$remote.manifest-hash-algo>
-=item B<grg.pack-filename-size>
+=item B<grg.pack-filename-size>, B<remote.$remote.pack-filename-size>
-=item B<grg.pack-hash-algo>
+=item B<grg.pack-hash-algo>, B<remote.$remote.pack-hash-algo>
-=item B<grg.pack-key-size>
+=item B<grg.pack-key-size>, B<remote.$remote.pack-key-size>
-=item B<grg.signingkey>
+=item B<grg.signingkey>, B<remote.$remote.signingkey>
-=item B<grg.rsync>
+=item B<grg.rsync>, B<remote.$remote.rsync>
=back