chiark / gitweb /
dgit: Fix check for --include-dirty --quilt=<splitting>
[dgit.git] / dgit
diff --git a/dgit b/dgit
index db56b503b14c82e0af53c0051f9b7180c5a7badd..493828695680a3ee7f72f9c2660c83f257b0d751 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -178,6 +178,29 @@ our $supplementary_message = '';
 our $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 ($@, $?);
     return unless forkcheck_mainprocess();
@@ -4466,7 +4489,6 @@ END
     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');
@@ -4492,9 +4514,8 @@ END
 
     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);
@@ -4502,17 +4523,22 @@ END
  "--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) {
+       $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) {
@@ -4952,6 +4978,7 @@ sub prep_push () {
     parseopts();
     build_or_push_prep_early();
     pushing();
+    build_or_push_prep_modes();
     check_not_dirty();
     my $specsuite;
     if (@ARGV==0) {
@@ -5394,10 +5421,7 @@ sub quiltify_splitbrain ($$$$$$$) {
     local $ENV{GIT_AUTHOR_EMAIL} = $authline[1];
     local $ENV{GIT_AUTHOR_DATE} =  $authline[2];
 
-    die if $split_brain;
-    die unless $do_split_brain;
-    runcmd @git, qw(checkout -q -b dgit-view);
-    $split_brain = 1;
+    confess unless $do_split_brain;
 
     my $fulldiffhint = sub {
        my ($x,$y) = @_;
@@ -5785,50 +5809,47 @@ sub build_maybe_quilt_fixup () {
 
     check_for_vendor_patches();
 
-    $do_split_brain = 1 if quiltmode_splitbrain();
-
     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 $split_brain;
+       $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;
@@ -5847,12 +5868,18 @@ END
     }
 }
 
-sub unpack_playtree_mkwork ($) {
+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;
 }
 
@@ -5901,7 +5928,7 @@ sub quilt_fixup_singlepatch ($$$) {
     # necessary to build the source package.
 
     unpack_playtree_linkorigs($upstreamversion, sub { });
-    unpack_playtree_mkwork($headref);
+    unpack_playtree_need_cd_work($headref);
 
     rmtree("debian/patches");
 
@@ -5917,9 +5944,14 @@ sub quilt_fixup_singlepatch ($$$) {
     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 "$!";
@@ -5963,8 +5995,9 @@ END
 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';
 
@@ -5992,6 +6025,8 @@ sub quilt_check_splitbrain_cache ($$) {
     # 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_
@@ -6023,7 +6058,7 @@ sub quilt_check_splitbrain_cache ($$) {
        "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;
@@ -6040,7 +6075,7 @@ sub quilt_check_splitbrain_cache ($$) {
 }
 
 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;
@@ -6114,16 +6149,39 @@ sub quilt_fixup_multipatch ($$$) {
     # 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';
@@ -6142,7 +6200,7 @@ END
 
     changedir '..';
 
-    unpack_playtree_mkwork($headref);
+    unpack_playtree_need_cd_work($headref);
 
     my $mustdeletepc=0;
     if (stat_exists ".pc") {
@@ -6377,9 +6435,20 @@ sub build_or_push_prep_early () {
     $dscfn = dscfn($version);
 }
 
+sub build_or_push_prep_modes () {
+    my ($format,) = get_source_format();
+    printdebug "format $format\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();
 }
 
@@ -6714,7 +6783,7 @@ sub build_source {
         unless ($split_brain) {
             my $upstreamversion = upstreamversion $version;
             unpack_playtree_linkorigs($upstreamversion, sub { });
-            unpack_playtree_mkwork($headref);
+            unpack_playtree_need_cd_work($headref);
             changedir '..';
         }
     } else {
@@ -6880,7 +6949,6 @@ sub cmd_print_unapplied_treeish {
     prep_ud();
     changedir $playground;
     my $uv = upstreamversion $version;
-    quilt_make_fake_dsc($uv);
     my $u = quilt_fakedsc2unapplied($headref, $uv);
     print $u, "\n" or confess "$!";
 }
@@ -7512,9 +7580,6 @@ sub parseopts_late_defaults () {
        $$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');