autoflush STDOUT 1;
our $supplementary_message = '';
-our $split_brain = 0;
+our $made_split_brain = 0;
+our $do_split_brain = 0;
+
+# Interactions between quilt mode and split brain
+# (currently, split brain only implemented iff
+# madformat_wantfixup && quiltmode_splitbrain)
+#
+# source format sane `3.0 (quilt)'
+# madformat_wantfixup()
+#
+# quilt mode normal quiltmode
+# (eg linear) _splitbrain
+#
+# ------------ ------------------------------------------------
+#
+# no split no q cache no q cache forbidden,
+# brain PM on master q fixup on master prevented
+# !$do_split_brain PM on master
+#
+# split brain no q cache q fixup cached, to dgit view
+# PM in dgit view PM in dgit view
+#
+# PM = pseudomerge to make ff, due to overwrite (or split view)
+# "no q cache" = do not record in cache on build, do not check cache
+# `3.0 (quilt)' with --quilt=nocheck is treated as sane format
END {
local ($@, $?);
push_parse_dsc($dscpath, $dscfn, $cversion);
my $format = getfield $dsc, 'Format';
- printdebug "format $format\n";
my $symref = git_get_symref();
my $actualhead = git_rev_parse('HEAD');
if (madformat_wantfixup($format)) {
# user might have not used dgit build, so maybe do this now:
- if (quiltmode_splitbrain()) {
+ if ($do_split_brain) {
changedir $playground;
- quilt_make_fake_dsc($upstreamversion);
my $cachekey;
($dgithead, $cachekey) =
quilt_check_splitbrain_cache($actualhead, $upstreamversion);
"--quilt=%s but no cached dgit view:
perhaps HEAD changed since dgit build[-source] ?",
$quilt_mode;
- $split_brain = 1;
- $dgithead = splitbrain_pseudomerge($clogp,
- $actualhead, $dgithead,
- $archive_hash);
- $maintviewhead = $actualhead;
- changedir $maindir;
- prep_ud(); # so _only_subdir() works, below
- } else {
+ }
+ if (!$do_split_brain) {
+ # In split brain mode, do not attempt to incorporate dirty
+ # stuff from the user's working tree. That would be mad.
commit_quilty_patch();
}
}
+ if ($do_split_brain) {
+ $made_split_brain = 1;
+ $dgithead = splitbrain_pseudomerge($clogp,
+ $actualhead, $dgithead,
+ $archive_hash);
+ $maintviewhead = $actualhead;
+ changedir $maindir;
+ prep_ud(); # so _only_subdir() works, below
+ }
if (defined $overwrite_version && !defined $maintviewhead
&& $archive_hash) {
my $r = system @diffcmd;
if ($r) {
if ($r==256) {
- my $referent = $split_brain ? $dgithead : 'HEAD';
+ confess unless !!$made_split_brain == !!$do_split_brain;
+ my $referent = $made_split_brain ? $dgithead : 'HEAD';
my $diffs = cmdoutput @git, qw(diff --stat), $tree, $dgithead;
my @mode_changes;
parseopts();
build_or_push_prep_early();
pushing();
+ build_or_push_prep_modes();
check_not_dirty();
my $specsuite;
if (@ARGV==0) {
return $r;
}
-sub quiltify_splitbrain_needed () {
- if (!$split_brain) {
- runcmd @git, qw(checkout -q -b dgit-view);
- $split_brain = 1;
- }
-}
-
sub quiltify_splitbrain ($$$$$$$) {
my ($clogp, $unapplied, $headref, $oldtiptree, $diffbits,
$editedignores, $cachekey) = @_;
local $ENV{GIT_AUTHOR_EMAIL} = $authline[1];
local $ENV{GIT_AUTHOR_DATE} = $authline[2];
- quiltify_splitbrain_needed();
+ confess unless $do_split_brain;
my $fulldiffhint = sub {
my ($x,$y) = @_;
check_for_vendor_patches();
- if (quiltmode_splitbrain) {
- fail <<END unless access_cfg_tagformats_can_splitbrain;
-quilt mode $quilt_mode requires split view so server needs to support
- both "new" and "maint" tag formats, but config says it doesn't.
-END
- }
-
my $clogp = parsechangelog();
my $headref = git_rev_parse('HEAD');
my $symref = git_get_symref();
-
- if ($quilt_mode eq 'linear'
- && !$fopts->{'single-debian-patch'}
- && branch_is_gdr($headref)) {
- # This is much faster. It also makes patches that gdr
- # likes better for future updates without laundering.
- #
- # However, it can fail in some casses where we would
- # succeed: if there are existing patches, which correspond
- # to a prefix of the branch, but are not in gbp/gdr
- # format, gdr will fail (exiting status 7), but we might
- # be able to figure out where to start linearising. That
- # will be slower so hopefully there's not much to do.
- my @cmd = (@git_debrebase,
- qw(--noop-ok -funclean-mixed -funclean-ordering
- make-patches --quiet-would-amend));
- # We tolerate soe snags that gdr wouldn't, by default.
- if (act_local()) {
- debugcmd "+",@cmd;
- $!=0; $?=-1;
- failedcmd @cmd
- if system @cmd
- and not ($? == 7*256 or
- $? == -1 && $!==ENOENT);
- } else {
- dryrun_report @cmd;
- }
- $headref = git_rev_parse('HEAD');
- }
+ my $upstreamversion = upstreamversion $version;
prep_ud();
changedir $playground;
- my $upstreamversion = upstreamversion $version;
+ my $splitbrain_cachekey;
+
+ if ($do_split_brain) {
+ my $cachehit;
+ ($cachehit, $splitbrain_cachekey) =
+ quilt_check_splitbrain_cache($headref, $upstreamversion);
+ if ($cachehit) {
+ changedir $maindir;
+ return;
+ }
+ }
+
+ unpack_playtree_need_cd_work($headref);
+ if ($do_split_brain) {
+ runcmd @git, qw(checkout -q -b dgit-view);
+ # so long as work is not deleted, its current branch will
+ # remain dgit-view, rather than master, so subsequent calls to
+ # unpack_playtree_need_cd_work
+ # will DTRT, resetting dgit-view.
+ die if $made_split_brain;
+ $made_split_brain = 1;
+ }
+ chdir '..';
if ($fopts->{'single-debian-patch'}) {
+ fail f_
+ "quilt mode %s does not make sense (or is not supported) with single-debian-patch",
+ $quilt_mode
+ if quiltmode_splitbrain();
quilt_fixup_singlepatch($clogp, $headref, $upstreamversion);
} else {
- quilt_fixup_multipatch($clogp, $headref, $upstreamversion);
+ quilt_fixup_multipatch($clogp, $headref, $upstreamversion,
+ $splitbrain_cachekey);
}
changedir $maindir;
@git, qw(pull --ff-only -q), "$playground/work", qw(master);
}
-sub unpack_playtree_mkwork ($) {
+sub build_check_quilt_splitbrain () {
+ build_maybe_quilt_fixup();
+
+ if ($do_split_brain) {
+ fail <<END unless access_cfg_tagformats_can_splitbrain;
+quilt mode $quilt_mode requires split view so server needs to support
+ both "new" and "maint" tag formats, but config says it doesn't.
+END
+ }
+}
+
+sub unpack_playtree_need_cd_work ($) {
my ($headref) = @_;
- mkdir "work" or confess "$!";
- changedir "work";
- mktree_in_ud_here();
+ # prep_ud() must have been called already.
+ if (!chdir "work") {
+ # Check in the filesystem because sometimes we run prep_ud
+ # in between multiple calls to unpack_playtree_need_cd_work.
+ confess "$!" unless $!==ENOENT;
+ mkdir "work" or confess "$!";
+ changedir "work";
+ mktree_in_ud_here();
+ }
runcmd @git, qw(reset -q --hard), $headref;
}
# necessary to build the source package.
unpack_playtree_linkorigs($upstreamversion, sub { });
- unpack_playtree_mkwork($headref);
+ unpack_playtree_need_cd_work($headref);
rmtree("debian/patches");
commit_quilty_patch();
}
-sub quilt_make_fake_dsc ($) {
+sub quilt_need_fake_dsc ($) {
+ # cwd should be playground
my ($upstreamversion) = @_;
+ return if stat_exists "fake.dsc";
+ # ^ OK to test this as a sentinel because if we created it
+ # we must either have done the rest too, or crashed.
+
my $fakeversion="$upstreamversion-~~DGITFAKE";
my $fakedsc=new IO::File 'fake.dsc', '>' or confess "$!";
sub quilt_fakedsc2unapplied ($$) {
my ($headref, $upstreamversion) = @_;
# must be run in the playground
- # quilt_make_fake_dsc must have been called
+ # quilt_need_fake_dsc must have been called
+ quilt_need_fake_dsc($upstreamversion);
runcmd qw(sh -ec),
'exec dpkg-source --no-check --skip-patches -x fake.dsc >/dev/null';
# Computes the cache key and looks in the cache.
# Returns ($dgit_view_commitid, $cachekey) or (undef, $cachekey)
+ quilt_need_fake_dsc($upstreamversion);
+
my $splitbrain_cachekey;
progress f_
"refs/$splitbraincache", $splitbrain_cachekey;
if ($cachehit) {
- unpack_playtree_mkwork($headref);
+ unpack_playtree_need_cd_work($headref);
my $saved = maybe_split_brain_save $headref, $cachehit, "cache-hit";
if ($cachehit ne $headref) {
progress f_ "dgit view: found cached (%s)", $saved;
runcmd @git, qw(checkout -q -b dgit-view), $cachehit;
- $split_brain = 1;
+ $made_split_brain = 1;
return ($cachehit, $splitbrain_cachekey);
}
progress __ "dgit view: found cached, no changes required";
}
sub quilt_fixup_multipatch ($$$) {
- my ($clogp, $headref, $upstreamversion) = @_;
+ my ($clogp, $headref, $upstreamversion, $splitbrain_cachekey) = @_;
progress f_ "examining quilt state (multiple patches, %s mode)",
$quilt_mode;
# afterwards with dpkg-source --before-build. That lets us save a
# tree object corresponding to .origs.
- my $splitbrain_cachekey;
+ if ($quilt_mode eq 'linear'
+ && branch_is_gdr($headref)) {
+ # This is much faster. It also makes patches that gdr
+ # likes better for future updates without laundering.
+ #
+ # However, it can fail in some casses where we would
+ # succeed: if there are existing patches, which correspond
+ # to a prefix of the branch, but are not in gbp/gdr
+ # format, gdr will fail (exiting status 7), but we might
+ # be able to figure out where to start linearising. That
+ # will be slower so hopefully there's not much to do.
- quilt_make_fake_dsc($upstreamversion);
+ unpack_playtree_need_cd_work $headref;
- if (quiltmode_splitbrain()) {
- my $cachehit;
- ($cachehit, $splitbrain_cachekey) =
- quilt_check_splitbrain_cache($headref, $upstreamversion);
- return if $cachehit;
+ my @cmd = (@git_debrebase,
+ qw(--noop-ok -funclean-mixed -funclean-ordering
+ make-patches --quiet-would-amend));
+ # We tolerate soe snags that gdr wouldn't, by default.
+ if (act_local()) {
+ debugcmd "+",@cmd;
+ $!=0; $?=-1;
+ failedcmd @cmd
+ if system @cmd
+ and not ($? == 7*256 or
+ $? == -1 && $!==ENOENT);
+ } else {
+ dryrun_report @cmd;
+ }
+ $headref = git_rev_parse('HEAD');
+
+ chdir '..';
}
+
my $unapplied=quilt_fakedsc2unapplied($headref, $upstreamversion);
ensuredir '.pc';
changedir '..';
- unpack_playtree_mkwork($headref);
+ unpack_playtree_need_cd_work($headref);
my $mustdeletepc=0;
if (stat_exists ".pc") {
$dscfn = dscfn($version);
}
+sub build_or_push_prep_modes () {
+ my ($format,) = get_source_format();
+ printdebug "format $format, quilt mode $quilt_mode\n";
+ if (madformat_wantfixup($format) && quiltmode_splitbrain()) {
+ $do_split_brain = 1;
+ }
+ fail __ "dgit: --include-dirty is not supported in split view quilt mode"
+ if $do_split_brain && $includedirty;
+}
+
sub build_prep_early () {
build_or_push_prep_early();
notpushing();
+ build_or_push_prep_modes();
check_not_dirty();
}
# said -wc we should still do the check.
clean_tree_check();
}
- build_maybe_quilt_fixup();
+ build_check_quilt_splitbrain();
if ($rmchanges) {
my $pat = changespat $version;
foreach my $f (glob "$buildproductsdir/$pat") {
#
# Note that if we are building a source package in split brain
# mode we do not support including uncommitted changes, because
- # that makes quilt fixup too hard. I.e. ($split_brain && (dgit is
+ # that makes quilt fixup too hard. I.e. ($made_split_brain && (dgit is
# building a source package)) => !$includedirty
return !$includedirty;
}
# If we are in split brain, there is already a playtree with
# the thing we should package into a .dsc (thanks to quilt
# fixup). If not, make a playtree
- prep_ud() unless $split_brain;
+ confess unless !!$made_split_brain == !!$do_split_brain;
+ prep_ud() unless $made_split_brain;
changedir $playground;
- unless ($split_brain) {
+ unless ($made_split_brain) {
my $upstreamversion = upstreamversion $version;
unpack_playtree_linkorigs($upstreamversion, sub { });
- unpack_playtree_mkwork($headref);
+ unpack_playtree_need_cd_work($headref);
changedir '..';
}
} else {
"dgit push-source: --include-dirty/--ignore-dirty does not make".
"sense with push-source!"
if $includedirty;
- build_maybe_quilt_fixup();
+ build_check_quilt_splitbrain();
if ($changesfile) {
my $changes = parsecontrol("$buildproductsdir/$changesfile",
__ "source changes file");
prep_ud();
changedir $playground;
my $uv = upstreamversion $version;
- quilt_make_fake_dsc($uv);
my $u = quilt_fakedsc2unapplied($headref, $uv);
print $u, "\n" or confess "$!";
}
$$vr = $v;
}
- fail __ "dgit: --include-dirty is not supported in split view quilt mode"
- if $split_brain && $includedirty;
-
if (!defined $cleanmode) {
local $access_forpush;
$cleanmode = access_cfg('clean-mode-newer', 'RETURN-UNDEF');