X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=dgit;h=9e2e66e4841b4adb690225fab1def69b6229df6d;hb=927b96798f1314b4146c3d57d5540a96cf9d6319;hp=3d3628093e0d42e4ae8d9ac4ed22b05c429611d6;hpb=5f9258f673404e784b450631b39ba433a1fda945;p=dgit.git
diff --git a/dgit b/dgit
index 3d362809..9e2e66e4 100755
--- a/dgit
+++ b/dgit
@@ -2,7 +2,7 @@
# dgit
# Integration between git and Debian-style archives
#
-# Copyright (C)2013 Ian Jackson
+# Copyright (C)2013-2015 Ian Jackson
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -32,7 +32,6 @@ use POSIX;
use IPC::Open2;
use Digest::SHA;
use Digest::MD5;
-use Config;
use Debian::Dgit;
@@ -53,7 +52,7 @@ our $new_package = 0;
our $ignoredirty = 0;
our $rmonerror = 1;
our @deliberatelies;
-our %supersedes;
+our %previously;
our $existing_package = 'dpkg';
our $cleanmode = 'dpkg-source';
our $changes_since_version;
@@ -112,6 +111,8 @@ sub lref () { return "refs/heads/".lbranch(); }
sub lrref () { return "refs/remotes/$remotename/".server_branch($csuite); }
sub rrref () { return server_ref($csuite); }
+sub lrfetchrefs () { return "refs/dgit-fetch/$csuite"; }
+
sub stripepoch ($) {
my ($vsn) = @_;
$vsn =~ s/^\d+\://;
@@ -140,30 +141,6 @@ END {
}
};
-our @signames = split / /, $Config{sig_name};
-
-sub waitstatusmsg () {
- if (!$?) {
- return "terminated, reporting successful completion";
- } elsif (!($? & 255)) {
- return "failed with error exit status ".WEXITSTATUS($?);
- } elsif (WIFSIGNALED($?)) {
- my $signum=WTERMSIG($?);
- return "died due to fatal signal ".
- ($signames[$signum] // "number $signum").
- ($? & 128 ? " (core dumped)" : ""); # POSIX(3pm) has no WCOREDUMP
- } else {
- return "failed with unknown wait status ".$?;
- }
-}
-
-sub fail {
- my $s = "@_\n";
- my $prefix = $us.($we_are_responder ? " (build host)" : "").": ";
- $s =~ s/^/$prefix/gm;
- die $s;
-}
-
sub badcfg { print STDERR "$us: invalid configuration: @_\n"; exit 12; }
sub no_such_package () {
@@ -187,6 +164,12 @@ sub deliberately ($) {
return !!grep { $_ eq "--deliberately-$enquiry" } @deliberatelies;
}
+sub deliberately_not_fast_forward () {
+ foreach (qw(not-fast-forward fresh-repo)) {
+ return 1 if deliberately($_) || deliberately("TEST-dgit-only-$_");
+ }
+}
+
#---------- remote protocol support, common ----------
# remote push initiator/responder protocol:
@@ -375,17 +358,6 @@ sub url_get {
our ($dscdata,$dscurl,$dsc,$dsc_checked,$skew_warning_vsn);
-sub failedcmd {
- { local ($!); printcmd \*STDERR, "$us: failed command:", @_ or die $!; };
- if ($!) {
- fail "failed to fork/exec: $!";
- } elsif ($?) {
- fail "subprocess ".waitstatusmsg();
- } else {
- fail "subprocess produced invalid output";
- }
-}
-
sub runcmd {
debugcmd "+",@_;
$!=0; $?=0;
@@ -403,27 +375,6 @@ sub printdone {
}
}
-sub cmdoutput_errok {
- die Dumper(\@_)." ?" if grep { !defined } @_;
- debugcmd "|",@_;
- open P, "-|", @_ or die $!;
- my $d;
- $!=0; $?=0;
- { local $/ = undef; $d =
; }
- die $! if P->error;
- if (!close P) { printdebug "=>!$?\n"; return undef; }
- chomp $d;
- $d =~ m/^.*/;
- printdebug "=> \`$&'",(length $' ? '...' : ''),"\n" if $debuglevel>0; #';
- return $d;
-}
-
-sub cmdoutput {
- my $d = cmdoutput_errok @_;
- defined $d or failedcmd @_;
- return $d;
-}
-
sub dryrun_report {
printcmd(\*STDERR,$debugprefix."#",@_);
}
@@ -493,20 +444,27 @@ our %defcfg = ('dgit.default.distro' => 'debian',
'dgit.default.archive-query' => 'madison:',
'dgit.default.sshpsql-dbname' => 'service=projectb',
'dgit-distro.debian.archive-query' => 'ftpmasterapi:',
- 'dgit-distro.debian.git-host' => 'dgit-git.debian.net',
- 'dgit-distro.debian.git-user-force' => 'dgit',
- 'dgit-distro.debian.git-proto' => 'git+ssh://',
- 'dgit-distro.debian.git-path' => '/dgit/debian/repos',
- 'dgit-distro.debian.git-check' => 'ssh-cmd',
+ 'dgit-distro.debian.git-check' => 'url',
+ 'dgit-distro.debian.git-check-suffix' => '/info/refs',
+ 'dgit-distro.debian/push.git-url' => '',
+ 'dgit-distro.debian/push.git-host' => 'push.dgit.debian.org',
+ 'dgit-distro.debian/push.git-user-force' => 'dgit',
+ 'dgit-distro.debian/push.git-proto' => 'git+ssh://',
+ 'dgit-distro.debian/push.git-path' => '/dgit/debian/repos',
+ 'dgit-distro.debian/push.git-create' => 'true',
+ 'dgit-distro.debian/push.git-check' => 'ssh-cmd',
'dgit-distro.debian.archive-query-url', 'https://api.ftp-master.debian.org/',
- 'dgit-distro.debian.archive-query-tls-key',
- '/etc/ssl/certs/%HOST%.pem:/etc/dgit/%HOST%.pem',
- 'dgit-distro.debian.diverts.alioth' => '/alioth',
- 'dgit-distro.debian/alioth.git-host' => 'git.debian.org',
- 'dgit-distro.debian/alioth.git-user-force' => '',
- 'dgit-distro.debian/alioth.git-proto' => 'git+ssh://',
- 'dgit-distro.debian/alioth.git-path' => '/git/dgit-repos/repos',
- 'dgit-distro.debian/alioth.git-create' => 'ssh-cmd',
+# 'dgit-distro.debian.archive-query-tls-key',
+# '/etc/ssl/certs/%HOST%.pem:/etc/dgit/%HOST%.pem',
+# ^ this does not work because curl is broken nowadays
+# Fixing #790093 properly will involve providing providing the key
+# in some pacagke and maybe updating these paths.
+#
+# 'dgit-distro.debian.archive-query-tls-curl-args',
+# '--ca-path=/etc/ssl/ca-debian',
+# ^ this is a workaround but works (only) on DSA-administered machines
+ 'dgit-distro.debian.git-url' => 'https://git.dgit.debian.org',
+ 'dgit-distro.debian.git-url-suffix' => '',
'dgit-distro.debian.upload-host' => 'ftp-master', # for dput
'dgit-distro.debian.mirror' => 'http://ftp.debian.org/debian/',
'dgit-distro.debian.backports-quirk' => '(squeeze)-backports*',
@@ -526,20 +484,35 @@ our %defcfg = ('dgit.default.distro' => 'debian',
'dgit-distro.test-dummy.upload-host' => 'test-dummy',
);
+sub git_get_config ($) {
+ my ($c) = @_;
+
+ our %git_get_config_memo;
+ if (exists $git_get_config_memo{$c}) {
+ return $git_get_config_memo{$c};
+ }
+
+ my $v;
+ my @cmd = (@git, qw(config --), $c);
+ {
+ local ($debuglevel) = $debuglevel-2;
+ $v = cmdoutput_errok @cmd;
+ };
+ if ($?==0) {
+ } elsif ($?==256) {
+ $v = undef;
+ } else {
+ failedcmd @cmd;
+ }
+ $git_get_config_memo{$c} = $v;
+ return $v;
+}
+
sub cfg {
foreach my $c (@_) {
return undef if $c =~ /RETURN-UNDEF/;
- my @cmd = (@git, qw(config --), $c);
- my $v;
- {
- local ($debuglevel) = $debuglevel-2;
- $v = cmdoutput_errok @cmd;
- };
- if ($?==0) {
- return $v;
- } elsif ($?!=256) {
- failedcmd @cmd;
- }
+ my $v = git_get_config($c);
+ return $v if defined $v;
my $dv = $defcfg{$c};
return $dv if defined $dv;
}
@@ -574,6 +547,31 @@ sub access_quirk () {
return ('none',undef);
}
+our $access_forpush;
+
+sub access_forpush_config () {
+ my $d = access_basedistro();
+ my $v = cfg("dgit-distro.$d.readonly", 'RETURN-UNDEF');
+ $v //= 'a';
+ return
+ $v =~ m/^[ty1]/ ? 0 : # force readonly, forpush = 0
+ $v =~ m/^[fn0]/ ? 1 : # force nonreadonly, forpush = 1
+ $v =~ m/^[a]/ ? '' : # auto, forpush = ''
+ badcfg "readonly needs t (true, y, 1) or f (false, n, 0) or a (auto)";
+}
+
+sub access_forpush () {
+ $access_forpush //= access_forpush_config();
+ return $access_forpush;
+}
+
+sub pushing () {
+ die "$access_forpush ?" if ($access_forpush // 1) ne 1;
+ badcfg "pushing but distro is configured readonly"
+ if access_forpush_config() eq '0';
+ $access_forpush = 1;
+}
+
sub access_distros () {
# Returns list of distros to try, in order
#
@@ -587,7 +585,12 @@ sub access_distros () {
my (undef,$quirkdistro) = access_quirk();
unshift @l, $quirkdistro;
unshift @l, $instead_distro;
- return grep { defined } @l;
+ @l = grep { defined } @l;
+
+ if (access_forpush()) {
+ @l = map { ("$_/push", $_) } @l;
+ }
+ @l;
}
sub access_cfg (@) {
@@ -660,15 +663,19 @@ sub access_gituserhost () {
sub access_giturl (;$) {
my ($optional) = @_;
my $url = access_cfg('git-url','RETURN-UNDEF');
- if (!defined $url) {
+ my $suffix;
+ if (!length $url) {
my $proto = access_cfg('git-proto', 'RETURN-UNDEF');
return undef unless defined $proto;
$url =
$proto.
access_gituserhost().
access_cfg('git-path');
+ } else {
+ $suffix = access_cfg('git-url-suffix','RETURN-UNDEF');
}
- return "$url/$package.git";
+ $suffix //= '.git';
+ return "$url/$package$suffix";
}
sub parsecontrolfh ($$;$) {
@@ -724,23 +731,6 @@ sub parsechangelog {
return $c;
}
-sub git_get_ref ($) {
- my ($refname) = @_;
- my $got = cmdoutput_errok @git, qw(show-ref --), $refname;
- if (!defined $got) {
- $?==256 or fail "git show-ref failed (status $?)";
- printdebug "ref $refname= [show-ref exited 1]\n";
- return '';
- }
- if ($got =~ m/^(\w+) \Q$refname\E$/m) {
- printdebug "ref $refname=$1\n";
- return $1;
- } else {
- printdebug "ref $refname= [no match]\n";
- return '';
- }
-}
-
sub must_getcwd () {
my $d = getcwd();
defined $d or fail "getcwd failed: $!";
@@ -772,16 +762,25 @@ sub archive_api_query_cmd ($) {
my $url = access_cfg('archive-query-url');
if ($url =~ m#^https://([-.0-9a-z]+)/#) {
my $host = $1;
- my $keys = access_cfg('archive-query-tls-key','RETURN-UNDEF');
+ my $keys = access_cfg('archive-query-tls-key','RETURN-UNDEF') //'';
foreach my $key (split /\:/, $keys) {
$key =~ s/\%HOST\%/$host/g;
if (!stat $key) {
fail "for $url: stat $key: $!" unless $!==ENOENT;
next;
}
- push @cmd, "--ca-certificate=$key", "--ca-directory=/dev/enoent";
+ fail "config requested specific TLS key but do not know".
+ " how to get curl to use exactly that EE key ($key)";
+# push @cmd, "--cacert", $key, "--capath", "/dev/enoent";
+# # Sadly the above line does not work because of changes
+# # to gnutls. The real fix for #790093 may involve
+# # new curl options.
last;
}
+ # Fixing #790093 properly will involve providing a value
+ # for this on clients.
+ my $kargs = access_cfg('archive-query-tls-curl-ca-args','RETURN-UNDEF');
+ push @cmd, split / /, $kargs if defined $kargs;
}
push @cmd, $url.$subpath;
return @cmd;
@@ -1068,13 +1067,32 @@ sub check_for_git () {
if ($r =~ m/^divert (\w+)$/) {
my $divert=$1;
my ($usedistro,) = access_distros();
+ # NB that if we are pushing, $usedistro will be $distro/push
$instead_distro= cfg("dgit-distro.$usedistro.diverts.$divert");
$instead_distro =~ s{^/}{ access_basedistro()."/" }e;
- printdebug "diverting $divert so using distro $instead_distro\n";
+ progress "diverting to $divert (using config for $instead_distro)";
return check_for_git();
}
failedcmd @cmd unless $r =~ m/^[01]$/;
return $r+0;
+ } elsif ($how eq 'url') {
+ my $prefix = access_cfg('git-check-url','git-url');
+ my $suffix = access_cfg('git-check-suffix','git-suffix',
+ 'RETURN-UNDEF') // '.git';
+ my $url = "$prefix/$package$suffix";
+ my @cmd = (qw(curl -sS -I), $url);
+ my $result = cmdoutput @cmd;
+ $result =~ m/^\S+ (404|200) /s or
+ fail "unexpected results from git check query - ".
+ Dumper($prefix, $result);
+ my $code = $1;
+ if ($code eq '404') {
+ return 0;
+ } elsif ($code eq '200') {
+ return 1;
+ } else {
+ die;
+ }
} elsif ($how eq 'true') {
return 1;
} elsif ($how eq 'false') {
@@ -1195,6 +1213,69 @@ sub clogp_authline ($) {
return $authline;
}
+sub vendor_patches_distro ($$) {
+ my ($checkdistro, $what) = @_;
+ return unless defined $checkdistro;
+
+ my $series = "debian/patches/\L$checkdistro\E.series";
+ printdebug "checking for vendor-specific $series ($what)\n";
+
+ if (!open SERIES, "<", $series) {
+ die "$series $!" unless $!==ENOENT;
+ return;
+ }
+ while () {
+ next unless m/\S/;
+ next if m/^\s+\#/;
+
+ print STDERR <error;
+ close SERIES;
+}
+
+sub check_for_vendor_patches () {
+ # This dpkg-source feature doesn't seem to be documented anywhere!
+ # But it can be found in the changelog (reformatted):
+
+ # commit 4fa01b70df1dc4458daee306cfa1f987b69da58c
+ # Author: Raphael Hertzog
+ # Date: Sun Oct 3 09:36:48 2010 +0200
+
+ # dpkg-source: correctly create .pc/.quilt_series with alternate
+ # series files
+ #
+ # If you have debian/patches/ubuntu.series and you were
+ # unpacking the source package on ubuntu, quilt was still
+ # directed to debian/patches/series instead of
+ # debian/patches/ubuntu.series.
+ #
+ # debian/changelog | 3 +++
+ # scripts/Dpkg/Source/Package/V3/quilt.pm | 4 +++-
+ # 2 files changed, 6 insertions(+), 1 deletion(-)
+
+ use Dpkg::Vendor;
+ vendor_patches_distro($ENV{DEB_VENDOR}, "DEB_VENDOR");
+ vendor_patches_distro(Dpkg::Vendor::get_current_vendor(),
+ "Dpkg::Vendor \`current vendor'");
+ vendor_patches_distro(access_basedistro(),
+ "distro being accessed");
+}
+
sub generate_commit_from_dsc () {
prep_ud();
changedir $ud;
@@ -1227,6 +1308,7 @@ sub generate_commit_from_dsc () {
runcmd @cmd;
my ($tree,$dir) = mktree_in_ud_from_only_subdir();
+ check_for_vendor_patches() if madformat($dsc->{format});
runcmd qw(sh -ec), 'dpkg-parsechangelog >../changelog.tmp';
my $clogp = parsecontrol('../changelog.tmp',"commit's changelog");
my $authline = clogp_authline $clogp;
@@ -1328,24 +1410,34 @@ sub ensure_we_have_orig () {
}
}
-sub rev_parse ($) {
- return cmdoutput @git, qw(rev-parse), "$_[0]~0";
-}
-
-sub is_fast_fwd ($$) {
- my ($ancestor,$child) = @_;
- my @cmd = (@git, qw(merge-base), $ancestor, $child);
- my $mb = cmdoutput_errok @cmd;
- if (defined $mb) {
- return rev_parse($mb) eq rev_parse($ancestor);
- } else {
- $?==256 or failedcmd @cmd;
- return 0;
- }
-}
-
sub git_fetch_us () {
- runcmd_ordryrun_local @git, qw(fetch),access_giturl(),fetchspec();
+ my @specs = (fetchspec());
+ push @specs,
+ map { "+refs/$_/*:".lrfetchrefs."/$_/*" }
+ qw(tags heads);
+ runcmd_ordryrun_local @git, qw(fetch -p -n -q), access_giturl(), @specs;
+
+ my %here;
+ my $tagpat = debiantag('*',access_basedistro);
+
+ git_for_each_ref("refs/tags/".$tagpat, sub {
+ my ($objid,$objtype,$fullrefname,$reftail) = @_;
+ printdebug "currently $fullrefname=$objid\n";
+ $here{$fullrefname} = $objid;
+ });
+ git_for_each_ref(lrfetchrefs."/tags/".$tagpat, sub {
+ my ($objid,$objtype,$fullrefname,$reftail) = @_;
+ my $lref = "refs".substr($fullrefname, length lrfetchrefs);
+ printdebug "offered $lref=$objid\n";
+ if (!defined $here{$lref}) {
+ my @upd = (@git, qw(update-ref), $lref, $objid, '');
+ runcmd_ordryrun_local @upd;
+ } elsif ($here{$lref} eq $objid) {
+ } else {
+ print STDERR \
+ "Not updateting $lref from $here{$lref} to $objid.\n";
+ }
+ });
}
sub fetch_from_archive () {
@@ -1452,6 +1544,38 @@ END
return 1;
}
+sub set_local_git_config ($$) {
+ my ($k, $v) = @_;
+ runcmd @git, qw(config), $k, $v;
+}
+
+sub setup_mergechangelogs () {
+ my $driver = 'dpkg-mergechangelogs';
+ my $cb = "merge.$driver";
+ my $attrs = '.git/info/attributes';
+ ensuredir '.git/info';
+
+ open NATTRS, ">", "$attrs.new" or die "$attrs.new $!";
+ if (!open ATTRS, "<", $attrs) {
+ $!==ENOENT or die "$attrs: $!";
+ } else {
+ while () {
+ chomp;
+ next if m{^debian/changelog\s};
+ print NATTRS $_, "\n" or die $!;
+ }
+ ATTRS->error and die $!;
+ close ATTRS;
+ }
+ print NATTRS "debian/changelog merge=$driver\n" or die $!;
+ close NATTRS;
+
+ set_local_git_config "$cb.name", 'debian/changelog merge driver';
+ set_local_git_config "$cb.driver", 'dpkg-mergechangelogs -m %O %A %B %A';
+
+ rename "$attrs.new", "$attrs" or die "$attrs: $!";
+}
+
sub clone ($) {
my ($dstdir) = @_;
canonicalise_suite();
@@ -1462,7 +1586,7 @@ sub clone ($) {
runcmd @git, qw(init -q);
my $giturl = access_giturl(1);
if (defined $giturl) {
- runcmd @git, qw(config), "remote.$remotename.fetch", fetchspec();
+ set_local_git_config "remote.$remotename.fetch", fetchspec();
open H, "> .git/HEAD" or die $!;
print H "ref: ".lref()."\n" or die $!;
close H or die $!;
@@ -1481,6 +1605,7 @@ sub clone ($) {
$vcsgiturl =~ s/\s+-b\s+\S+//g;
runcmd @git, qw(remote add vcs-git), $vcsgiturl;
}
+ setup_mergechangelogs();
runcmd @git, qw(reset --hard), lrref();
printdone "ready for work in $dstdir";
}
@@ -1567,7 +1692,7 @@ sub push_parse_changelog ($) {
$package = getfield $clogp, 'Source';
my $cversion = getfield $clogp, 'Version';
- my $tag = debiantag($cversion);
+ my $tag = debiantag($cversion, access_basedistro);
runcmd @git, qw(check-ref-format), $tag;
my $dscfn = dscfn($cversion);
@@ -1619,9 +1744,9 @@ tagger $authline
$package release $cversion for $clogsuite ($csuite) [dgit]
[dgit distro=$declaredistro$delibs]
END
- foreach my $ref (sort keys %supersedes) {
+ foreach my $ref (sort keys %previously) {
print TO <{format});
changedir '../../../..';
my $diffopt = $debuglevel>0 ? '--exit-code' : '--quiet';
my @diffcmd = (@git, qw(diff), $diffopt, $tree);
@@ -1709,13 +1835,7 @@ sub dopush ($) {
failedcmd @diffcmd;
}
}
-#fetch from alioth
-#do fast forward check and maybe fake merge
-# if (!is_fast_fwd(mainbranch
-# runcmd @git, qw(fetch -p ), "$alioth_git/$package.git",
-# map { lref($_).":".rref($_) }
-# (uploadbranch());
- my $head = rev_parse('HEAD');
+ my $head = git_rev_parse('HEAD');
if (!$changesfile) {
my $multi = "$buildproductsdir/".
"${package}_".(stripepoch $cversion)."_multi.changes";
@@ -1738,11 +1858,12 @@ sub dopush ($) {
responder_send_command("param head $head");
responder_send_command("param csuite $csuite");
- if ($forceflag && defined $lastpush_hash) {
- git_for_each_tag_referring($lastpush_hash, sub {
- my ($objid,$fullrefname,$tagname) = @_;
- responder_send_command("supersedes $fullrefname=$objid");
- $supersedes{$fullrefname} = $objid;
+ if (deliberately_not_fast_forward) {
+ git_for_each_ref(lrfetchrefs, sub {
+ my ($objid,$objtype,$lrfetchrefname,$reftail) = @_;
+ my $rrefname= substr($lrfetchrefname, length(lrfetchrefs) + 1);
+ responder_send_command("previously $rrefname=$objid");
+ $previously{$rrefname} = $objid;
});
}
@@ -1763,13 +1884,12 @@ sub dopush ($) {
my $tag_obj_hash = cmdoutput @git, qw(hash-object -w -t tag), $tagobjfn;
runcmd_ordryrun @git, qw(verify-tag), $tag_obj_hash;
runcmd_ordryrun_local @git, qw(update-ref), "refs/tags/$tag", $tag_obj_hash;
- runcmd_ordryrun @git, qw(tag -v --), $tag;
if (!check_for_git()) {
create_remote_git_repo();
}
runcmd_ordryrun @git, qw(push),access_giturl(),
- $forceflag."HEAD:".rrref(), "refs/tags/$tag";
+ $forceflag."HEAD:".rrref(), $forceflag."refs/tags/$tag";
runcmd_ordryrun @git, qw(update-ref -m), 'dgit push', lrref(), 'HEAD';
if ($we_are_responder) {
@@ -1876,6 +1996,7 @@ sub cmd_pull {
}
sub cmd_push {
+ pushing();
parseopts();
badusage "-p is not allowed with dgit push" if defined $package;
check_not_dirty();
@@ -1892,10 +2013,12 @@ sub cmd_push {
if ($new_package) {
local ($package) = $existing_package; # this is a hack
canonicalise_suite();
- }
- if (defined $specsuite && $specsuite ne $isuite) {
+ } else {
canonicalise_suite();
- $csuite eq $specsuite or
+ }
+ if (defined $specsuite &&
+ $specsuite ne $isuite &&
+ $specsuite ne $csuite) {
fail "dgit push: changelog specifies $isuite ($csuite)".
" but command line specifies $specsuite";
}
@@ -1906,15 +2029,14 @@ sub cmd_push {
if (fetch_from_archive()) {
if (is_fast_fwd(lrref(), 'HEAD')) {
# ok
- } elsif (deliberately('not-fast-forward') ||
- deliberately('TEST-not-fast-forward-dgit-only')) {
+ } elsif (deliberately_not_fast_forward) {
$forceflag = '+';
} else {
fail "dgit push: HEAD is not a descendant".
" of the archive's version.\n".
- "$us: To overwrite its contents,".
+ "dgit: To overwrite its contents,".
" use git merge -s ours ".lrref().".\n".
- "$us: To rewind history, if permitted by the archive,".
+ "dgit: To rewind history, if permitted by the archive,".
" use --deliberately-not-fast-forward";
}
} else {
@@ -1928,6 +2050,7 @@ sub cmd_push {
#---------- remote commands' implementation ----------
sub cmd_remote_push_build_host {
+ pushing();
my ($nrargs) = shift @ARGV;
my (@rargs) = @ARGV[0..$nrargs-1];
@ARGV = @ARGV[$nrargs..$#ARGV];
@@ -1938,6 +2061,7 @@ sub cmd_remote_push_build_host {
# offered several)
$debugprefix = ' ';
$we_are_responder = 1;
+ $us .= " (build host)";
open PI, "<&STDIN" or die $!;
open STDIN, "/dev/null" or die $!;
@@ -1987,6 +2111,7 @@ sub i_method {
}
sub cmd_rpush {
+ pushing();
my $host = nextarg;
my $dir;
if ($host =~ m/^((?:[^][]|\[[^][]*\])*)\:/) {
@@ -2060,12 +2185,12 @@ sub i_resp_param ($) {
$i_param{$1} = $2;
}
-sub i_resp_supersedes ($) {
+sub i_resp_previously ($) {
$_[0] =~ m#^(refs/tags/\S+)=(\w+)$#
- or badproto \*RO, "bad supersedes spec";
+ or badproto \*RO, "bad previously spec";
my $r = system qw(git check-ref-format), $1;
- die "bad supersedes ref spec ($r)" if $r;
- $supersedes{$1} = $2;
+ die "bad previously ref spec ($r)" if $r;
+ $previously{$1} = $2;
}
our %i_wanted;
@@ -2330,7 +2455,7 @@ sub quiltify ($$) {
my $s = $abbrev->($notp);
my $c = $notp->{Child};
$s .= "..".$abbrev->($c) if $c;
- $s .= ": ".$c->{Whynot};
+ $s .= ": ".$notp->{Whynot};
return $s;
};
if ($quilt_mode eq 'linear') {
@@ -2414,6 +2539,8 @@ sub build_maybe_quilt_fixup () {
return unless madformat $format;
# sigh
+ check_for_vendor_patches();
+
# Our objective is:
# - honour any existing .pc in case it has any strangeness
# - determine the git commit corresponding to the tip of
@@ -2459,7 +2586,7 @@ sub build_maybe_quilt_fixup () {
# 6. Back in the main tree, fast forward to the new HEAD
my $clogp = parsechangelog();
- my $headref = rev_parse('HEAD');
+ my $headref = git_rev_parse('HEAD');
prep_ud();
changedir $ud;
@@ -2538,7 +2665,7 @@ END
commit_quilty_patch();
if ($mustdeletepc) {
- runcmd @git, qw(rm -rq .pc);
+ runcmd @git, qw(rm -rqf .pc);
commit_admin "Commit removal of .pc (quilt series tracking data)";
}
@@ -2570,8 +2697,18 @@ sub quilt_fixup_editor () {
sub clean_tree () {
if ($cleanmode eq 'dpkg-source') {
runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean);
+ } elsif ($cleanmode eq 'dpkg-source-d') {
+ runcmd_ordryrun_local @dpkgbuildpackage, qw(-d -T clean);
} elsif ($cleanmode eq 'git') {
runcmd_ordryrun_local @git, qw(clean -xdf);
+ } elsif ($cleanmode eq 'git-ff') {
+ runcmd_ordryrun_local @git, qw(clean -xdff);
+ } elsif ($cleanmode eq 'check') {
+ my $leftovers = cmdoutput @git, qw(clean -xdn);
+ if (length $leftovers) {
+ print STDERR $leftovers, "\n" or die $!;
+ fail "tree contains uncommitted files and --clean=check specified";
+ }
} elsif ($cleanmode eq 'none') {
} else {
die "$cleanmode ?";
@@ -2621,17 +2758,35 @@ sub changesopts () {
return @opts;
}
+sub massage_dbp_args ($) {
+ my ($cmd) = @_;
+ return unless $cleanmode =~ m/git|none/;
+ debugcmd '#massaging#', @$cmd if $debuglevel>1;
+ my @newcmd = shift @$cmd;
+ # -nc has the side effect of specifying -b if nothing else specified
+ push @newcmd, '-nc';
+ # and some combinations of -S, -b, et al, are errors, rather than
+ # later simply overriding earlier
+ push @newcmd, '-F' unless grep { m/^-[bBASF]$/ } @$cmd;
+ push @newcmd, @$cmd;
+ @$cmd = @newcmd;
+}
+
sub cmd_build {
build_prep();
- runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc), changesopts(), @ARGV;
+ my @dbp = (@dpkgbuildpackage, qw(-us -uc), changesopts(), @ARGV);
+ massage_dbp_args \@dbp;
+ runcmd_ordryrun_local @dbp;
printdone "build successful\n";
}
sub cmd_git_build {
build_prep();
+ my @dbp = @dpkgbuildpackage;
+ massage_dbp_args \@dbp;
my @cmd =
(qw(git-buildpackage -us -uc --git-no-sign-tags),
- "--git-builder=@dpkgbuildpackage");
+ "--git-builder=@dbp");
unless (grep { m/^--git-debian-branch|^--git-ignore-branch/ } @ARGV) {
canonicalise_suite();
push @cmd, "--git-debian-branch=".lbranch();
@@ -2648,6 +2803,9 @@ sub build_source {
if ($cleanmode eq 'dpkg-source') {
runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S)),
changesopts();
+ } elsif ($cleanmode eq 'dpkg-source-d') {
+ runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S -d)),
+ changesopts();
} else {
my $pwd = must_getcwd();
my $leafdir = basename $pwd;
@@ -2672,7 +2830,7 @@ sub cmd_sbuild {
changedir "..";
my $pat = "${package}_".(stripepoch $version)."_*.changes";
if (act_local()) {
- stat_exist $dscfn or fail "$dscfn (in parent directory): $!";
+ stat_exists $dscfn or fail "$dscfn (in parent directory): $!";
stat_exists $sourcechanges
or fail "$sourcechanges (in parent directory): $!";
foreach my $cf (glob $pat) {
@@ -2712,6 +2870,20 @@ sub cmd_archive_api_query {
exec @cmd or fail "exec curl: $!\n";
}
+sub cmd_clone_dgit_repos_server {
+ badusage "need destination argument" unless @ARGV==1;
+ my ($destdir) = @ARGV;
+ $package = '_dgit-repos-server';
+ my @cmd = (@git, qw(clone), access_giturl(), $destdir);
+ debugcmd ">",@cmd;
+ exec @cmd or fail "exec git clone: $!\n";
+}
+
+sub cmd_setup_mergechangelogs {
+ badusage "no arguments allowed to dgit setup-mergechangelogs" if @ARGV;
+ setup_mergechangelogs();
+}
+
#---------- argument parsing and main program ----------
sub cmd_version {
@@ -2776,7 +2948,7 @@ sub parseopts () {
} elsif (m/^--build-products-dir=(.*)/s) {
push @ropts, $_;
$buildproductsdir = $1;
- } elsif (m/^--clean=(dpkg-source|git|none)$/s) {
+ } elsif (m/^--clean=(dpkg-source(?:-d)?|git|git-ff|check|none)$/s) {
push @ropts, $_;
$cleanmode = $1;
} elsif (m/^--clean=(.*)$/s) {
@@ -2848,9 +3020,18 @@ sub parseopts () {
} elsif (s/^-wg$//s) {
push @ropts, $&;
$cleanmode = 'git';
+ } elsif (s/^-wgf$//s) {
+ push @ropts, $&;
+ $cleanmode = 'git-ff';
} elsif (s/^-wd$//s) {
push @ropts, $&;
$cleanmode = 'dpkg-source';
+ } elsif (s/^-wdd$//s) {
+ push @ropts, $&;
+ $cleanmode = 'dpkg-source-d';
+ } elsif (s/^-wc$//s) {
+ push @ropts, $&;
+ $cleanmode = 'check';
} else {
badusage "unknown short option \`$_'";
}
@@ -2875,6 +3056,7 @@ my $cmd = shift @ARGV;
$cmd =~ y/-/_/;
if (!defined $quilt_mode) {
+ local $access_forpush;
$quilt_mode = cfg('dgit.force.quilt-mode', 'RETURN-UNDEF')
// access_cfg('quilt-mode', 'RETURN-UNDEF')
// 'linear';