X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=dgit;h=61a1f73007a5e94ba5ff706d2347bf37368e3343;hb=111b247b6198535db5788a07069971e409f539cd;hp=5ea9c26613432c1bbb95fcc4f86f2fa1351c410a;hpb=1d7cbdc7bef6b4752ba0d46b22dd77136c5b3efb;p=dgit.git
diff --git a/dgit b/dgit
index 5ea9c266..61a1f730 100755
--- a/dgit
+++ b/dgit
@@ -40,11 +40,13 @@ our @ropts;
our $sign = 1;
our $dryrun_level = 0;
our $changesfile;
+our $buildproductsdir = '..';
our $new_package = 0;
our $ignoredirty = 0;
our $noquilt = 0;
our $existing_package = 'dpkg';
our $cleanmode = 'dpkg-source';
+our $changes_since_version;
our $we_are_responder;
our $initiator_tempdir;
@@ -113,8 +115,6 @@ sub dscfn ($) {
return "${package}_".(stripepoch $vsn).".dsc";
}
-sub changesopts () { return @changesopts[1..$#changesopts]; }
-
our $us = 'dgit';
our $debugprefix = '';
@@ -248,14 +248,14 @@ sub responder_send_command ($) {
my ($command) = @_;
return unless $we_are_responder;
# called even without $we_are_responder
- printdebug "<< $command\n";
+ printdebug ">> $command\n";
print PO $command, "\n" or die $!;
}
sub responder_send_file ($$) {
my ($keyword, $ourfn) = @_;
return unless $we_are_responder;
- printdebug "[[ $keyword $ourfn\n";
+ printdebug "]] $keyword $ourfn\n";
responder_send_command "file $keyword";
protocol_send_file \*PO, $ourfn;
}
@@ -263,11 +263,12 @@ sub responder_send_file ($$) {
sub responder_receive_files ($@) {
my ($keyword, @ourfns) = @_;
die unless $we_are_responder;
- printdebug "]] $keyword @ourfns\n";
+ printdebug "[[ $keyword @ourfns\n";
responder_send_command "want $keyword";
foreach my $fn (@ourfns) {
protocol_receive_file \*PI, $fn;
}
+ printdebug "[[\$\n";
protocol_expect { m/^files-end$/ } \*PI;
}
@@ -312,7 +313,8 @@ sub shellquote {
local $_;
foreach my $a (@_) {
$_ = $a;
- if (s{['\\]}{\\$&}g || m{\s} || m{[^-_./0-9a-z]}i) {
+ if (m{[^-=_./0-9a-z]}i) {
+ s{['\\]}{'\\$&'}g;
push @out, "'$_'";
} else {
push @out, $_;
@@ -330,7 +332,7 @@ sub printcmd {
}
sub failedcmd {
- { local ($!); printcmd \*STDERR, "$_[0]: failed command:", @_ or die $!; };
+ { local ($!); printcmd \*STDERR, "$us: failed command:", @_ or die $!; };
if ($!) {
fail "failed to fork/exec: $!";
} elsif (!($? & 0xff)) {
@@ -440,20 +442,43 @@ sub cmd_help () {
exit 0;
}
+our $td = $ENV{DGIT_TEST_DUMMY_DIR} || "DGIT_TEST_DUMMY_DIR-unset";
+
our %defcfg = ('dgit.default.distro' => 'debian',
'dgit.default.username' => '',
'dgit.default.archive-query-default-component' => 'main',
'dgit.default.ssh' => 'ssh',
+ 'dgit-distro.debian.git-user' => 'dgit',
'dgit-distro.debian.git-host' => 'git.debian.org',
'dgit-distro.debian.git-proto' => 'git+ssh://',
- 'dgit-distro.debian.git-path' => '/git/dgit-repos/repos',
- 'dgit-distro.debian.git-check' => 'ssh-cmd',
- 'dgit-distro.debian.git-create' => 'ssh-cmd',
- 'dgit-distro.debian.sshdakls-host' => 'coccia.debian.org',
- 'dgit-distro.debian.sshdakls-dir' =>
- '/srv/ftp-master.debian.org/ftp/dists',
+ 'dgit-distro.debian.git-path' => '/dgit-repos/',
+ 'dgit-distro.debian.git-check' => 'true',
+ 'dgit-distro.debian.git-create' => 'true',
+ 'dgit-distro.debian.sshpsql-host' => 'coccia.debian.org',
+ 'dgit-distro.debian.sshpsql-dbname' => 'service=projectb',
'dgit-distro.debian.upload-host' => 'ftp-master', # for dput
- 'dgit-distro.debian.mirror' => 'http://ftp.debian.org/debian/');
+ 'dgit-distro.debian.mirror' => 'http://ftp.debian.org/debian/',
+ 'dgit-distro.debian.backports-quirk' => '%-backports*',
+ 'dgit-distro.debian-backports.mirror' => 'http://backports.debian.org/debian-backports/',
+ 'dgit-distro.test-dummy.ssh' => "$td/ssh",
+ 'dgit-distro.test-dummy.username' => "alice",
+ 'dgit-distro.test-dummy.git-check' => "ssh-cmd",
+ 'dgit-distro.test-dummy.git-create' => "ssh-cmd",
+ 'dgit-distro.test-dummy.git-url' => "$td/git",
+ 'dgit-distro.test-dummy.git-host' => "git",
+ 'dgit-distro.test-dummy.git-path' => "$td/git",
+ 'dgit-distro.test-dummy.archive-query' => "dummycat:$td/aq",
+ 'dgit-distro.test-dummy.mirror' => "file://$td/mirror/",
+ 'dgit-distro.test-dummy.upload-host' => 'test-dummy',
+ 'dgit-distro.test-dummy-drs.ssh' => "$td/ssh",
+ 'dgit-distro.test-dummy-drs.username' => "alice",
+ 'dgit-distro.test-dummy-drs.git-check' => "true",
+ 'dgit-distro.test-dummy-drs.git-create' => "true",
+ 'dgit-distro.test-dummy-drs.git-url' => "$td/git",
+ 'dgit-distro.test-dummy-drs.archive-query' => "dummycat:$td/aq",
+ 'dgit-distro.test-dummy-drs.mirror' => "file://$td/mirror/",
+ 'dgit-distro.test-dummy-drs.upload-host' => 'test-dummy',
+ );
sub cfg {
foreach my $c (@_) {
@@ -475,16 +500,41 @@ sub cfg {
badcfg "need value for one of: @_";
}
-sub access_distro () {
+sub access_basedistro () {
return cfg("dgit-suite.$isuite.distro",
"dgit.default.distro");
}
+sub access_quirk () {
+ # returns (quirk name, distro to use instead, quirk-specific info)
+ my $basedistro = access_basedistro();
+ my $backports_quirk = cfg("dgit-distro.$basedistro.backports-quirk",
+ 'RETURN-UNDEF');
+ if (defined $backports_quirk) {
+ my $re = $backports_quirk;
+ $re =~ s/[^-0-9a-z_\%*]/\\$&/ig;
+ $re =~ s/\*/.*/g;
+ $re =~ s/\%/([-0-9a-z_]+)/ or badcfg "backports-quirk needs \%";
+ if ($isuite =~ m/^$re$/) {
+ return ('backports',"$basedistro-backports",$1);
+ }
+ }
+ return ('none',$basedistro);
+}
+
+sub access_distro () {
+ return (access_quirk())[1];
+}
+
sub access_cfg (@) {
my (@keys) = @_;
+ my $basedistro = access_basedistro();
my $distro = $idistro || access_distro();
- my $value = cfg(map { ("dgit-distro.$distro.$_",
- "dgit.default.$_") } @keys);
+ my $value = cfg(map {
+ ("dgit-distro.$distro.$_",
+ "dgit-distro.$basedistro.$_",
+ "dgit.default.$_")
+ } @keys);
return $value;
}
@@ -563,17 +613,34 @@ 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 '';
+ }
+}
+
our %rmad;
sub archive_query ($) {
my ($method) = @_;
my $query = access_cfg('archive-query','RETURN-UNDEF');
if (!defined $query) {
- my $distro = access_distro();
+ my $distro = access_basedistro();
if ($distro eq 'debian') {
- $query = "sshdakls:".
- access_someuserhost('sshdakls').':'.
- access_cfg('sshdakls-dir');
+ $query = "sshpsql:".
+ access_someuserhost('sshpsql').':'.
+ access_cfg('sshpsql-dbname');
} else {
$query = "madison:$distro";
}
@@ -584,6 +651,12 @@ sub archive_query ($) {
{ no strict qw(refs); &{"${method}_${proto}"}($proto,$data); }
}
+sub pool_dsc_subpath ($$) {
+ my ($vsn,$component) = @_; # $package is implict arg
+ my $prefix = substr($package, 0, $package =~ m/^l/ ? 4 : 1);
+ return "/pool/$component/$prefix/$package/".dscfn($vsn);
+}
+
sub archive_query_madison ($$) {
my ($proto,$data) = @_;
die unless $proto eq 'madison';
@@ -593,28 +666,6 @@ sub archive_query_madison ($$) {
return madison_parse($rmad);
}
-sub archive_query_sshdakls ($$) {
- my ($proto,$data) = @_;
- $data =~ s/:.*// or badcfg "invalid sshdakls method string \`$data'";
- my $dakls = cmdoutput
- access_cfg_ssh, $data, qw(dak ls -asource),"-s$isuite",$package;
- return madison_parse($dakls);
-}
-
-sub canonicalise_suite_sshdakls ($$) {
- my ($proto,$data) = @_;
- $data =~ m/:/ or badcfg "invalid sshdakls method string \`$data'";
- my @cmd =
- (access_cfg_ssh, $`,
- "set -e; cd $';".
- " if test -h $isuite; then readlink $isuite; exit 0; fi;".
- " if test -d $isuite; then echo $isuite; exit 0; fi;".
- " exit 1");
- my $dakls = cmdoutput @cmd;
- failedcmd @cmd unless $dakls =~ m/^\w/;
- return $dakls;
-}
-
sub madison_parse ($) {
my ($rmad) = @_;
my @out;
@@ -622,7 +673,7 @@ sub madison_parse ($) {
$l =~ m{^ \s*( [^ \t|]+ )\s* \|
\s*( [^ \t|]+ )\s* \|
\s*( [^ \t|/]+ )(?:/([^ \t|/]+))? \s* \|
- \s*( [^ \t|]+ )\s* }x or die "$rmad $?";
+ \s*( [^ \t|]+ )\s* }x or die "$rmad ?";
$1 eq $package or die "$rmad $package ?";
my $vsn = $2;
my $newsuite = $3;
@@ -633,14 +684,13 @@ sub madison_parse ($) {
$component = access_cfg('archive-query-default-component');
}
$5 eq 'source' or die "$rmad ?";
- my $prefix = substr($package, 0, $package =~ m/^l/ ? 4 : 1);
- my $subpath = "/pool/$component/$prefix/$package/".dscfn($vsn);
- push @out, [$vsn,$subpath,$newsuite];
+ push @out, [$vsn,pool_dsc_subpath($vsn,$component),$newsuite];
}
return sort { -version_compare_string($a->[0],$b->[0]); } @out;
}
sub canonicalise_suite_madison ($$) {
+ # madison canonicalises for us
my @r = archive_query_madison($_[0],$_[1]);
@r or fail
"unable to canonicalise suite using package $package".
@@ -649,12 +699,116 @@ sub canonicalise_suite_madison ($$) {
return $r[0][2];
}
+sub sshpsql ($$) {
+ my ($data,$sql) = @_;
+ $data =~ m/:/ or badcfg "invalid sshpsql method string \`$data'";
+ my ($userhost,$dbname) = ($`,$'); #';
+ my @rows;
+ my @cmd = (access_cfg_ssh, $userhost,
+ "export LANG=C; ".shellquote qw(psql -A), $dbname, qw(-c), $sql);
+ printcmd(\*DEBUG,$debugprefix."|",@cmd) if $debug>0;
+ open P, "-|", @cmd or die $!;
+ while (
) {
+ chomp or die;
+ printdebug("$debugprefix>|$_|\n");
+ push @rows, $_;
+ }
+ $!=0; $?=0; close P or failedcmd @cmd;
+ @rows or die;
+ my $nrows = pop @rows;
+ $nrows =~ s/^\((\d+) rows?\)$/$1/ or die "$nrows ?";
+ @rows == $nrows+1 or die "$nrows ".(scalar @rows)." ?";
+ @rows = map { [ split /\|/, $_ ] } @rows;
+ my $ncols = scalar @{ shift @rows };
+ die if grep { scalar @$_ != $ncols } @rows;
+ return @rows;
+}
+
+sub sql_injection_check {
+ foreach (@_) { die "$_ $& ?" if m/[']/; }
+}
+
+sub archive_query_sshpsql ($$) {
+ my ($proto,$data) = @_;
+ sql_injection_check $isuite, $package;
+ my @rows = sshpsql($data, <[0],$b->[0]) } @rows;
+ @rows = map {
+ my ($vsn,$component,$filename) = @$_;
+ [ $vsn, "/pool/$component/$filename" ];
+ } @rows;
+ return @rows;
+}
+
+sub canonicalise_suite_sshpsql ($$) {
+ my ($proto,$data) = @_;
+ sql_injection_check $isuite;
+ my @rows = sshpsql($data, <[0] } @rows;
+ fail "unknown suite $isuite" unless @rows;
+ die "ambiguous $isuite: @rows ?" if @rows>1;
+ return $rows[0];
+}
+
+sub canonicalise_suite_dummycat ($$) {
+ my ($proto,$data) = @_;
+ my $dpath = "$data/suite.$isuite";
+ if (!open C, "<", $dpath) {
+ $!==ENOENT or die "$dpath: $!";
+ printdebug "dummycat canonicalise_suite $isuite $dpath ENOENT\n";
+ return $isuite;
+ }
+ $!=0; $_ = ;
+ chomp or die "$dpath: $!";
+ close C;
+ printdebug "dummycat canonicalise_suite $isuite $dpath = $_\n";
+ return $_;
+}
+
+sub archive_query_dummycat ($$) {
+ my ($proto,$data) = @_;
+ canonicalise_suite();
+ my $dpath = "$data/package.$csuite.$package";
+ if (!open C, "<", $dpath) {
+ $!==ENOENT or die "$dpath: $!";
+ printdebug "dummycat query $csuite $package $dpath ENOENT\n";
+ return ();
+ }
+ my @rows;
+ while () {
+ next if m/^\#/;
+ next unless m/\S/;
+ die unless chomp;
+ printdebug "dummycat query $csuite $package $dpath | $_\n";
+ my @row = split /\s+/, $_;
+ @row==2 or die "$dpath: $_ ?";
+ push @rows, \@row;
+ }
+ C->error and die "$dpath: $!";
+ close C;
+ return sort { -version_compare_string($a->[0],$b->[0]); } @rows;
+}
+
sub canonicalise_suite () {
return if defined $csuite;
fail "cannot operate on $isuite suite" if $isuite eq 'UNRELEASED';
$csuite = archive_query('canonicalise_suite');
if ($isuite ne $csuite) {
- # madison canonicalises for us
progress "canonical suite name for $isuite is $csuite";
}
}
@@ -692,6 +846,8 @@ sub check_for_git () {
my $r= cmdoutput @cmd;
failedcmd @cmd unless $r =~ m/^[01]$/;
return $r+0;
+ } elsif ($how eq 'true') {
+ return 1;
} else {
badcfg "unknown git-check \`$how'";
}
@@ -704,6 +860,8 @@ sub create_remote_git_repo () {
(access_cfg_ssh, access_gituserhost(),
"set -e; cd ".access_cfg('git-path').";".
" cp -a _template $package.git");
+ } elsif ($how eq 'true') {
+ # nothing to do
} else {
badcfg "unknown git-create \`$how'";
}
@@ -935,22 +1093,13 @@ sub fetch_from_archive () {
progress "no version available from the archive";
}
- my $lrref_fn = ".git/".lrref();
- if (open H, $lrref_fn) {
- $lastpush_hash = ;
- chomp $lastpush_hash;
- die "$lrref_fn $lastpush_hash ?" unless $lastpush_hash =~ m/^\w+$/;
- } elsif ($! == &ENOENT) {
- $lastpush_hash = '';
- } else {
- die "$lrref_fn $!";
- }
+ $lastpush_hash = git_get_ref(lrref());
printdebug "previous reference hash=$lastpush_hash\n";
my $hash;
if (defined $dsc_hash) {
- fail "missing git history even though dsc has hash -".
- " could not find commit $dsc_hash".
- " (should be in ".access_giturl()."#".rrref().")"
+ fail "missing remote git history even though dsc has hash -".
+ " could not find ref ".lrref().
+ " (should have been fetched from ".access_giturl()."#".rrref().")"
unless $lastpush_hash;
$hash = $dsc_hash;
ensure_we_have_orig();
@@ -1211,13 +1360,14 @@ sub dopush () {
my ($clogp, $cversion, $tag, $dscfn) =
push_parse_changelog("$clogpfn");
- stat "../$dscfn" or
+ my $dscpath = "$buildproductsdir/$dscfn";
+ stat $dscpath or
fail "looked for .dsc $dscfn, but $!;".
" maybe you forgot to build";
- responder_send_file('dsc', "../$dscfn");
+ responder_send_file('dsc', $dscpath);
- push_parse_dsc("../$dscfn", $dscfn, $cversion);
+ push_parse_dsc($dscpath, $dscfn, $cversion);
my $format = getfield $dsc, 'Format';
printdebug "format $format\n";
@@ -1227,7 +1377,8 @@ sub dopush () {
check_not_dirty();
changedir $ud;
progress "checking that $dscfn corresponds to HEAD";
- runcmd qw(dpkg-source -x --), "../../../../$dscfn";
+ runcmd qw(dpkg-source -x --),
+ $dscpath =~ m#^/# ? $dscpath : "../../../$dscpath";
my ($tree,$dir) = mktree_in_ud_from_only_subdir();
changedir '../../../..';
my @diffcmd = (@git, qw(diff --exit-code), $tree);
@@ -1249,32 +1400,40 @@ sub dopush () {
# (uploadbranch());
my $head = rev_parse('HEAD');
if (!$changesfile) {
- my $multi = "../${package}_".(stripepoch $cversion)."_multi.changes";
+ my $multi = "$buildproductsdir/".
+ "${package}_".(stripepoch $cversion)."_multi.changes";
if (stat "$multi") {
$changesfile = $multi;
} else {
$!==&ENOENT or die "$multi: $!";
my $pat = "${package}_".(stripepoch $cversion)."_*.changes";
- my @cs = glob "../$pat";
+ my @cs = glob "$buildproductsdir/$pat";
fail "failed to find unique changes file".
- " (looked for $pat in .., or $multi);".
+ " (looked for $pat in $buildproductsdir, or $multi);".
" perhaps you need to use dgit -C"
unless @cs==1;
($changesfile) = @cs;
}
+ } else {
+ $changesfile = "$buildproductsdir/$changesfile";
}
responder_send_file('changes',$changesfile);
responder_send_command("param head $head");
my $tfn = sub { ".git/dgit/tag$_[0]"; };
- my ($tagobjfn) =
- $we_are_responder
- ? responder_receive_files('signed-tag', $tfn->('.signed.tmp'))
- : push_mktag($head,$clogp,$tag,
- "../$dscfn",
- $changesfile,$changesfile,
- $tfn);
+ my $tagobjfn;
+
+ if ($we_are_responder) {
+ $tagobjfn = $tfn->('.signed.tmp');
+ responder_receive_files('signed-tag', $tagobjfn);
+ } else {
+ $tagobjfn =
+ push_mktag($head,$clogp,$tag,
+ $dscpath,
+ $changesfile,$changesfile,
+ $tfn);
+ }
my $tag_obj_hash = cmdoutput @git, qw(hash-object -w -t tag), $tagobjfn;
runcmd_ordryrun @git, qw(verify-tag), $tag_obj_hash;
@@ -1284,27 +1443,24 @@ sub dopush () {
if (!check_for_git()) {
create_remote_git_repo();
}
- runcmd_ordryrun @git, qw(push),access_giturl(),"HEAD:".rrref();
+ runcmd_ordryrun @git, qw(push),access_giturl(),
+ "HEAD:".rrref(), "refs/tags/$tag";
runcmd_ordryrun @git, qw(update-ref -m), 'dgit push', lrref(), 'HEAD';
- if (!$we_are_responder) {
- if (act_local()) {
- rename "../$dscfn.tmp","../$dscfn" or die "$dscfn $!";
- } else {
- progress "[new .dsc left in $dscfn.tmp]";
- }
- }
-
if ($we_are_responder) {
my $dryrunsuffix = act_local() ? "" : ".tmp";
responder_receive_files('signed-dsc-changes',
- "../$dscfn$dryrunsuffix",
+ "$dscpath$dryrunsuffix",
"$changesfile$dryrunsuffix");
} else {
+ if (act_local()) {
+ rename "$dscpath.tmp",$dscpath or die "$dscfn $!";
+ } else {
+ progress "[new .dsc left in $dscpath.tmp]";
+ }
sign_changes $changesfile;
}
- runcmd_ordryrun @git, qw(push),access_giturl(),"refs/tags/$tag";
my $host = access_cfg('upload-host','RETURN-UNDEF');
my @hostarg = defined($host) ? ($host,) : ();
runcmd_ordryrun @dput, @hostarg, $changesfile;
@@ -1406,7 +1562,7 @@ sub cmd_push {
is_fast_fwd(lrref(), 'HEAD') or
fail "dgit push: HEAD is not a descendant".
" of the archive's version.\n".
- "$us: To overwrite it, use git-merge -s ours ".lrref().".";
+ "$us: To overwrite it, use git merge -s ours ".lrref().".";
} else {
$new_package or
fail "package appears to be new in this suite;".
@@ -1498,16 +1654,6 @@ sub cmd_rpush {
};
i_method "i_resp", $icmd, $iargs;
}
-
- my $pid = $i_child_pid;
- $i_child_pid = undef; # prevents killing some other process with same pid
- printdebug "waiting for remote child $pid...";
- my $got = waitpid $pid, 0;
- die $! unless $got == $pid;
- die "remote child failed $?" if $?;
-
- i_cleanup();
- exit 0;
}
sub i_resp_progress ($) {
@@ -1517,7 +1663,15 @@ sub i_resp_progress ($) {
}
sub i_resp_complete {
+ my $pid = $i_child_pid;
+ $i_child_pid = undef; # prevents killing some other process with same pid
+ printdebug "waiting for remote child $pid...\n";
+ my $got = waitpid $pid, 0;
+ die $! unless $got == $pid;
+ die "remote child failed $?" if $?;
+
i_cleanup();
+ printdebug "all done\n";
exit 0;
}
@@ -1527,6 +1681,7 @@ sub i_resp_file ($) {
my $localpath = "$i_tmp/$localname";
stat $localpath and badproto \*RO, "file $keyword ($localpath) twice";
protocol_receive_file \*RO, $localpath;
+ i_method "i_file", $keyword;
}
our %i_param;
@@ -1542,45 +1697,60 @@ sub i_resp_want ($) {
my ($keyword) = @_;
die "$keyword ?" if $i_wanted{$keyword}++;
my @localpaths = i_method "i_want", $keyword;
- printdebug "]] $keyword @localpaths\n";
+ printdebug "[[ $keyword @localpaths\n";
foreach my $localpath (@localpaths) {
protocol_send_file \*RI, $localpath;
}
- print RI "end-files\n" or die $!;
+ print RI "files-end\n" or die $!;
}
-our ($i_clogp, $i_version, $i_tag, $i_dscfn);
+our ($i_clogp, $i_version, $i_tag, $i_dscfn, $i_changesfn);
-sub i_localname_parsed_changelog { return "remote-changelog.822"; }
-sub i_localname_changes { return "remote.changes"; }
-sub i_localname_dsc {
+sub i_localname_parsed_changelog {
+ return "remote-changelog.822";
+}
+sub i_file_parsed_changelog {
($i_clogp, $i_version, $i_tag, $i_dscfn) =
push_parse_changelog "$i_tmp/remote-changelog.822";
die if $i_dscfn =~ m#/|^\W#;
+}
+
+sub i_localname_dsc {
+ defined $i_dscfn or badproto \*RO, "dsc (before parsed-changelog)";
return $i_dscfn;
}
+sub i_file_dsc { }
+
+sub i_localname_changes {
+ defined $i_dscfn or badproto \*RO, "dsc (before parsed-changelog)";
+ $i_changesfn = $i_dscfn;
+ $i_changesfn =~ s/\.dsc$/_dgit.changes/ or die;
+ return $i_changesfn;
+}
+sub i_file_changes { }
sub i_want_signed_tag {
printdebug Dumper(\%i_param, $i_dscfn);
- defined $i_param{'head'} && defined $i_dscfn
- or badproto \*RO, "sequencing error";
+ defined $i_param{'head'} && defined $i_dscfn && defined $i_clogp
+ or badproto \*RO, "premature desire for signed-tag";
my $head = $i_param{'head'};
die if $head =~ m/[^0-9a-f]/ || $head !~ m/^../;
- push_parse_dsc $i_dscfn, 'remote dsc',
+ push_parse_dsc $i_dscfn, 'remote dsc', $i_version;
- push_mktag $head, $i_clogp, $i_tag,
- $i_dscfn,
- 'remote.changes', 'remote changes',
- 'tag.tag';
+ my $tagobjfn =
+ push_mktag $head, $i_clogp, $i_tag,
+ $i_dscfn,
+ $i_changesfn, 'remote changes',
+ sub { "tag$_[0]"; };
- return 'tag.tag';
+ return $tagobjfn;
}
sub i_want_signed_dsc_changes {
rename "$i_dscfn.tmp","$i_dscfn" or die "$i_dscfn $!";
- sign_changes 'remote.changes';
- return ($i_dscfn, 'remote.changes');
+ sign_changes $i_changesfn;
+ return ($i_dscfn, $i_changesfn);
}
#---------- building etc. ----------
@@ -1601,6 +1771,17 @@ sub build_maybe_quilt_fixup () {
chomp;
return unless madformat($_);
# sigh
+
+ my @cmd = (@git, qw(ls-files --exclude-standard -iodm));
+ my $problems = cmdoutput @cmd;
+ if (length $problems) {
+ print STDERR "problematic files:\n";
+ print STDERR " $_\n" foreach split /\n/, $problems;
+ fail "Cannot do quilt fixup in tree containing ignored files. ".
+ "Perhaps your package's clean target is broken, in which".
+ " case -wg (which says to use git-clean -xdf) may help.";
+ }
+
my $clogp = parsechangelog();
my $version = getfield $clogp, 'Version';
my $author = getfield $clogp, 'Maintainer';
@@ -1660,9 +1841,21 @@ sub quilt_fixup_editor () {
exit 0;
}
+sub clean_tree () {
+ if ($cleanmode eq 'dpkg-source') {
+ runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean);
+ } elsif ($cleanmode eq 'git') {
+ runcmd_ordryrun_local @git, qw(clean -xdf);
+ } elsif ($cleanmode eq 'none') {
+ } else {
+ die "$cleanmode ?";
+ }
+}
+
sub build_prep () {
badusage "-p is not allowed when building" if defined $package;
check_not_dirty();
+ clean_tree();
my $clogp = parsechangelog();
$isuite = getfield $clogp, 'Distribution';
$package = getfield $clogp, 'Source';
@@ -1670,17 +1863,40 @@ sub build_prep () {
build_maybe_quilt_fixup();
}
+sub changesopts () {
+ my @opts =@changesopts[1..$#changesopts];
+ if (!defined $changes_since_version) {
+ my @vsns = archive_query('archive_query');
+ my @quirk = access_quirk();
+ if ($quirk[0] eq 'backports') {
+ local $isuite = $quirk[2];
+ local $csuite;
+ canonicalise_suite();
+ push @vsns, archive_query('archive_query');
+ }
+ if (@vsns) {
+ @vsns = map { $_->[0] } @vsns;
+ @vsns = sort { -version_compare_string($a, $b) } @vsns;
+ $changes_since_version = $vsns[0];
+ progress "changelog will contain changes since $vsns[0]";
+ } else {
+ $changes_since_version = '_';
+ progress "package seems new, not specifying -v";
+ }
+ }
+ if ($changes_since_version ne '_') {
+ unshift @opts, "-v$changes_since_version";
+ }
+ return @opts;
+}
+
sub cmd_build {
- badusage "dgit build implies --clean=dpkg-source"
- if $cleanmode ne 'dpkg-source';
build_prep();
runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc), changesopts(), @ARGV;
printdone "build successful\n";
}
sub cmd_git_build {
- badusage "dgit git-build implies --clean=dpkg-source"
- if $cleanmode ne 'dpkg-source';
build_prep();
my @cmd =
(qw(git-buildpackage -us -uc --git-no-sign-tags),
@@ -1702,12 +1918,6 @@ sub build_source {
runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S)),
changesopts();
} else {
- if ($cleanmode eq 'git') {
- runcmd_ordryrun_local @git, qw(clean -xdf);
- } elsif ($cleanmode eq 'none') {
- } else {
- die "$cleanmode ?";
- }
my $pwd = cmdoutput qw(env - pwd);
my $leafdir = basename $pwd;
changedir "..";
@@ -1739,7 +1949,14 @@ sub cmd_sbuild {
}
}
runcmd_ordryrun_local @sbuild, @ARGV, qw(-d), $isuite, $dscfn;
- runcmd_ordryrun_local @mergechanges, glob $pat;
+ my @changesfiles = glob $pat;
+ @changesfiles = sort {
+ ($b =~ m/_source\.changes$/ <=> $a =~ m/_source\.changes$/)
+ or $a cmp $b
+ } @changesfiles;
+ fail "wrong number of different changes files (@changesfiles)"
+ unless @changesfiles;
+ runcmd_ordryrun_local @mergechanges, @changesfiles;
my $multichanges = "${package}_".(stripepoch $version)."_multi.changes";
if (act_local()) {
stat $multichanges or fail "$multichanges: $!";
@@ -1791,12 +2008,15 @@ sub parseopts () {
} elsif (m/^--new$/) {
push @ropts, $_;
$new_package=1;
- } elsif (m/^--(\w+)=(.*)/s &&
+ } elsif (m/^--since-version=([^_]+|_)$/) {
+ push @ropts, $_;
+ $changes_since_version = $1;
+ } elsif (m/^--([-0-9a-z]+)=(.*)/s &&
($om = $opts_opt_map{$1}) &&
length $om->[0]) {
push @ropts, $_;
$om->[0] = $2;
- } elsif (m/^--(\w+):(.*)/s &&
+ } elsif (m/^--([-0-9a-z]+):(.*)/s &&
!$opts_opt_cmdonly{$1} &&
($om = $opts_opt_map{$1})) {
push @ropts, $_;
@@ -1812,6 +2032,9 @@ sub parseopts () {
} elsif (m/^--distro=(.*)/s) {
push @ropts, $_;
$idistro = $1;
+ } elsif (m/^--build-products-dir=(.*)/s) {
+ push @ropts, $_;
+ $buildproductsdir = $1;
} elsif (m/^--clean=(dpkg-source|git|none)$/s) {
push @ropts, $_;
$cleanmode = $1;
@@ -1844,7 +2067,10 @@ sub parseopts () {
} elsif (s/^-N/-/) {
push @ropts, $&;
$new_package=1;
- } elsif (m/^-[vm]/) {
+ } elsif (s/^-v([^_]+|_)$//s) {
+ push @ropts, $&;
+ $changes_since_version = $1;
+ } elsif (m/^-m/) {
push @ropts, $&;
push @changesopts, $_;
$_ = '';
@@ -1857,6 +2083,9 @@ sub parseopts () {
} elsif (s/^-C(.*)//s) {
push @ropts, $&;
$changesfile = $1;
+ if ($changesfile =~ s#^(.*)/##) {
+ $buildproductsdir = $1;
+ }
} elsif (s/^-k(.*)//s) {
$keyid=$1;
} elsif (s/^-wn//s) {