X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=infra%2Fdgit-repos-server;h=d2f94f1957e0bed922a0db052e2a81b921fa789a;hp=3f41a0bb9ba356093a6f2ce2259875b8b4fcb287;hb=8afbacc6da4ad5ccaf931d113df175bef22cc7b1;hpb=c00456f208d26767246b28e6f06f4462a76d9ac2 diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index 3f41a0bb..d2f94f19 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -124,10 +124,7 @@ sub acquirelock ($$) { 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]; @@ -200,16 +197,46 @@ sub policyhook { 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 () { @@ -217,6 +244,7 @@ sub makeworkingclone () { $workrepo = "$dgitrepos/_tmp/${package}_incoming$$"; acquiretree($workrepo, 1); runcmd qw(git clone -l -q --mirror), $destrepo, $workrepo; + rmtree "${workrepo}_fresh"; } sub setupstunthook () { @@ -234,6 +262,12 @@ END 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; @@ -273,6 +307,8 @@ sub maybeinstallprospective () { 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 $!; @@ -282,6 +318,7 @@ sub main__git_receive_pack () { makeworkingclone(); setupstunthook(); runcmd qw(git receive-pack), $workrepo; + dealwithfreshrepo(); maybeinstallprospective(); } @@ -504,9 +541,9 @@ sub checks () { debug "translated version $v"; $tagname eq "debian/$v" or die; - my ($policy) = policyhook(NOFFCHECK, 'push',$package, - $version,$suite,$tagname, - join(",",@delberatelies)); + $policy = policyhook(NOFFCHECK|FRESHREPO, 'push',$package, + $version,$suite,$tagname, + join(",",@delberatelies)); checksuite(); @@ -517,17 +554,24 @@ sub checks () { 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"; @@ -546,11 +590,9 @@ sub 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; @@ -633,19 +675,13 @@ sub parseargsdispatch () { my ($policy, $pollock) = policyhook(FRESHREPO,'check-package',$package); if ($policy & FRESHREPO) { - my $garbagerepo = "$dgitrepos/_tmp/${package}_garbage"; - acquiretree($garbagerepo,1); - rmtree $garbagerepo; - rename $realdestrepo, $garbagerepo - or $! == ENOENT - or die "rename repo $destrepo to $garbagerepo: $!"; + movetogarbage; } close $pollock or die $!; - if (stat $realdestrepo) { + if (stat_exists $realdestrepo) { $destrepo = $realdestrepo; } else { - $! == ENOENT or die "stat dest repo $destrepo: $!"; debug " fixmissing $funcn"; my $fixfunc = $main::{"fixmissing__$funcn"}; &$fixfunc;