use Fcntl qw(:flock);
use File::Path qw(rmtree);
-open DEBUG, ">/dev/null" or die $!;
+use Debian::Dgit qw(:DEFAULT :policyflags);
-our $package_re = '[0-9a-z][-+.0-9a-z]+';
+open DEBUG, ">/dev/null" or die $!;
our $func;
our $dgitrepos;
debug " locking $lock failed";
return undef;
}
- if (!stat $lock) {
- next if $! == ENOENT;
- die "stat $lock: $!";
- }
+ next unless stat_exists $lock;
my $want = (stat _)[1];
stat $fh or die $!;
my $got = (stat _)[1];
die "@_ $? $!" if $r;
}
+sub policyhook {
+ my ($policyallowbits, @polargs) = @_;
+ # => ($exitstatuspolicybitmap, $policylockfh);
+ die if $policyallowbits & ~0x3e;
+ my @cmd = ($policyhook,$distro,$repos,@polargs);
+ debugcmd @_;
+ my $r = system @_;
+ die "system: $!" if $r < 0;
+ die "hook (@cmd) failed ($?)" if $r & ~($policyallowbits << 8);
+ return $r >> 8;
+}
+
+sub mkemptyrepo ($$) {
+ my ($dir,$sharedperm) = @_;
+ runcmd qw(git init --bare --quiet), "--shared=$sharedperm", $dir;
+}
+
+sub mkrepo_fromtemplate ($) {
+ my ($dir) = @_;
+ my $template = "$dgitrepos/_template";
+ debug "copy tempalate $template -> $dir";
+ my $r = system qw(cp -a --), $template, $dir;
+ !$r or die "create new repo $dir failed: $r $!";
+}
+
+sub movetogarbage () {
+ my $garbagerepo = "$dgitrepos/_tmp/${package}_garbage";
+ acquiretree($garbagerepo,1);
+ rmtree $garbagerepo;
+ rename $realdestrepo, $garbagerepo
+ or $! == ENOENT
+ or die "rename repo $realdestrepo to $garbagerepo: $!";
+}
+
+sub onwardpush () {
+ my @cmd = (qw(git send-pack), $destrepo);
+ push @cmd, qw(--force) if $policy & NOFFCHECK;
+ push @cmd, "$commit:refs/dgit/$suite",
+ "$tagval:refs/tags/$tagname");
+ debugcmd @cmd;
+ $!=0;
+ my $r = system @cmd;
+ !$r or die "onward push to $destrepo failed: $r $!";
+}
+
#----- git-receive-pack -----
sub fixmissing__git_receive_pack () {
mkrepotmp();
$destrepo = "$dgitrepos/_tmp/${package}_prospective";
acquiretree($destrepo, 1);
- my $template = "$dgitrepos/_template";
- debug "fixmissing copy tempalate $template -> $destrepo";
- my $r = system qw(cp -a --), $template, $destrepo;
- !$r or die "create new repo failed failed: $r $!";
+ mkrepo_fromtemplate($destrepo);
}
sub makeworkingclone () {
$workrepo = "$dgitrepos/_tmp/${package}_incoming$$";
acquiretree($workrepo, 1);
runcmd qw(git clone -l -q --mirror), $destrepo, $workrepo;
+ rmtree "${workrepo}_fresh";
}
sub setupstunthook () {
debug " stunt hook set up $prerecv";
}
+sub dealwithfreshrepo () {
+ my $freshrepo = "${workrepo}_fresh";
+ return unless stat_exists $freshrepo;
+ $destrepo = $freshrepo;
+}
+
sub maybeinstallprospective () {
return if $destrepo eq $realdestrepo;
die Dumper(\%got)." -- missing refs in new repo"
if grep { !$_ } values %got;
+ movetogarbage; # in case of FRESHREPO
+
debug "install $destrepo => $realdestrepo";
rename $destrepo, $realdestrepo or die $!;
remove "$destrepo.lock" or die $!;
makeworkingclone();
setupstunthook();
runcmd qw(git receive-pack), $workrepo;
+ dealwithfreshrepo();
maybeinstallprospective();
}
debug "translated version $v";
$tagname eq "debian/$v" or die;
+ $policy = policyhook(NOFFCHECK|FRESHREPO, 'push',$package,
+ $version,$suite,$tagname,
+ join(",",@delberatelies));
+
checksuite();
# check that our ref is being fast-forwarded
debug "oldcommit $oldcommit";
- if ($oldcommit =~ m/[^0]/) {
+ if (!($policy & NOFFCHECK) && $oldcommit =~ m/[^0]/) {
$?=0; $!=0; my $mb = `git merge-base $commit $oldcommit`;
chomp $mb;
$mb eq $oldcommit or reject "not fast forward on dgit branch";
}
-}
-sub onwardpush () {
- my @cmd = (qw(git send-pack), $destrepo,
- "$commit:refs/dgit/$suite",
- "$tagval:refs/tags/$tagname");
- debugcmd @cmd;
- $!=0;
- my $r = system @cmd;
- !$r or die "onward push failed: $r $!";
-}
+ if ($policy & FRESHREPO) {
+ # This is troublesome. We have been asked by the policy hook
+ # to receive the push into a fresh repo. But of course we
+ # have actually already mostly received the push into the working
+ # repo. (This is unavoidable because the instruction to use a new
+ # repo comes ultimately from the signed tag for the dgit push,
+ # which has to have been received into some repo.)
+ #
+ # So what we do is generate a fresh working repo right now and
+ # push the head and tag into it. The presence of this fresh
+ # working repo is detected by the parent, which responds by
+ # making a fresh master repo from the template.
+
+ $destrepo = "${workrepo}_fresh"; # workrepo lock covers
+ mkrepo_fromtemplate $destrepo;
+ }
+}
sub stunthook () {
debug "stunthook";
sub fixmissing__git_upload_pack () {
$destrepo = "$dgitrepos/_empty";
my $lfh = acquiretree($destrepo,1);
- return if stat $destrepo;
- die $! unless $!==ENOENT;
+ return if stat_exists $destrepo;
rmtree "$destrepo.new";
- umask 022;
- runcmd qw(git init --bare --quiet), "$destrepo.new";
+ mkemptyrepo "$destrepo.new", "0644";
rename "$destrepo.new", $destrepo or die $!;
unlink "$destrepo.lock" or die $!;
close $lfh;
reject "unknown method" unless $mainfunc;
- if (stat $realdestrepo) {
+ my ($policy, $pollock) = policyhook(FRESHREPO,'check-package',$package);
+ if ($policy & FRESHREPO) {
+ movetogarbage;
+ }
+ close $pollock or die $!;
+
+ if (stat_exists $realdestrepo) {
$destrepo = $realdestrepo;
} else {
- $! == ENOENT or die "stat dest repo $destrepo: $!";
debug " fixmissing $funcn";
my $fixfunc = $main::{"fixmissing__$funcn"};
&$fixfunc;