From dd88f3100854f2440b673cafc2b6ae5ad52f9ebf Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 5 Jul 2019 14:41:29 +0100 Subject: dgit-repos-server: New prototype tag2upload mode for git-debpush Signed-off-by: Ian Jackson --- infra/dgit-repos-server | 207 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) (limited to 'infra') diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index eea5d94..68429eb 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -21,6 +21,8 @@ # usages: # dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --ssh # dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --cron +# dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] \ +# --tag2upload URL TAGNAME # settings # --repos=GIT-REPOS-DIR default DISTRO-DIR/repos/ # --suites=SUITES-FILE default DISTRO-DIR/suites @@ -50,6 +52,8 @@ # (With --cron AUTH-SPEC is not used and may be the empty string.) use strict; +use Carp; +use IO::Handle; use Debian::Dgit::Infra; # must precede Debian::Dgit; - can change @INC! use Debian::Dgit qw(:DEFAULT :policyflags); @@ -1068,6 +1072,209 @@ our @hookenvs = qw(distro suitesfile suitesformasterfile policyhook # workrepo and destrepo handled ad-hoc +sub mode_tag2upload () { + # PROTOTYPE + # CALLER MUST PREVENT MULTIPLE CONCURRENT RUNS IN SAME CWD + # If we fail (exit nonzero), caller should capture our stderr, + # and retry some bounded number of times in some appropriate way + @ARGV==2 or die; + + my $url; + ($url,$tagval) = @ARGV; + + $ENV{DGIT_DRS_EMAIL_NOREPLY} // die; + + my $start = time // die; + my @t = gmtime $start; + + die if $url =~ m/[^[:graph:]]/; + die if $tagval =~ m/[^[:graph:]]/; + + open OL, ">>overall.log" or die $!; + autoflush OL 1; + my $quit = sub { + printf OL "%04d-%02d-%02d %02d:%02d:%02d (%04ds): %s %s: %s\n", + $t[5] + 1900, @t[4,3,2,1,0], (time-$start), $url, $tagval, $_[0]; + exit 0; + }; + + $ENV{DGIT_DRS_ANY_URL} or $url =~ m{^https://}s + or $quit->("url scheme not as expected"); + + $tagval =~ m{^$distro/($versiontag_re)$}s + or $quit->("tag name not for us"); + + $version = $1; + $version =~ y/_\%\#/:~/d; + + my $work = 'work'; + + my $tagref = "refs/tags/$tagval"; + + rmtree $work; + mkdir $work or die $!; + changedir $work; + runcmd qw(git init -q); + runcmd qw(git remote add origin), $url; + runcmd qw(git fetch --depth=1 origin), "$tagref:$tagref"; + changedir ".git"; + mkdir 'dgit-tmp' or die $!; + + my $tagger; + open T, "-|", qw(git cat-file tag), $tagval or die $!; + { + local $/ = undef; + $!=0; $_=; defined or die $!; + + # quick and dirty check, will check properly later + m/^\[dgit[^"]* please-upload(?:\]| )/m or + $quit->("tag missing please-upload request $_"); + + m/^tagger (.*) \d+ [-+]\d+$/m or + $quit->("failed to fish tagger out of tag"); + $tagger = $1; + }; + + readtag(); + m/^($package_re) release (\S+) for ($suite_re)$/ or + $quit->("tag headline not for us"); + $package = $1; + my $tagmversion = $2; + $suite = $3; + + + # This is for us. From now on, we will capture errors to + # be emailed to the tagger. + # TODO: failures to git fetch from salsa will burn a version + + open H, ">>dgit-tmp/tagupl.email" or die $!; + print H <>dgit-tmp/tagupl.log" or die $!; + + my $child = fork() // die $!; + if ($child) { + # we are the parent + # if child exits 0, it has called $quit->() + $!=0; waitpid $child, 0 == $child or die $!; + printdebug "child $child ?=$?\n"; + exit 0 unless $?; + print L "execution child: ", waitstatusmsg(), "\n" or die $!; + close L or die $!; + print H <>tagupl.email + $ENV{DGIT_DRS_SENDMAIL} -oee -odb -oi -t \\ + -f$ENV{DGIT_DRS_EMAIL_NOREPLY} \\ + &L" or die $!; + open STDOUT, ">&STDERR" or die $!; + open DEBUG, ">&STDERR" if $debuglevel; + + die "$tagmversion != $version " unless $tagmversion eq $version; + + my %need = map { $_ => 1 } qw(please-upload split); + my ($upstreamc, $upstreamt); + my $quilt; + my $distro_ok; + + parsetag_general sub { + if (m/^(\S+) / && exists $need{$1}) { + $_ = $'; + delete $need{$1}; + } elsif (s/^upstream=(\w+) //) { + $upstreamc = $1; + } elsif (s/^upstream-tag=(\S+) //) { + $upstreamt = $1; + } elsif (s/^quilt=([-+0-9a-z]+) //) { + $quilt = $1; + } else { + return 0; + } + return 1; + }, sub { + my ($gotdistro) = @_; + $distro_ok ||= $gotdistro eq $distro; + }; + + $quit->("other distro") unless $distro_ok; + + reject "missing \"$_\"" foreach keys %need; + + reject "upstream tag and not commitish, or v-v" + unless defined $upstreamt == defined $upstreamc; + + verifytag(); + + my @dgit; + push @dgit, $ENV{DGIT_DRS_DGIT} // 'dgit'; + push @dgit, '-wn'; + push @dgit, "-p$package"; + + changedir ".."; + runcmd (@dgit, qw(setup-gitattributes)); + + my @fetch = qw(git fetch origin --unshallow); + if (defined $upstreamt) { + runcmd qw(git check-ref-format), "refs/tags/$upstreamt"; + runcmd qw(git check-ref-format), "refs/tags/$upstreamt"; + my $utagref = "refs/tags/$upstreamt"; + push @fetch, "$utagref:$utagref"; + } + runcmd @fetch; + + $upstreamc eq git_rev_parse "refs/tags/$upstreamt" or die; + + runcmd qw(git checkout -q), "refs/tags/$tagval"; + + @fetch = (@dgit, qw(fetch), $suite); + debugcmd "+",@_; + $!=0; $?=-1; + if (system @fetch) { + failedcmd @fetch unless $? == 4*256; + } + # this is just to get the orig, so we don't really care about the ref + runcmd qw(git deborig), "$upstreamc"; + + my @dgitcmd; + push @dgitcmd, @dgit; + push @dgitcmd, qw(--force-uploading-source-only); + if (defined $quilt) { + push @dgitcmd, "--quilt=$quilt"; + if ($quilt =~ m/baredebian/) { + die "needed upstream commmitish with --quilt=baredebian"; + push @dgitcmd, "--upstream-commitish=$upstreamc"; + } + } + push @dgitcmd, qw(push-source --new --overwrite), $suite; + # xxx what about the key to use? + + runcmd @dgitcmd; + + $quit->('done'); +} + sub mode_ssh () { die if @ARGV; -- cgit v1.2.3