#!/usr/bin/perl
-our $VERSION = '2014.01.28';
+package git::remote::gpg;
+package main;
+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.
use File::Copy;
use File::Path;
use File::Spec::Functions qw(:ALL);
- use File::Temp;
+ use File::Temp qw(tempdir);
use Getopt::Long;
use IPC::Run;
# NOTE: to debug: IPCRUNDEBUG=basic|data|details|gory
return $clear;
}
# grg remote I/O
+ # XXX: there is no locking mechanism
sub grg_remote_fetch_file ($) {
my ($ctx) = @_;
# NOTE: avoid File::Copy::copy().
IPC::Run::run([@{$ctx->{config}->{curl}}
, '--show-error'
, '--output', File::Spec->catfile($ctx->{'dir-cache'}, '#1')
- , File::Spec->catfile($ctx->{remote}->{uri}->as_string
- , '{'.join(',', (keys %{$ctx->{remote}->{fetch}})).'}') ])
+ , $ctx->{remote}->{uri}->as_string.'/'.'{'.join(',', (keys %{$ctx->{remote}->{fetch}})).'}' ]
+ , '>&2')
}
sub grg_remote_fetch ($$) {
my ($ctx, $files) = @_;
}
sub grg_remote_init_rsync ($) {
my ($ctx) = @_;
- my $tmp = File::Temp->tempdir('grg_rsync_XXXXXXXX', CLEANUP => 1);
+ my $tmp = tempdir('grg_rsync_XXXXXXXX', CLEANUP => 1);
my $uri = $ctx->{remote}->{uri}->clone;
my ($path, $dst);
if ($uri->opaque =~ m{^//}) {
}
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) = @_;
}
sub grg_remote_push_sftp ($) {
my ($ctx) = @_;
- my $uri = $ctx->{remote}->{uri}->clone;
- $uri->fragment('');
- $uri->query('');
+ 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(',', @{$ctx->{remote}->{push}}).'}'
- , $uri->as_string.'/'])
+ , File::Spec->catfile($ctx->{'dir-cache'},'{'.join(',', @{$ctx->{remote}->{push}}).'}')
+ , $uri->as_string.'/']
+ , '>&2')
}
sub grg_remote_push ($) {
my ($ctx) = @_;
, 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
# grg manifest
sub grg_manifest_fetch ($) {
my ($ctx) = @_;
+ debug(sub{'remote->checked='},$ctx->{remote}->{checked});
+ return
+ if defined $ctx->{remote}->{checked};
$ctx->{manifest} =
{ 'hidden-keys' => {}
, keys => {}
, packs => {}
, refs => {}
- , version => undef
+ , version => $VERSION
};
my $fetched = grg_remote_fetch($ctx, [$ctx->{'manifest-file'}]);
my $crypt = $fetched->{$ctx->{'manifest-file'}}->{path};
if (defined $crypt) {
- $ctx->{remote}->{checked} = 1;
my $json;
grg_decrypt_asymmetric($ctx, sub {
push @{$_[0]}, $crypt;
return (@_, '>', \$json); });
- rm($fetched->{$ctx->{'manifest-file'}}->{path})
- unless $fetched->{$ctx->{'manifest-file'}}->{preserve};
my $manifest;
($manifest = JSON::decode_json($json) and ref $manifest eq 'HASH')
or error("failed to decode JSON manifest");
+ $ctx->{remote}->{checked} = 1;
+ rm($fetched->{$ctx->{'manifest-file'}}->{path})
+ unless $fetched->{$ctx->{'manifest-file'}}->{preserve};
$ctx->{manifest} = {%{$ctx->{manifest}}, %$manifest};
foreach my $slot (qw(keys hidden-keys)) {
while (my ($fpr, $uid) = each %{$ctx->{manifest}->{$slot}}) {
}
}
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 @$push_refs == 0;
+ $manifest_refs->{HEAD} = 'ref: refs/heads/master'
+ unless defined $manifest_refs->{HEAD};
grg_manifest_push($ctx);
grg_disconnect($ctx);
}
, rsync => ['rsync']
}
, 'dir-cache' => undef
- , manifest => {}
+ , manifest => undef
, 'manifest-file' => undef
, remote =>
{ checking => 0
&mkdir($ctx->{'dir-cache'});
}
else {
- $ctx->{'dir-cache'} = File::Temp->tempdir('grg_cache_XXXXXXXX', CLEANUP => 1);
+ $ctx->{'dir-cache'} = tempdir('grg_cache_XXXXXXXX', CLEANUP => 1);
}
debug(sub{"ctx="},$ctx);
grg_commands($ctx);
=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