X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=infra%2Fdgit-repos-server;h=f7d1b045b82c53af39c5144e366b43e65ce223f4;hp=1be6e78d26613f27ce3a172cd2bbb0962d5780da;hb=349b41c2bded6dea53dd947e4ee5c16867b6d055;hpb=4a1b8fa04cf960003af5b2bc3c54687a0e9d6945 diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index 1be6e78d..f7d1b045 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -9,8 +9,10 @@ # --suites=SUITES-FILE default DISTRO-DIR/suites # --suites-master=SUITES-FILE default DISTRO-DIR/suites-master # --policy-hook=POLICY-HOOK default DISTRO-DIR/policy-hook +# --mirror-hook=MIRROR-HOOK default DISTRO-DIR/mirror-hook # --dgit-live=DGIT-LIVE-DIR default DISTRO-DIR/dgit-live -# (DISTRO-DIR is not used other than as default and to pass to policy hook) +# (DISTRO-DIR is not used other than as default and to pass to policy +# and mirror hooks) # internal usage: # .../dgit-repos-server --pre-receive-hook PACKAGE # @@ -31,7 +33,9 @@ # (With --cron AUTH-SPEC is not used and may be the empty string.) use strict; -$SIG{__WARN__} = sub { die $_[0]; }; + +use Debian::Dgit qw(:DEFAULT :policyflags); +setup_sigwarn(); # DGIT-REPOS-DIR contains: # git tree (or other object) lock (in acquisition order, outer first) @@ -65,7 +69,7 @@ $SIG{__WARN__} = sub { die $_[0]; }; # as a result of this the stunt pre-receive hook runs; it does this: # + understand what refs we are allegedly updating and # check some correspondences: -# * we are updating only refs/tags/DISTRO/* and refs/dgit/* +# * we are updating only refs/tags/[archive/]DISTRO/* and refs/dgit/* # * and only one of each # * and the tag does not already exist # and @@ -82,7 +86,7 @@ $SIG{__WARN__} = sub { die $_[0]; }; # * the signed tag must refer to a commit # * the signed tag commit must be the refs/dgit value # * the name in the signed tag must correspond to its ref name -# * the tag name must be debian/ (massaged as needed) +# * the tag name must be [archive/]debian/ (massaged as needed) # * the suite is one of those permitted # * the signed tag has a suitable name # * run the "push" policy hook @@ -119,7 +123,7 @@ $SIG{__WARN__} = sub { die $_[0]; }; # a stampfile whose presence indicates that there may be # cleanup to do # -# Policy hook script is invoked like this: +# Policy hook scripts are invoked like this: # POLICY-HOOK-SCRIPT DISTRO DGIT-REPOS-DIR DGIT-LIVE-DIR DISTRO-DIR ACTION... # ie. # POLICY-HOOK-SCRIPT ... check-list [...] @@ -131,7 +135,8 @@ $SIG{__WARN__} = sub { die $_[0]; }; # # DELIBERATELIES is like this: --deliberately-foo,--deliberately-bar,... # -# Exit status is a bitmask. Bit weight constants are defined in Dgit.pm. +# Exit status of policy hook is a bitmask. +# Bit weight constants are defined in Dgit.pm. # NOFFCHECK (2) # suppress dgit-repos-server's fast-forward check ("push" only) # FRESHREPO (4) @@ -168,15 +173,24 @@ $SIG{__WARN__} = sub { die $_[0]; }; # If policy hook wants to run dgit (or something else in the dgit # package), it should use DGIT-LIVE-DIR/dgit (etc.), or if that is # ENOENT, use the installed version. - +# +# Mirror hook scripts are invoked like this: +# MIRROR-HOOK-SCRIPT DISTRO-DIR ACTION... +# and currently there is only one action invoked by dgit-repos-server: +# MIRROR-HOOK-SCRIPT DISTRO-DIR updated-hook PACKAGE [...] +# +# Exit status of the mirror hook is advisory only. The mirror hook +# runs too late to do anything useful about a problem, so the only +# effect of a mirror hook exiting nonzero is a warning message to +# stderr (which the pushing user should end up seeing). +# +# If the mirror hook does not exist, it is silently skipped. use POSIX; use Fcntl qw(:flock); use File::Path qw(rmtree); use File::Temp qw(tempfile); -use Debian::Dgit qw(:DEFAULT :policyflags); - initdebug(''); our $func; @@ -186,6 +200,7 @@ our $distro; our $suitesfile; our $suitesformasterfile; our $policyhook; +our $mirrorhook; our $dgitlive; our $distrodir; our $destrepo; @@ -278,7 +293,7 @@ sub policyhook { # => ($exitstatuspolicybitmap); die if $policyallowbits & ~0x3e; my @cmd = ($policyhook,$distro,$dgitrepos,$dgitlive,$distrodir,@polargs); - debugcmd '+',@cmd; + debugcmd '+M',@cmd; my $r = system @cmd; die "system: $!" if $r < 0; die "dgit-repos-server: policy hook failed (or rejected) ($?)\n" @@ -327,7 +342,8 @@ sub movetogarbage () { ensuredir "$dgitrepos/_removed-tags"; open PREVIOUS, ">>", removedtagsfile or die removedtagsfile." $!"; - git_for_each_ref('refs/tags/'.debiantag('*',$distro), sub { + git_for_each_ref([ map { 'refs/tags/'.$_ } debiantags('*',$distro) ], + sub { my ($objid,$objtype,$fullrefname,$reftail) = @_; print PREVIOUS "\n$objid $reftail .\n" or die $!; }, $real); @@ -390,6 +406,23 @@ sub dealwithfreshrepo () { $destrepo = $freshrepo; } +sub mirrorhook { + my @cmd = ($mirrorhook,$distrodir,@_); + debugcmd '+',@cmd; + return unless stat_exists $mirrorhook; + my $r = system @cmd; + if ($r) { + printf STDERR <> 8) : + "wait status $?"); + } +} + sub maybeinstallprospective () { return if $destrepo eq realdestrepo; @@ -447,6 +480,7 @@ sub main__git_receive_pack () { runcmd qw(git receive-pack), $workrepo; dealwithfreshrepo(); maybeinstallprospective(); + mirrorhook('updated-hook', $package); } #----- stunt post-receive hook ----- @@ -463,7 +497,7 @@ sub readupdates () { printdebug " upd.| $_\n"; m/^(\S+) (\S+) (\S+)$/ or die "$_ ?"; my ($old, $sha1, $refname) = ($1, $2, $3); - if ($refname =~ m{^refs/tags/(?=$distro/)}) { + if ($refname =~ m{^refs/tags/(?=(?:archive/)?$distro/)}) { reject "pushing multiple tags!" if defined $tagname; $tagname = $'; #'; $tagval = $sha1; @@ -591,7 +625,7 @@ sub dm_txt_check ($$) { printdebug " dm_txt_check $keyid $dmtxtfn\n"; open DT, '<', $dmtxtfn or die "$dmtxtfn $!"; while (
) { - m/^fingerprint:\s+$keyid$/oi + m/^fingerprint:\s+\Q$keyid\E$/oi ..0 or next; if (s/^allow:/ /i..0) { } else { @@ -788,9 +822,16 @@ sub checks () { tagh1('object') eq $commit or reject "tag refers to wrong commit"; tagh1('tag') eq $tagname or reject "tag name in tag is wrong"; - my $expecttagname = debiantag $version, $distro; - printdebug "expected tag $expecttagname\n"; - $tagname eq $expecttagname or die; + my @expecttagnames = debiantags($version, $distro); + printdebug "expected tag @expecttagnames\n"; + grep { $tagname eq $_ } @expecttagnames or die; + + foreach my $othertag (grep { $_ ne $tagname } @expecttagnames) { + reject "tag $othertag (pushed with differing dgit version)". + " already exists -". + " not replacing previously-pushed version" + if git_get_ref "refs/tags/".$othertag; + } lockrealtree(); @@ -928,11 +969,12 @@ our %indistrodir = ( 'suites' => \$suitesfile, 'suites-master' => \$suitesformasterfile, 'policy-hook' => \$policyhook, + 'mirror-hook' => \$mirrorhook, 'dgit-live' => \$dgitlive, ); our @hookenvs = qw(distro suitesfile suitesformasterfile policyhook - dgitlive keyrings dgitrepos distrodir); + mirrorhook dgitlive keyrings dgitrepos distrodir); # workrepo and destrepo handled ad-hoc