X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=infra%2Fdgit-repos-server;h=0d55aa133b01679ffaeb5b6d88d01d2ae2189964;hp=d3d711f178ab99fda55dbe849fd77114f98b6e01;hb=08350aa0ad7092bd26e7fff5a563dec7a4e682e7;hpb=07bdd0fbd6a2cf1c0b175afe1e075bb566ed1f2c diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index d3d711f1..0d55aa13 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -2,10 +2,14 @@ # dgit-repos-server # # usages: -# .../dgit-repos-server DISTRO SUITES KEYRING-AUTH-SPEC \ -# DGIT-REPOS-DIR POLICY-HOOK-SCRIPT --ssh -# .../dgit-repos-server DISTRO SUITES KEYRING-AUTH-SPEC \ -# DGIT-REPOS-DIR POLICY-HOOK-SCRIPT --cron +# dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --ssh +# dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --cron +# settings +# --repos=GIT-REPOS-DIR default DISTRO-DIR/repos/ +# --suites=SUITES-FILE default DISTRO-DIR/suites +# --policy-hook=POLICY-HOOK default DISTRO-DIR/policy-hook +# --dgit-live=DGIT-LIVE-DIR default DISTRO-DIR/dgit-live +# (DISTRO-DIR is not used other than as default) # internal usage: # .../dgit-repos-server --pre-receive-hook PACKAGE # @@ -16,13 +20,14 @@ # SUITES is the name of a file which lists the permissible suites # one per line (#-comments and blank lines ignored) # -# KEYRING-AUTH-SPEC is a :-separated list of +# AUTH-SPEC is a :-separated list of # KEYRING.GPG,AUTH-SPEC # where AUTH-SPEC is one of # a # mDM.TXT use strict; +$SIG{__WARN__} = sub { die $_[0]; }; # DGIT-REPOS-DIR contains: # git tree (or other object) lock (in acquisition order, outer first) @@ -111,7 +116,7 @@ use strict; # cleanup to do # # Policy hook script is invoked like this: -# POLICY-HOOK-SCRIPT DISTRO DGIT-REPOS-DIR ACTION... +# POLICY-HOOK-SCRIPT DISTRO DGIT-REPOS-DIR DGIT-LIVE-DIR ACTION... # ie. # POLICY-HOOK-SCRIPT ... check-list [...] # POLICY-HOOK-SCRIPT ... check-package PACKAGE [...] @@ -142,6 +147,9 @@ use strict; # First, without any locking, check-list is called. It should produce # a list of package names. Then check-package will be invoked for # each named package, in each case after taking an appropriate lock. +# +# If policy hook wants to run dgit (or something else in the dgit +# package), it should use DGIT-LIVE-DIR/dgit (etc.) use POSIX; @@ -158,7 +166,7 @@ our $package; our $distro; our $suitesfile; our $policyhook; -our $realdestrepo; +our $dgitlive; our $destrepo; our $workrepo; our $keyrings; @@ -174,6 +182,8 @@ sub debug { print DEBUG "$debug @_\n"; } +sub realdestrepo () { "$dgitrepos/$package.git"; } + sub acquirelock ($$) { my ($lock, $must) = @_; my $fh; @@ -212,7 +222,7 @@ sub locksometree ($) { } sub lockrealtree () { - locksometree($realdestrepo); + locksometree(realdestrepo); } sub mkrepotmp () { @@ -261,11 +271,12 @@ sub policyhook { my ($policyallowbits, @polargs) = @_; # => ($exitstatuspolicybitmap); die if $policyallowbits & ~0x3e; - my @cmd = ($policyhook,$distro,$dgitrepos,@polargs); + my @cmd = ($policyhook,$distro,$dgitrepos,$dgitlive,@polargs); debugcmd @cmd; my $r = system @cmd; die "system: $!" if $r < 0; die "hook (@cmd) failed ($?)" if $r & ~($policyallowbits << 8); + debug sprintf "hook (%s) => %#x", "@polargs", $r; return $r >> 8; } @@ -284,7 +295,7 @@ sub mkrepo_fromtemplate ($) { } sub movetogarbage () { - # $realdestrepo must have been locked + # realdestrepo must have been locked my $garbagerepo = "$dgitrepos/${package}_garbage"; # We arrange to always keep at least one old tree, for anti-rewind # purposes (and, I guess, recovery from mistakes). This is either @@ -298,7 +309,7 @@ sub movetogarbage () { } rename "$garbagerepo", "$garbagerepo-old" or die "$garbagerepo $!"; } - rename $realdestrepo, $garbagerepo + rename realdestrepo, $garbagerepo or $! == ENOENT or die "$garbagerepo $!"; } @@ -344,7 +355,7 @@ sub dealwithfreshrepo () { } sub maybeinstallprospective () { - return if $destrepo eq $realdestrepo; + return if $destrepo eq realdestrepo; if (open REJ, "<", "$workrepo/drs-error") { local $/ = undef; @@ -388,8 +399,8 @@ sub maybeinstallprospective () { movetogarbage; } - debug "install $destrepo => $realdestrepo"; - rename $destrepo, $realdestrepo or die $!; + debug "install $destrepo => ".realdestrepo; + rename $destrepo, realdestrepo or die $!; remove "$destrepo.lock" or die $!; } @@ -783,47 +794,20 @@ sub argval () { return $v; } -sub parseargsdispatch () { - die unless @ARGV; +our %indistrodir = ( + # keys are used for DGIT_DRS_XXX too + 'repos' => \$dgitrepos, + 'suites' => \$suitesfile, + 'policy-hook' => \$policyhook, + 'dgit-live' => \$dgitlive, + ); - delete $ENV{'GIT_DIR'}; # if not run via ssh, our parent git process - delete $ENV{'GIT_PREFIX'}; # sets these and they mess things up - - if ($ENV{'DGIT_DRS_DEBUG'}) { - $debug='='; - open DEBUG, ">&STDERR" or die $!; - } - - if ($ARGV[0] eq '--pre-receive-hook') { - if ($debug) { $debug.="="; } - shift @ARGV; - @ARGV == 1 or die; - $package = shift @ARGV; - defined($distro = $ENV{'DGIT_DRS_DISTRO'}) or die; - defined($dgitrepos = $ENV{'DGIT_DRS_REPOS'}) or die; - defined($suitesfile = $ENV{'DGIT_DRS_SUITES'}) or die; - defined($workrepo = $ENV{'DGIT_DRS_WORK'}) or die; - defined($destrepo = $ENV{'DGIT_DRS_DEST'}) or die; - defined($keyrings = $ENV{'DGIT_DRS_KEYRINGS'}) or die $!; - defined($policyhook = $ENV{'DGIT_DRS_POLICYHOOK'}) or die $!; - open STDOUT, ">&STDERR" or die $!; - eval { - stunthook(); - }; - if ($@) { - recorderror "$@" or die; - die $@; - } - exit 0; - } +our @hookenvs = qw(distro suitesfile policyhook dgitlive keyrings dgitrepos); - $ENV{'DGIT_DRS_DISTRO'} = $distro = argval(); - $ENV{'DGIT_DRS_SUITES'} = $suitesfile = argval(); - $ENV{'DGIT_DRS_KEYRINGS'} = $keyrings = argval(); - $ENV{'DGIT_DRS_REPOS'} = $dgitrepos = argval(); - $ENV{'DGIT_DRS_POLICYHOOK'} = $policyhook = argval(); +# workrepo and destrepo handled ad-hoc - die unless @ARGV==1 && $ARGV[0] eq '--ssh'; +sub mode_ssh () { + die if @ARGV; my $cmd = $ENV{'SSH_ORIGINAL_COMMAND'}; $cmd =~ m{ @@ -838,7 +822,6 @@ sub parseargsdispatch () { or reject "command string not understood"; my $method = $1; $package = $2; - $realdestrepo = "$dgitrepos/$package.git"; my $funcn = $method; $funcn =~ y/-/_/; @@ -855,8 +838,8 @@ sub parseargsdispatch () { close $lfh; - if (stat_exists $realdestrepo) { - $destrepo = $realdestrepo; + if (stat_exists realdestrepo) { + $destrepo = realdestrepo; } else { debug " fixmissing $funcn"; my $fixfunc = $main::{"fixmissing__$funcn"}; @@ -867,6 +850,60 @@ sub parseargsdispatch () { &$mainfunc; } +sub parseargsdispatch () { + die unless @ARGV; + + delete $ENV{'GIT_DIR'}; # if not run via ssh, our parent git process + delete $ENV{'GIT_PREFIX'}; # sets these and they mess things up + + if ($ENV{'DGIT_DRS_DEBUG'}) { + $debug='='; + open DEBUG, ">&STDERR" or die $!; + } + + if ($ARGV[0] eq '--pre-receive-hook') { + if ($debug) { $debug.="="; } + shift @ARGV; + @ARGV == 1 or die; + $package = shift @ARGV; + ${ $main::{$_} } = $ENV{"DGIT_DRS_\U$_"} foreach @hookenvs; + defined($workrepo = $ENV{'DGIT_DRS_WORK'}) or die; + defined($destrepo = $ENV{'DGIT_DRS_DEST'}) or die; + open STDOUT, ">&STDERR" or die $!; + eval { + stunthook(); + }; + if ($@) { + recorderror "$@" or die; + die $@; + } + exit 0; + } + + $distro = $ENV{'DGIT_DRS_DISTRO'} = argval(); + my $distrodir = argval(); + $keyrings = $ENV{'DGIT_DRS_KEYRINGS'} = argval(); + + foreach my $dk (keys %indistrodir) { + ${ $indistrodir{$dk} } = "$distrodir/$dk"; + } + + while (@ARGV && $ARGV[0] =~ m/^--([-0-9a-z]+)=/ && $indistrodir{$1}) { + ${ $indistrodir{$1} } = $'; #'; + shift @ARGV; + } + + $ENV{"DGIT_DRS_\U$_"} = ${ $main::{$_} } foreach @hookenvs; + + die unless @ARGV==1; + + my $mode = shift @ARGV; + die unless $mode =~ m/^--(\w+)$/; + my $fn = ${*::}{"mode_$1"}; + die unless $fn; + $fn->(); +} + sub unlockall () { while (my $fh = pop @lockfhs) { close $fh; } }