X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=infra%2Fdgit-repos-policy-debian;h=e02c100ccc5d093c36d63245eeac7a25fe2f599e;hp=83ce793929469f837c277ad68d6fa30a51622e7f;hb=673989e62a91bf9fbd637f766af022b6da77f830;hpb=9ff6957e842708e9641ad00510f336b347bff302 diff --git a/infra/dgit-repos-policy-debian b/infra/dgit-repos-policy-debian index 83ce7939..e02c100c 100755 --- a/infra/dgit-repos-policy-debian +++ b/infra/dgit-repos-policy-debian @@ -9,17 +9,24 @@ use JSON; use File::Temp qw(tempfile); use DBI; use IPC::Open2; +use Data::Dumper; use Debian::Dgit qw(:DEFAULT :policyflags); use Debian::Dgit::Policy::Debian; +initdebug('%'); +enabledebuglevel $ENV{'DGIT_DRS_DEBUG'}; + +END { $? = 127; } # deliberate exit uses _exit + our $distro = shift @ARGV // die "need DISTRO"; our $repos = shift @ARGV // die "need DGIT-REPOS-DIR"; our $dgitlive = shift @ARGV // die "need DGIT-LIVE-DIR"; +our $distrodir = shift @ARGV // die "need DISTRO-DIR"; our $action = shift @ARGV // die "need ACTION"; our $publicmode = 02775; -our $new_upload_propagation_slop = 3600*4 + 100; +our $new_upload_propagation_slop = 3600*4 + 100;# fixme config; our $poldbh; our $pkg; @@ -79,38 +86,40 @@ our %deliberately; sub apiquery ($) { my ($subpath) = @_; local $/=undef; - my $cmd = "$dgitlive/dgit -d $distro ". - "\$DGIT_TEST_OPTS \$DGIT_TEST_DEBUG archive-api-query $subpath"; + my $cmd = "$dgitlive/dgit -d$distro \$DGIT_TEST_OPTS"; + $cmd .= " -".("D" x $debuglevel) if $debuglevel; + $cmd .= " archive-api-query $subpath"; + printdebug "apiquery $cmd\n"; $!=0; $?=0; my $json = `$cmd`; - defined $json or die "$subpath $! $?"; - return decode_json $json; + defined $json && !$? or die "$subpath $! $?"; + my $r = decode_json $json; + my $d = new Data::Dumper([$r], [qw(r)]); + printdebug "apiquery $subpath | ", $d->Dump() if $debuglevel>=2; + return $r; } sub specific_suite_has_vsn_in_our_history ($) { my ($suite) = @_; - my $in_suite = apiquery "/dsc_in_suite/$suite/$pkg"; + my $in_suite = apiquery "dsc_in_suite/$suite/$pkg"; foreach my $entry (@$in_suite) { my $vsn = $entry->{version}; die "$pkg ?" unless defined $vsn; - my $tag = debiantag $vsn; - $?=0; my $r = system qw(git show-ref --verify --quiet), $tag; + my $tagref = "refs/tags/".debiantag $vsn; + printdebug " checking history suite=$suite vsn=$vsn tagref=$tagref\n"; + $?=0; my $r = system qw(git show-ref --verify --quiet), $tagref; return 1 if !$r; next if $r==256; - die "$pkg tag $tag $? $!"; + die "$pkg tagref $tagref $? $!"; } return 0; } sub new_has_vsn_in_our_history () { - stat $pkgdir or die "$pkgdir $!"; - my $mtime = ((stat _)[9]); - my $age = time - $mtime; - return 1 if $age < $new_upload_propagation_slop; return specific_suite_has_vsn_in_our_history('new'); } sub good_suite_has_vsn_in_our_history () { - my $suites = apiquery "/suites"; + my $suites = apiquery "suites"; foreach my $suitei (@$suites) { my $suite = $suitei->{name}; die unless defined $suite; @@ -120,36 +129,49 @@ sub good_suite_has_vsn_in_our_history () { return 0; } -sub getpackage () { - die unless @ARGV >= 1; - $pkg = shift @ARGV; - die unless $pkg =~ m/^$package_re$/; - - $pkgdir = "$repos/$pkg"; +sub statpackage () { + $pkgdir = "$repos/$pkg.git"; if (!stat_exists $pkgdir) { + printdebug "statpackage $pkg => ENOENT\n"; $pkg_exists = 0; } else { $pkg_exists = 1; $pkg_secret = !!(~(stat _)[2] & 05); + printdebug "statpackage $pkg => exists, secret=$pkg_secret.\n"; } } +sub getpackage () { + die unless @ARGV >= 1; + $pkg = shift @ARGV; + die unless $pkg =~ m/^$package_re$/; + + statpackage(); +} + sub add_taint ($$) { - my ($refobj, $reason); + my ($refobj, $reason) = @_; + + printdebug "TAINTING $refobj\n", + (map { "\%| $_" } split "\n", $reason), + "\n"; my $tf = new File::Temp or die $!; print $tf "$refobj^0\n" or die $!; + flush $tf or die $!; + seek $tf,0,0 or die $!; my $gcfpid = open GCF, "-|"; defined $gcfpid or die $!; if (!$gcfpid) { open STDIN, "<&", $tf or die $!; - exec 'git', 'cat-file'; + exec 'git', 'cat-file', '--batch'; die $!; } close $tf or die $!; $_ = ; + defined $_ or die; m/^(\w+) (\w+) (\d+)\n/ or die "$_ ?"; my $gitobjid = $1; my $gitobjtype = $2; @@ -163,7 +185,7 @@ sub add_taint ($$) { close GCF; $poldbh->do("INSERT INTO taints". - " (package, gitobjid, gitobjtype, gitobjdata, time, comment)", + " (package, gitobjid, gitobjtype, gitobjdata, time, comment)". " VALUES (?,?,?,?,?,?)", {}, $pkg, $gitobjid, $gitobjtype, $gitobjdata, time, $reason); @@ -171,9 +193,9 @@ sub add_taint ($$) { die unless defined $taint_id; $poldbh->do("INSERT INTO taintoverrides". - " (taint_id, deliberately)", - " VALUES (?, 'include-questionable-history')", {}, - $taint_id); + " (taint_id, deliberately)". + " VALUES (?, '--deliberately-include-questionable-history')", + {}, $taint_id); } sub add_taint_by_tag ($$) { @@ -184,19 +206,31 @@ sub add_taint_by_tag ($$) { " removed from NEW (ie, rejected) (or never arrived)"); } -sub action__check_package () { +sub action_check_package () { getpackage(); return 0 unless $pkg_exists; return 0 unless $pkg_secret; + printdebug "check_package\n"; + chdir $pkgdir or die "$pkgdir $!"; - return if new_has_vsn_in_our_history(); + + stat '.' or die "$pkgdir $!"; + my $mtime = ((stat _)[9]); + my $age = time - $mtime; + printdebug "check_package age=$age\n"; + + return 0 if $age < $new_upload_propagation_slop; + + return 0 if new_has_vsn_in_our_history(); if (good_suite_has_vsn_in_our_history) { chmod $publicmode, "." or die $!; return 0; } + printdebug "check_package secret, deleted, tainting\n"; + git_for_each_ref('refs/tags', sub { my ($objid,$objtype,$fullrefname,$tagname) = @_; add_taint_by_tag($tagname,$objid); @@ -216,10 +250,12 @@ sub getpushinfo () { } } -sub deliberately ($) { return $deliberately{$_[0]}; } +sub deliberately ($) { return $deliberately{"--deliberately-$_[0]"}; } sub action_push () { getpackage(); + getpushinfo(); + return 0 unless $pkg_exists; return 0 unless $pkg_secret; @@ -228,9 +264,9 @@ sub action_push () { if (deliberately('not-fast-forward')) { add_taint(server_ref($suite), - "suite $suite when --deliberately-not-fast-forward". + "rewound suite $suite; --deliberately-not-fast-forward". " specified in signed tag $tagname for upload of". - " version $version into suite $suite"); + " version $version"); return NOFFCHECK|FRESHREPO; } if (deliberately('include-questionable-history')) { @@ -243,17 +279,28 @@ sub action_push () { } sub action_push_confirm () { + getpackage(); + getpushinfo(); + die unless @ARGV >= 1; + my $freshrepo = shift @ARGV; + my $initq = $poldbh->prepare(<execute($pkg); + my @objscatcmd = qw(git); + push @objscatcmd, qw(--git-dir), $freshrepo if length $freshrepo; + push @objscatcmd, qw(cat-file --batch); + debugcmd '|',@objscatcmd if $debuglevel>=2; + my @taintids; my $chkinput = tempfile(); while (my $taint = $initq->fetchrow_hashref()) { push @taintids, $taint->{taint_id}; print $chkinput $taint->{gitobjid}, "\n" or die $!; + printdebug '|> ', $taint->{gitobjid}, "\n" if $debuglevel>=2; } flush $chkinput or die $!; seek $chkinput,0,0 or die $!; @@ -261,16 +308,17 @@ END my $checkpid = open CHKOUT, "-|" // die $!; if (!$checkpid) { open STDIN, "<&", $chkinput or die $!; - exec qw(git cat-file --batch) or die $!; + exec @objscatcmd or die $!; } my ($taintinfoq,$overridesanyq,$untaintq,$overridesq); my $overridesstmt = <; die "$? $!" unless defined $_; + printdebug "|< ", $_ if $debuglevel>=2; next if m/^\w+ missing$/; die unless m/^(\w+) (\w+) (\d+)\s/; @@ -316,6 +365,8 @@ Taint recorded$timeshow for $pkgshow Reason: $ti->{comment} END + printdebug "SQL overrides: @overridesv $taintid /\n$overridesstmt\n"; + $overridesq ||= $poldbh->prepare($overridesstmt); $overridesq->execute(@overridesv, $taintid); my ($ovwhy) = $overridesq->fetchrow_array(); @@ -351,17 +402,48 @@ END return 1; } + if (length $freshrepo) { + if (!good_suite_has_vsn_in_our_history()) { + stat $freshrepo or die "$freshrepo $!"; + my $oldmode = ((stat _)[2]); + my $oldwrites = $oldmode & 0222; + # remove r and x bits which have corresponding w bits clear + my $newmode = $oldmode & + (~0555 | ($oldwrites << 1) | ($oldwrites >> 1)); + printdebug sprintf "chmod %#o (was %#o) %s\n", + $newmode, $oldmode, $freshrepo; + chmod $newmode, $freshrepo or die $!; + utime undef, undef, $freshrepo or die $!; + } + } + + return 0; +} + +sub action_check_list () { + opendir L, "$repos" or die "$repos $!"; + while (defined (my $dent = readdir L)) { + next unless $dent =~ m/^($package_re)\.git$/; + $pkg = $1; + statpackage(); + next unless $pkg_exists; + next unless $pkg_secret; + print "$pkg\n" or die $!; + } + closedir L or die $!; + close STDOUT or die $!; return 0; } $action =~ y/-/_/; my $fn = ${*::}{"action_$action"}; if (!$fn) { + printdebug "dgit-repos-policy-debian: unknown action $action\n"; exit 0; } my $sleepy=0; -our $rcode = 127; +my $rcode; for (;;) { poldb_setup(poldb_path($repos)); @@ -380,5 +462,6 @@ for (;;) { $poldbh->rollback; } -print STDERR $stderr; -exit $rcode; +print STDERR $stderr or die $!; +flush STDERR or die $!; +_exit $rcode;