summaryrefslogtreecommitdiff
path: root/infra
diff options
context:
space:
mode:
Diffstat (limited to 'infra')
-rwxr-xr-xinfra/dgit-repos-server207
1 files changed, 207 insertions, 0 deletions
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 [<settings>] --ssh
# dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [<settings>] --cron
+# dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [<settings>] \
+# --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; $_=<T>; 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 <<END or die $!;
+Subject: push-to-upload failed, $package $version ($distro)
+X-Debian-Push-Distro: $distro
+X-Debian-Push-Package: $package
+END
+ printf H "To: %s", $tagger or die $!; # no newline
+ flush H or die $!;
+
+ open L, ">>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 <<END or die $!;
+
+
+Processing of tag $tagval
+From url $url
+Was not successful:
+
+END
+ $ENV{DGIT_DRS_SENDMAIL} //= '/usr/lib/sendmail';
+
+ close H or die $!;
+ runcmd qw(sh -ec), <<"END";
+ cd dgit-tmp
+ cat tagupl.log >>tagupl.email
+ $ENV{DGIT_DRS_SENDMAIL} -oee -odb -oi -t \\
+ -f$ENV{DGIT_DRS_EMAIL_NOREPLY} \\
+ <tagupl.email
+END
+ exit 0;
+ }
+
+ open STDERR, ">&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;