our $existing_package = 'dpkg';
our $cleanmode;
our $changes_since_version;
+our $rmchanges;
our $quilt_mode;
-our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck';
+our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|unapplied';
our $we_are_responder;
our $initiator_tempdir;
our $suite_re = '[-+.0-9a-z]+';
our $cleanmode_re = 'dpkg-source(?:-d)?|git|git-ff|check|none';
+our $git_authline_re = '^([^<>]+) \<(\S+)\> (\d+ [-+]\d+)$';
+
our (@git) = qw(git);
our (@dget) = qw(dget);
our (@curl) = qw(curl -f);
our (@dput) = qw(dput);
our (@debsign) = qw(debsign);
our (@gpg) = qw(gpg);
-our (@sbuild) = qw(sbuild -A);
+our (@sbuild) = qw(sbuild);
our (@ssh) = 'ssh';
our (@dgit) = qw(dgit);
our (@dpkgbuildpackage) = qw(dpkg-buildpackage -i\.git/ -I.git);
our (@dpkgsource) = qw(dpkg-source -i\.git/ -I.git);
our (@dpkggenchanges) = qw(dpkg-genchanges);
our (@mergechanges) = qw(mergechanges -f);
+our (@gbppq) = qw(gbp-pq);
our (@changesopts) = ('');
our %opts_opt_map = ('dget' => \@dget, # accept for compatibility
autoflush STDOUT 1;
our $supplementary_message = '';
+our $need_split_build_invocation = 0;
+our $split_brain = 0;
END {
local ($@, $?);
return srcfn($vsn,".dsc");
}
+sub changespat ($;$) {
+ my ($vsn, $arch) = @_;
+ return "${package}_".(stripepoch $vsn)."_".($arch//'*').".changes";
+}
+
our $us = 'dgit';
initdebug('');
local ($?);
foreach my $f (@end) {
eval { $f->(); };
- warn "$us: cleanup: $@" if length $@;
+ print STDERR "$us: cleanup: $@" if length $@;
}
};
our $ud = '.git/dgit/unpack';
-sub prep_ud () {
- rmtree($ud);
+sub prep_ud (;$) {
+ my ($d) = @_;
+ $d //= $ud;
+ rmtree($d);
mkpath '.git/dgit';
- mkdir $ud or die $!;
+ mkdir $d or die $!;
}
sub mktree_in_ud_here () {
remove_stray_gits();
mktree_in_ud_here();
- my $format=get_source_format();
+ my ($format, $fopts) = get_source_format();
if (madformat($format)) {
rmtree '.pc';
}
$author =~ s#,.*##ms;
my $date = cmdoutput qw(date), '+%s %z', qw(-d), getfield($clogp,'Date');
my $authline = "$author $date";
- $authline =~ m/^[^<>]+ \<\S+\> \d+ [-+]\d+$/ or
+ $authline =~ m/$git_authline_re/o or
fail "unexpected commit author line format \`$authline'".
" (was generated from changelog Maintainer field)";
+ return ($1,$2,$3) if wantarray;
return $authline;
}
canonicalise_suite();
badusage "dry run makes no sense with clone" unless act_local();
my $hasgit = check_for_git();
- mkdir $dstdir or die "$dstdir $!";
+ mkdir $dstdir or fail "create \`$dstdir': $!";
changedir $dstdir;
runcmd @git, qw(init -q);
my $giturl = access_giturl(1);
}
sub check_not_dirty () {
+ foreach my $f (qw(local-options local-patch-header)) {
+ if (stat_exists "debian/source/$f") {
+ fail "git tree contains debian/source/$f";
+ }
+ }
+
return if $ignoredirty;
+
my @cmd = (@git, qw(diff --quiet HEAD));
debugcmd "+",@cmd;
$!=0; $?=0; system @cmd;
return;
}
my @adds = map { s/[][*?\\]/\\$&/g; $_; } sort keys %adds;
- runcmd_ordryrun_local @git, qw(add), @adds;
+ runcmd_ordryrun_local @git, qw(add -f), @adds;
commit_admin "Commit Debian 3.0 (quilt) metadata";
}
sub get_source_format () {
+ my %options;
+ if (open F, "debian/source/options") {
+ while (<F>) {
+ next if m/^\s*\#/;
+ next unless m/\S/;
+ s/\s+$//; # ignore missing final newline
+ if (m/\s*\#\s*/) {
+ my ($k, $v) = ($`, $'); #');
+ $v =~ s/^"(.*)"$/$1/;
+ $options{$k} = $v;
+ } else {
+ $options{$_} = 1;
+ }
+ }
+ F->error and die $!;
+ close F;
+ } else {
+ die $! unless $!==&ENOENT;
+ }
+
if (!open F, "debian/source/format") {
die $! unless $!==&ENOENT;
return '';
$_ = <F>;
F->error and die $!;
chomp;
- return $_;
+ return ($_, \%options);
}
sub madformat ($) {
my $format = getfield $dsc, 'Format';
printdebug "format $format\n";
if (madformat($format)) {
+ # user might have not used dgit build, so maybe do this now:
commit_quilty_patch();
}
check_not_dirty();
}
my $head = git_rev_parse('HEAD');
if (!$changesfile) {
- my $multi = "$buildproductsdir/".
- "${package}_".(stripepoch $cversion)."_multi.changes";
- if (stat_exists "$multi") {
- $changesfile = $multi;
- } else {
- my $pat = "${package}_".(stripepoch $cversion)."_*.changes";
- my @cs = glob "$buildproductsdir/$pat";
- fail "failed to find unique changes file".
- " (looked for $pat in $buildproductsdir, or $multi);".
- " perhaps you need to use dgit -C"
- unless @cs==1;
- ($changesfile) = @cs;
- }
+ my $pat = changespat $cversion;
+ my @cs = glob "$buildproductsdir/$pat";
+ fail "failed to find unique changes file".
+ " (looked for $pat in $buildproductsdir);".
+ " perhaps you need to use dgit -C"
+ unless @cs==1;
+ ($changesfile) = @cs;
} else {
$changesfile = "$buildproductsdir/$changesfile";
}
sign_changes $changesfile;
}
- supplementary_message(<<'END');
+ supplementary_message(<<END);
Push failed, while uploading package(s) to the archive server.
You can retry the upload of exactly these same files with dput of:
$changesfile
return if $!==&ENOENT;
die "chdir $cwd_remove: $!";
}
- rmtree($dstdir) or die "remove $dstdir: $!\n";
+ if (stat $dstdir) {
+ rmtree($dstdir) or die "remove $dstdir: $!\n";
+ } elsif (!grep { $! == $_ }
+ (ENOENT, ENOTDIR, EACCES, EPERM, ELOOP)) {
+ } else {
+ print STDERR "check whether to remove $dstdir: $!\n";
+ }
};
}
local $ENV{'EDITOR'} = cmdoutput qw(realpath --), $0;
local $ENV{'VISUAL'} = $ENV{'EDITOR'};
local $ENV{$fakeeditorenv} = cmdoutput qw(realpath --), $descfn;
- runcmd_ordryrun_local @dpkgsource, qw(--commit .), $patchname;
+ runcmd @dpkgsource, qw(--commit .), $patchname;
}
}
-sub quiltify_trees_differ ($$) {
- my ($x,$y) = @_;
- # returns 1 iff the two tree objects differ other than in debian/
+sub quiltify_trees_differ ($$;$) {
+ my ($x,$y,$finegrained) = @_;
+ # returns true iff the two tree objects differ other than in debian/
+ # with $finegrained,
+ # returns bitmask 01 - differ in upstream files except .gitignore
+ # 02 - differ in .gitignore
local $/=undef;
- my @cmd = (@git, qw(diff-tree --name-only -z), $x, $y);
+ my @cmd = (@git, qw(diff-tree --name-only -z));
+ push @cmd, qw(-r) if $finegrained;
+ push @cmd, $x, $y;
my $diffs= cmdoutput @cmd;
+ my $r = 0;
foreach my $f (split /\0/, $diffs) {
- next if $f eq 'debian';
- return 1;
+ next if $f =~ m#^debian(?:/.*)?$#s;
+ $r |= ($f =~ m#^(?:.*/)?.gitignore$#s) ? 02 : 01;
}
- return 0;
+ printdebug "quiltify_trees_differ $x $y => $r\n";
+ return $r;
}
sub quiltify_tree_sentinelfiles ($) {
qw(-- debian/rules debian/control);
$r =~ s/\n/,/g;
return $r;
+ }
+
+sub quiltify_splitbrain_needed () {
+ if (!$split_brain) {
+ progress "creating dgit view";
+ runcmd @git, qw(checkout -q -b dgit-view);
+ $split_brain = 1;
+ }
}
-sub quiltify ($$) {
- my ($clogp,$target) = @_;
+sub quiltify_splitbrain ($$) {
+ my ($clogp, $diffbits) = @_;
+ if ($quilt_mode !~ m/gbp|dpm/) {
+ # treat .gitignore just like any other upstream file
+ $diffbits = { %$diffbits };
+ $_ = !!$_ foreach values %$diffbits;
+ }
+ if ($quilt_mode =~ m/gbp|unapplied/ &&
+ ($diffbits->{O2A} & 01) && # some patches
+ !($diffbits->{H2O} & 01)) { # but HEAD is like orig
+ quiltify_splitbrain_needed();
+ progress "creating patches-applied version using gbp-pq";
+ my @authline = clogp_authline($clogp);
+ local $ENV{GIT_COMMITTER_NAME} = $authline[0];
+ local $ENV{GIT_COMMITTER_EMAIL} = $authline[1];
+ local $ENV{GIT_COMMITTER_DATE} = $authline[2];
+ open STDOUT, ">/dev/null" or die $!;
+ runcmd shell_cmd 'exec >/dev/null', @gbppq, qw(import);
+ }
+ if (($diffbits->{H2O} & 02) && # user has modified .gitignore
+ !($diffbits->{O2A} & 02)) { # patches do not change .gitignore
+ quiltify_splitbrain_needed();
+ progress "creating patch to represent .gitignore changes";
+ die 'xxx gitignore';
+
+ }
+ die 'xxx memoisation via git-reflog';
+ die 'xxx fast forward (should not depend on quilt mode, but will always be needed if we did $split_brain)';
+}
+
+sub quiltify ($$$$) {
+ my ($clogp,$target,$oldtiptree,$failsuggestion) = @_;
# Quilt patchification algorithm
#
# After traversing PT, we git commit the changes which
# should be contained within debian/patches.
- changedir '../fake';
- remove_stray_gits();
- mktree_in_ud_here();
- rmtree '.pc';
- runcmd @git, 'add', '.';
- my $oldtiptree=git_write_tree();
- changedir '../work';
-
# The search for the path S..T is breadth-first. We maintain a
# todo list containing search nodes. A search node identifies a
# commit, and looks something like this:
my $abbrev = sub {
my $x = $_[0]{Commit};
$x =~ s/(.*?[0-9a-z]{8})[0-9a-z]*$/$1/;
- return $;
+ return $x;
};
my $reportnot = sub {
my ($notp) = @_;
foreach my $notp (@nots) {
print STDERR "$us: ", $reportnot->($notp), "\n";
}
+ print STDERR "$us: $_\n" foreach @$failsuggestion;
fail "quilt fixup naive history linearisation failed.\n".
"Use dpkg-source --commit by hand; or, --quilt=smash for one ugly patch";
} elsif ($quilt_mode eq 'smash') {
}
sub build_maybe_quilt_fixup () {
- my $format=get_source_format;
+ my ($format,$fopts) = get_source_format;
return unless madformat $format;
# sigh
check_for_vendor_patches();
+ my $clogp = parsechangelog();
+ my $headref = git_rev_parse('HEAD');
+
+ prep_ud();
+ changedir $ud;
+
+ my $upstreamversion=$version;
+ $upstreamversion =~ s/-[^-]*$//;
+
+ if ($fopts->{'single-debian-patch'}) {
+ quilt_fixup_singlepatch($clogp, $headref, $upstreamversion);
+ } else {
+ quilt_fixup_multipatch($clogp, $headref, $upstreamversion);
+ }
+
+ changedir '../../../..';
+ runcmd_ordryrun_local
+ @git, qw(pull --ff-only -q .git/dgit/unpack/work master);
+}
+
+sub quilt_fixup_mkwork ($) {
+ my ($headref) = @_;
+
+ mkdir "work" or die $!;
+ changedir "work";
+ mktree_in_ud_here();
+ runcmd @git, qw(reset -q --hard), $headref;
+}
+
+sub quilt_fixup_linkorigs ($$) {
+ my ($upstreamversion, $fn) = @_;
+ # calls $fn->($leafname);
+
+ foreach my $f (<../../../../*>) { #/){
+ my $b=$f; $b =~ s{.*/}{};
+ {
+ local ($debuglevel) = $debuglevel-1;
+ printdebug "QF linkorigs $b, $f ?\n";
+ }
+ next unless is_orig_file $b, srcfn $upstreamversion,'';
+ printdebug "QF linkorigs $b, $f Y\n";
+ link_ltarget $f, $b or die "$b $!";
+ $fn->($b);
+ }
+}
+
+sub quilt_fixup_delete_pc () {
+ runcmd @git, qw(rm -rqf .pc);
+ commit_admin "Commit removal of .pc (quilt series tracking data)";
+}
+
+sub quilt_fixup_singlepatch ($$$) {
+ my ($clogp, $headref, $upstreamversion) = @_;
+
+ progress "starting quiltify (single-debian-patch)";
+
+ # dpkg-source --commit generates new patches even if
+ # single-debian-patch is in debian/source/options. In order to
+ # get it to generate debian/patches/debian-changes, it is
+ # necessary to build the source package.
+
+ quilt_fixup_linkorigs($upstreamversion, sub { });
+ quilt_fixup_mkwork($headref);
+
+ rmtree("debian/patches");
+
+ runcmd @dpkgsource, qw(-b .);
+ chdir "..";
+ runcmd @dpkgsource, qw(-x), (srcfn $version, ".dsc");
+ rename srcfn("$upstreamversion", "/debian/patches"),
+ "work/debian/patches";
+
+ chdir "work";
+ commit_quilty_patch();
+
+
+}
+
+sub quilt_fixup_multipatch ($$$) {
+ my ($clogp, $headref, $upstreamversion) = @_;
+
+ progress "starting quiltify (multiple patches, $quilt_mode mode)";
+
# Our objective is:
# - honour any existing .pc in case it has any strangeness
# - determine the git commit corresponding to the tip of
# can work. We do this as follows:
# 1. Collect all relevant .orig from parent directory
# 2. Generate a debian.tar.gz out of
- # debian/{patches,rules,source/format}
+ # debian/{patches,rules,source/format,source/options}
# 3. Generate a fake .dsc containing just these fields:
# Format Source Version Files
# 4. Extract the fake .dsc
# 5. If we had a .pc in-tree, delete it, and git-commit
# 6. Back in the main tree, fast forward to the new HEAD
- my $clogp = parsechangelog();
- my $headref = git_rev_parse('HEAD');
-
- prep_ud();
- changedir $ud;
-
- my $upstreamversion=$version;
- $upstreamversion =~ s/-[^-]*$//;
+ # Another situation we may have to cope with is gbp-style
+ # patches-unapplied trees.
+ #
+ # We would want to detect these, so we know to escape into
+ # quilt_fixup_gbp. However, this is in general not possible.
+ # Consider a package with a one patch which the dgit user reverts
+ # (with git-revert or the moral equivalent).
+ #
+ # That is indistinguishable in contents from a patches-unapplied
+ # tree. And looking at the history to distinguish them is not
+ # useful because the user might have made a confusing-looking git
+ # history structure (which ought to produce an error if dgit can't
+ # cope, not a silent reintroduction of an unwanted patch).
+ #
+ # So gbp users will have to pass an option. But we can usually
+ # detect their failure to do so: if the tree is not a clean
+ # patches-applied tree, quilt linearisation fails, but the tree
+ # _is_ a clean patches-unapplied tree, we can suggest that maybe
+ # they want --quilt=unapplied.
+ #
+ # To help detect this, when we are extracting the fake dsc, we
+ # first extract it with --skip-patches, and then apply the patches
+ # afterwards with dpkg-source --before-build. That lets us save a
+ # tree object corresponding to .origs.
my $fakeversion="$upstreamversion-~~DGITFAKE";
print $fakedsc " ".$md->hexdigest." $size $b\n" or die $!;
};
- foreach my $f (<../../../../*>) { #/){
- my $b=$f; $b =~ s{.*/}{};
- next unless is_orig_file $b, srcfn $upstreamversion,'';
- link_ltarget $f, $b or die "$b $!";
- $dscaddfile->($b);
- }
+ quilt_fixup_linkorigs($upstreamversion, $dscaddfile);
- my @files=qw(debian/source/format debian/rules);
- if (stat_exists '../../../debian/patches') {
- push @files, 'debian/patches';
+ my @files=qw(debian/source/format debian/rules
+ debian/control debian/changelog);
+ foreach my $maybe (qw(debian/patches debian/source/options
+ debian/tests/control)) {
+ next unless stat_exists "../../../$maybe";
+ push @files, $maybe;
}
my $debtar= srcfn $fakeversion,'.debian.tar.gz';
$dscaddfile->($debtar);
close $fakedsc or die $!;
- runcmd qw(sh -ec), 'exec dpkg-source --no-check -x fake.dsc >/dev/null';
+ runcmd qw(sh -ec),
+ 'exec dpkg-source --no-check --skip-patches -x fake.dsc >/dev/null';
my $fakexdir= $package.'-'.(stripepoch $upstreamversion);
rename $fakexdir, "fake" or die "$fakexdir $!";
- mkdir "work" or die $!;
- changedir "work";
+ changedir 'fake';
+
+ remove_stray_gits();
mktree_in_ud_here();
- runcmd @git, qw(reset --hard), $headref;
+
+ rmtree '.pc';
+
+ runcmd @git, qw(add -Af .);
+ my $unapplied=git_write_tree();
+ printdebug "fake orig tree object $unapplied\n";
+
+ ensuredir '.pc';
+
+ runcmd qw(sh -ec),
+ 'exec dpkg-source --before-build . >/dev/null';
+
+ changedir '..';
+
+ quilt_fixup_mkwork($headref);
my $mustdeletepc=0;
if (stat_exists ".pc") {
rename '../fake/.pc','.pc' or die $!;
}
- quiltify($clogp,$headref);
+ changedir '../fake';
+ rmtree '.pc';
+ runcmd @git, qw(add -Af .);
+ my $oldtiptree=git_write_tree();
+ changedir '../work';
+
+
+ # We calculate some guesswork now about what kind of tree this might
+ # be. This is mostly for error reporting.
+
+ my $diffbits = {
+ # H = user's HEAD
+ # O = orig, without patches applied
+ # A = "applied", ie orig with H's debian/patches applied
+ H2O => quiltify_trees_differ($headref, $unapplied, 1),
+ H2A => quiltify_trees_differ($headref, $oldtiptree,1),
+ O2A => quiltify_trees_differ($unapplied,$oldtiptree,1),
+ };
+
+ my @dl;
+ foreach my $b (qw(01 02)) {
+ foreach my $v (qw(H2O O2A H2A)) {
+ push @dl, ($diffbits->{$v} & $b) ? '##' : '==';
+ }
+ }
+ printdebug "differences \@dl @dl.\n";
+
+ progress sprintf
+"$us: quilt differences: src: %s orig %s gitignores: %s orig %s\n".
+"$us: quilt differences: HEAD %s o+d/p HEAD %s o+d/p",
+ $dl[0], $dl[1], $dl[3], $dl[4],
+ $dl[2], $dl[5];
+
+ my @failsuggestion;
+ if (!($diffbits->{H2O} & $diffbits->{O2A})) {
+ push @failsuggestion, "This might be a patches-unapplied branch.";
+ } elsif (!($diffbits->{H2A} & $diffbits->{O2A})) {
+ push @failsuggestion, "This might be a patches-applied branch.";
+ }
+ push @failsuggestion, "Maybe you need to specify one of".
+ " --quilt=gbp --quilt=dpm --quilt=unapplied ?";
+
+ if ($quilt_mode =~ m/gbp|dpm|unapplied/) {
+ quiltify_splitbrain($clogp, $diffbits);
+ return;
+ }
+
+ quiltify($clogp,$headref,$oldtiptree,\@failsuggestion);
if (!open P, '>>', ".pc/applied-patches") {
$!==&ENOENT or die $!;
commit_quilty_patch();
if ($mustdeletepc) {
- runcmd @git, qw(rm -rqf .pc);
- commit_admin "Commit removal of .pc (quilt series tracking data)";
+ quilt_fixup_delete_pc();
}
-
- changedir '../../../..';
- runcmd @git, qw(pull --ff-only -q .git/dgit/unpack/work master);
}
sub quilt_fixup_editor () {
$package = getfield $clogp, 'Source';
$version = getfield $clogp, 'Version';
build_maybe_quilt_fixup();
+ if ($rmchanges) {
+ my $pat = changespat $version;
+ foreach my $f (glob "$buildproductsdir/$pat") {
+ if (act_local()) {
+ unlink $f or fail "remove old changes file $f: $!";
+ } else {
+ progress "would remove $f";
+ }
+ }
+ }
}
sub changesopts_initial () {
sub massage_dbp_args ($;$) {
my ($cmd,$xargs) = @_;
- if ($cleanmode eq 'dpkg-source') {
+ # We need to:
+ #
+ # - if we're going to split the source build out so we can
+ # do strange things to it, massage the arguments to dpkg-buildpackage
+ # so that the main build doessn't build source (or add an argument
+ # to stop it building source by default).
+ #
+ # - add -nc to stop dpkg-source cleaning the source tree,
+ # unless we're not doing a split build and want dpkg-source
+ # as cleanmode, in which case we can do nothing
+ #
+ # return values:
+ # 0 - source will NOT need to be built separately by caller
+ # +1 - source will need to be built separately by caller
+ # +2 - source will need to be built separately by caller AND
+ # dpkg-buildpackage should not in fact be run at all!
+ debugcmd '#massaging#', @$cmd if $debuglevel>1;
+#print STDERR "MASS0 ",Dumper($cmd, $xargs, $need_split_build_invocation);
+ if ($cleanmode eq 'dpkg-source' && !$need_split_build_invocation) {
$suppress_clean = 1;
- return;
+ return 0;
}
- 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, @$xargs);
- push @newcmd, @$cmd;
- @$cmd = @newcmd;
+ # later simply overriding earlie. So we need to:
+ # - search the command line for these options
+ # - pick the last one
+ # - perhaps add our own as a default
+ # - perhaps adjust it to the corresponding non-source-building version
+ my $dmode = '-F';
+ foreach my $l ($cmd, $xargs) {
+ next unless $l;
+ @$l = grep { !(m/^-[SgGFABb]$/s and $dmode=$_) } @$l;
+ }
+ push @$cmd, '-nc';
+#print STDERR "MASS1 ",Dumper($cmd, $xargs, $dmode);
+ my $r = 0;
+ if ($need_split_build_invocation) {
+ $r = $dmode =~ m/[S]/ ? +2 :
+ $dmode =~ y/gGF/ABb/ ? +1 :
+ $dmode =~ m/[ABb]/ ? 0 :
+ die "$dmode ?";
+ }
+ push @$cmd, $dmode;
+#print STDERR "MASS2 ",Dumper($cmd, $xargs, $r);
+ return $r;
}
sub cmd_build {
my @dbp = (@dpkgbuildpackage, qw(-us -uc), changesopts_initial(), @ARGV);
- massage_dbp_args \@dbp;
- build_prep();
- push @dbp, changesopts_version();
- runcmd_ordryrun_local @dbp;
+ my $wantsrc = massage_dbp_args \@dbp;
+ if ($wantsrc > 0) {
+ build_source();
+ } else {
+ build_prep();
+ }
+ if ($wantsrc < 2) {
+ push @dbp, changesopts_version();
+ runcmd_ordryrun_local @dbp;
+ }
printdone "build successful\n";
}
sub cmd_gbp_build {
my @dbp = @dpkgbuildpackage;
- massage_dbp_args \@dbp, \@ARGV;
+
+ my $wantsrc = massage_dbp_args \@dbp, \@ARGV;
my @cmd;
if (length executable_on_path('git-buildpackage')) {
}
push @cmd, (qw(-us -uc --git-no-sign-tags), "--git-builder=@dbp");
- if ($cleanmode eq 'dpkg-source') {
- $suppress_clean = 1;
+ if ($wantsrc > 0) {
+ build_source();
} else {
- push @cmd, '--git-cleaner=true';
+ if (!$suppress_clean) {
+ push @cmd, '--git-cleaner=true';
+ }
+ build_prep();
}
- build_prep();
- unless (grep { m/^--git-debian-branch|^--git-ignore-branch/ } @ARGV) {
- canonicalise_suite();
- push @cmd, "--git-debian-branch=".lbranch();
+ if ($wantsrc < 2) {
+ unless (grep { m/^--git-debian-branch|^--git-ignore-branch/ } @ARGV) {
+ canonicalise_suite();
+ push @cmd, "--git-debian-branch=".lbranch();
+ }
+ push @cmd, changesopts();
+ runcmd_ordryrun_local @cmd, @ARGV;
}
- push @cmd, changesopts();
- runcmd_ordryrun_local @cmd, @ARGV;
printdone "build successful\n";
}
sub cmd_git_build { cmd_gbp_build(); } # compatibility with <= 1.0
$suppress_clean = 1;
}
build_prep();
- $sourcechanges = "${package}_".(stripepoch $version)."_source.changes";
+ $sourcechanges = changespat $version,'source';
+ if (act_local()) {
+ unlink "../$sourcechanges" or $!==ENOENT
+ or fail "remove $sourcechanges: $!";
+ }
$dscfn = dscfn($version);
if ($cleanmode eq 'dpkg-source') {
- runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S)),
- changesopts();
+ 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();
+ runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc -S -d),
+ changesopts();
} else {
my $pwd = must_getcwd();
my $leafdir = basename $pwd;
sub cmd_sbuild {
build_source();
+ my $pat = changespat $version;
+ if (!$rmchanges) {
+ my @unwanted = map { s#^\.\./##; $_; } glob "../$pat";
+ @unwanted = grep { $_ ne changespat $version,'source' } @unwanted;
+ fail "changes files other than source matching $pat".
+ " already present (@unwanted);".
+ " building would result in ambiguity about the intended results"
+ if @unwanted;
+ }
changedir "..";
- my $pat = "${package}_".(stripepoch $version)."_*.changes";
if (act_local()) {
stat_exists $dscfn or fail "$dscfn (in parent directory): $!";
stat_exists $sourcechanges
or fail "$sourcechanges (in parent directory): $!";
- foreach my $cf (glob $pat) {
- next if $cf eq $sourcechanges;
- unlink $cf or fail "remove $cf: $!";
- }
}
- runcmd_ordryrun_local @sbuild, @ARGV, qw(-d), $isuite, $dscfn;
+ runcmd_ordryrun_local @sbuild, qw(-d), $isuite, @ARGV, $dscfn;
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;
+ unless @changesfiles==2;
+ my $binchanges = parsecontrol($changesfiles[1], "binary changes file");
+ foreach my $l (split /\n/, getfield $binchanges, 'Files') {
+ fail "$l found in binaries changes file $binchanges"
+ if $l =~ m/\.dsc$/;
+ }
runcmd_ordryrun_local @mergechanges, @changesfiles;
- my $multichanges = "${package}_".(stripepoch $version)."_multi.changes";
+ my $multichanges = changespat $version,'multi';
if (act_local()) {
stat_exists $multichanges or fail "$multichanges: $!";
+ foreach my $cf (glob $pat) {
+ next if $cf eq $multichanges;
+ rename "$cf", "$cf.inmulti" or fail "$cf\{,.inmulti}: $!";
+ }
}
printdone "build successful, results in $multichanges\n" or die $!;
}
my $clogp = parsechangelog();
$version = getfield $clogp, 'Version';
$package = getfield $clogp, 'Source';
+ check_not_dirty();
+ clean_tree();
build_maybe_quilt_fixup();
}
} elsif (m/^--no-rm-on-error$/s) {
push @ropts, $_;
$rmonerror = 0;
+ } elsif (m/^--(no-)?rm-old-changes$/s) {
+ push @ropts, $_;
+ $rmchanges = !$1;
} elsif (m/^--deliberately-($deliberately_re)$/s) {
push @ropts, $_;
push @deliberatelies, $&;
+ } elsif (m/^--always-split-source-build$/s) {
+ # undocumented, for testing
+ push @ropts, $_;
+ $need_split_build_invocation = 1;
} elsif (m/^(--[-0-9a-z]+)(=|$)/ && ($oi = $valopts_long{$1})) {
$val = $2 ? $' : undef; #';
$valopt->($oi->{Long});
my $cmd = shift @ARGV;
$cmd =~ y/-/_/;
+if (!defined $rmchanges) {
+ local $access_forpush;
+ $rmchanges = access_cfg_bool(0, 'rm-old-changes');
+}
+
if (!defined $quilt_mode) {
local $access_forpush;
$quilt_mode = cfg('dgit.force.quilt-mode', 'RETURN-UNDEF')