chiark / gitweb /
dgit-repos-server: Make $policy a global
[dgit.git] / infra / dgit-repos-server
index a2916d6221ceaff7ffa13d07c4c4794ff3fee339..ef9f968ea268ac379b2a0cd617389fb3d8fe4a67 100755 (executable)
@@ -2,7 +2,8 @@
 # dgit-repos-server
 #
 # usages:
-#  .../dgit-repos-server DISTRO SUITES KEYRING-AUTH-SPEC DGIT-REPOS-DIR --ssh
+#  .../dgit-repos-server DISTRO SUITES KEYRING-AUTH-SPEC \
+#      DGIT-REPOS-DIR POLICY-HOOK-SCRIPT --ssh
 # internal usage:
 #  .../dgit-repos-server --pre-receive-hook PACKAGE
 #
@@ -86,20 +87,23 @@ use POSIX;
 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;
 our $package;
 our $suitesfile;
+our $policyhook;
 our $realdestrepo;
 our $destrepo;
 our $workrepo;
 our $keyrings;
 our @lockfhs;
 our $debug='';
+our @deliberatelies;
+our $policy;
 
 #----- utilities -----
 
@@ -184,16 +188,58 @@ sub runcmd {
     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 () {
@@ -331,6 +377,20 @@ sub parsetag () {
     for (;;) {
        print PT or die $!;
        $!=0; $_=<T>; defined or die "missing signature? $!";
+       if (m/^\[dgit ([^"].*)\]$/) { # [dgit "something"] is for future
+           $_ = $1." ";
+           for (;;) {
+               if (s/^distro\=(\S+) //) {
+                   die "$1 != $distro" unless $1 eq $distro;
+               } elsif (s/^(--deliberately-$package_re) //) {
+                   push @deliberatelies, $1;
+               } elsif (s/^[-+.=0-9a-z]\S* //) {
+               } else {
+                   die "unknown dgit info in tag";
+               }
+           }
+           next;
+       }
        last if m/^-----BEGIN PGP/;
     }
     for (;;) {
@@ -463,7 +523,7 @@ sub tagh1 ($) {
 
 sub checks () {
     debug "checks";
-    checksuite();
+
     tagh1('type') eq 'commit' or reject "tag refers to wrong kind of object";
     tagh1('object') eq $commit or reject "tag refers to wrong commit";
     tagh1('tag') eq $tagname or reject "tag name in tag is wrong";
@@ -474,25 +534,21 @@ sub checks () {
     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 $!";
-}      
-
 sub stunthook () {
     debug "stunthook";
     chdir $workrepo or die "chdir $workrepo: $!";
@@ -513,8 +569,7 @@ sub fixmissing__git_upload_pack () {
     return if stat $destrepo;
     die $! unless $!==ENOENT;
     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;
@@ -554,6 +609,7 @@ sub parseargsdispatch () {
        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();
@@ -569,6 +625,7 @@ sub parseargsdispatch () {
     $ENV{'DGIT_DRS_SUITES'} = argval();
     $ENV{'DGIT_DRS_KEYRINGS'} = argval();
     $dgitrepos = argval();
+    $ENV{'DGIT_DRS_POLICYHOOK'} = $policyhook = argval();
 
     die unless @ARGV==1 && $ARGV[0] eq '--ssh';
 
@@ -593,6 +650,12 @@ sub parseargsdispatch () {
 
     reject "unknown method" unless $mainfunc;
 
+    my ($policy, $pollock) = policyhook(FRESHREPO,'check-package',$package);
+    if ($policy & FRESHREPO) {
+       movetogarbage;
+    }
+    close $pollock or die $!;
+
     if (stat $realdestrepo) {
        $destrepo = $realdestrepo;
     } else {