chiark / gitweb /
Split brain: Provide --gbp= and --gbp:
[dgit.git] / dgit
diff --git a/dgit b/dgit
index 1477d1725ac6d3ed09384f2cd0b901173ad890ce..d9b3a0186e3ce9dc27fb90169891476c097ece9d 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -64,6 +64,7 @@ our $quilt_mode;
 our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|unapplied';
 our $we_are_responder;
 our $initiator_tempdir;
+our $patches_applied_dirtily = 00;
 
 our %format_ok = map { $_=>1 } ("1.0","3.0 (native)","3.0 (quilt)");
 
@@ -86,7 +87,7 @@ 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 (@gbp) = qw(gbp);
 our (@changesopts) = ('');
 
 our %opts_opt_map = ('dget' => \@dget, # accept for compatibility
@@ -101,6 +102,7 @@ our %opts_opt_map = ('dget' => \@dget, # accept for compatibility
                      'dpkg-source' => \@dpkgsource,
                      'dpkg-buildpackage' => \@dpkgbuildpackage,
                      'dpkg-genchanges' => \@dpkggenchanges,
+                     'gbp' => \@gbp,
                      'ch' => \@changesopts,
                      'mergechanges' => \@mergechanges);
 
@@ -1988,10 +1990,14 @@ END
 
     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();
     }
+
+    die 'xxx fast forward (should not depend on quilt mode, but will always be needed if we did $split_brain)' if $split_brain;
+
     check_not_dirty();
     changedir $ud;
     progress "checking that $dscfn corresponds to HEAD";
@@ -2574,14 +2580,24 @@ sub quiltify_splitbrain ($$$$$$) {
     local $ENV{GIT_COMMITTER_NAME} =  $authline[0];
     local $ENV{GIT_COMMITTER_EMAIL} = $authline[1];
     local $ENV{GIT_COMMITTER_DATE} =  $authline[2];
+       
     if ($quilt_mode =~ m/gbp|unapplied/ &&
-       ($diffbits->{O2A} & 01) && # some patches
-       !($diffbits->{H2O} & 01)) { # but HEAD is like orig
+       ($diffbits->{H2O} & 01)) {
+       my $msg =
+ "--quilt=$quilt_mode specified, implying patches-unapplied git tree\n".
+ " but git tree differs from orig in upstream files.";
+       if (!stat_exists "debian/patches") {
+           $msg .=
+ "\n ... debian/patches is missing; perhaps this is a patch queue branch?";
+       }  
+       fail $msg;
+    }
+    if ($quilt_mode =~ m/gbp|unapplied/ &&
+       ($diffbits->{O2A} & 01)) { # some patches
        quiltify_splitbrain_needed();
-       progress "creating patches-applied version using gbp-pq";
-       open STDOUT, ">/dev/null" or die $!;
-       runcmd shell_cmd 'exec >/dev/null', @gbppq, qw(import);
-       # gbp-pq import creates a fresh branch; push back to dgit-view
+       progress "creating patches-applied version using gbp pq";
+       runcmd shell_cmd 'exec >/dev/null', @gbp, qw(pq import);
+       # gbp pq import creates a fresh branch; push back to dgit-view
        runcmd @git, qw(update-ref refs/heads/dgit-view HEAD);
        runcmd @git, qw(checkout -q dgit-view);
     }
@@ -2628,7 +2644,8 @@ END
     runcmd @git, qw(update-ref -m), $cachekey, "refs/$splitbraincache",
        $dgitview;
 
-    die 'xxx fast forward (should not depend on quilt mode, but will always be needed if we did $split_brain)';
+    progress "created dgit view (commit id $dgitview)";
+
     changedir '.git/dgit/unpack/work';
 }
 
@@ -2865,6 +2882,8 @@ sub build_maybe_quilt_fixup () {
        quilt_fixup_multipatch($clogp, $headref, $upstreamversion);
     }
 
+    die 'bug' if $split_brain && !$need_split_build_invocation;
+
     changedir '../../../..';
     runcmd_ordryrun_local
         @git, qw(pull --ff-only -q .git/dgit/unpack/work master);
@@ -3047,6 +3066,7 @@ END
        # we look for an entry whose message is the key for the cache lookup
        my @cachekey = (qw(dgit), $our_version);
        push @cachekey, $upstreamversion;
+       push @cachekey, $quilt_mode;
        push @cachekey, $headref;
 
        push @cachekey, hashfile('fake.dsc');
@@ -3218,15 +3238,44 @@ sub quilt_fixup_editor () {
     exit 0;
 }
 
+sub maybe_apply_patches_dirtily () {
+    return unless $quilt_mode =~ m/gbp|unapplied/;
+    print STDERR <<END or die $!;
+
+dgit: Building, or cleaning with rules target, in patches-unapplied tree.
+dgit: Have to apply the patches - making the tree dirty.
+dgit: (Consider specifying --clean=git and (or) using dgit sbuild.)
+
+END
+    $patches_applied_dirtily = 01;
+    $patches_applied_dirtily |= 02 unless stat_exists '.pc';
+    runcmd qw(dpkg-source --before-build .);
+}
+
+sub maybe_unapply_patches_again () {
+    progress "dgit: Unapplying patches again to tidy up the tree."
+       if $patches_applied_dirtily;
+    runcmd qw(dpkg-source --after-build .)
+       if $patches_applied_dirtily & 01;
+    rmtree '.pc'
+       if $patches_applied_dirtily & 02;
+}
+
 #----- other building -----
 
-our $suppress_clean;
+our $clean_using_builder;
+# ^ tree is to be cleaned by dpkg-source's builtin idea that it should
+#   clean the tree before building (perhaps invoked indirectly by
+#   whatever we are using to run the build), rather than separately
+#   and explicitly by us.
 
 sub clean_tree () {
-    return if $suppress_clean;
+    return if $clean_using_builder;
     if ($cleanmode eq 'dpkg-source') {
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean);
     } elsif ($cleanmode eq 'dpkg-source-d') {
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @dpkgbuildpackage, qw(-d -T clean);
     } elsif ($cleanmode eq 'git') {
        runcmd_ordryrun_local @git, qw(clean -xdf);
@@ -3248,6 +3297,7 @@ sub cmd_clean () {
     badusage "clean takes no additional arguments" if @ARGV;
     notpushing();
     clean_tree();
+    maybe_unapply_patches_again();
 }
 
 sub build_prep () {
@@ -3328,7 +3378,7 @@ sub massage_dbp_args ($;$) {
     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;
+       $clean_using_builder = 1;
        return 0;
     }
     # -nc has the side effect of specifying -b if nothing else specified
@@ -3347,11 +3397,13 @@ sub massage_dbp_args ($;$) {
 #print STDERR "MASS1 ",Dumper($cmd, $xargs, $dmode);
     my $r = 0;
     if ($need_split_build_invocation) {
+       printdebug "massage split $dmode.\n";
        $r = $dmode =~ m/[S]/     ? +2 :
             $dmode =~ y/gGF/ABb/ ? +1 :
             $dmode =~ m/[ABb]/   ?  0 :
             die "$dmode ?";
     }
+    printdebug "massage done $r $dmode.\n";
     push @$cmd, $dmode;
 #print STDERR "MASS2 ",Dumper($cmd, $xargs, $r);
     return $r;
@@ -3367,8 +3419,10 @@ sub cmd_build {
     }
     if ($wantsrc < 2) {
        push @dbp, changesopts_version();
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @dbp;
     }
+    maybe_unapply_patches_again();
     printdone "build successful\n";
 }
 
@@ -3388,7 +3442,7 @@ sub cmd_gbp_build {
     if ($wantsrc > 0) {
        build_source();
     } else {
-       if (!$suppress_clean) {
+       if (!$clean_using_builder) {
            push @cmd, '--git-cleaner=true';
        }
        build_prep();
@@ -3399,16 +3453,27 @@ sub cmd_gbp_build {
            push @cmd, "--git-debian-branch=".lbranch();
        }
        push @cmd, changesopts();
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @cmd, @ARGV;
     }
+    maybe_unapply_patches_again();
     printdone "build successful\n";
 }
 sub cmd_git_build { cmd_gbp_build(); } # compatibility with <= 1.0
 
 sub build_source {
-    if ($cleanmode =~ m/^dpkg-source/) {
-       # dpkg-source will clean, so we shouldn't
-       $suppress_clean = 1;
+    my $our_cleanmode = $cleanmode;
+    if ($need_split_build_invocation) {
+       # Pretend that clean is being done some other way.  This
+       # forces us not to try to use dpkg-buildpackage to clean and
+       # build source all in one go; and instead we run dpkg-source
+       # (and build_prep() will do the clean since $clean_using_builder
+       # is false).
+       $our_cleanmode = 'ELSEWHERE';
+    }
+    if ($our_cleanmode =~ m/^dpkg-source/) {
+       # dpkg-source invocation (below) will clean, so build_prep shouldn't
+       $clean_using_builder = 1;
     }
     build_prep();
     $sourcechanges = changespat $version,'source';
@@ -3417,18 +3482,38 @@ sub build_source {
            or fail "remove $sourcechanges: $!";
     }
     $dscfn = dscfn($version);
-    if ($cleanmode eq 'dpkg-source') {
+    if ($our_cleanmode eq 'dpkg-source') {
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc -S),
-                              changesopts();
-    } elsif ($cleanmode eq 'dpkg-source-d') {
+           changesopts();
+    } elsif ($our_cleanmode eq 'dpkg-source-d') {
+       maybe_apply_patches_dirtily();
        runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc -S -d),
-                              changesopts();
+           changesopts();
     } else {
-       my $pwd = must_getcwd();
-       my $leafdir = basename $pwd;
-       changedir "..";
-       runcmd_ordryrun_local @dpkgsource, qw(-b --), $leafdir;
-       changedir $pwd;
+       my @cmd = (@dpkgsource, qw(-b --));
+       if ($split_brain) {
+           changedir $ud;
+           runcmd_ordryrun_local @cmd, "work";
+           my @udfiles = <${package}_*>;
+           changedir "../../..";
+           foreach my $f (@udfiles) {
+               printdebug "source copy, found $f\n";
+               next unless
+                   $f eq $dscfn or
+                   ($f =~ m/\.debian\.tar(?:\.\w+)$/ &&
+                    $f eq srcfn($version, $&));
+               printdebug "source copy, found $f - renaming\n";
+               rename "$ud/$f", "../$f" or $!==ENOENT
+                   or fail "put in place new source file ($f): $!";
+           }
+       } else {
+           my $pwd = must_getcwd();
+           my $leafdir = basename $pwd;
+           changedir "..";
+           runcmd_ordryrun_local @cmd, $leafdir;
+           changedir $pwd;
+       }
        runcmd_ordryrun_local qw(sh -ec),
            'exec >$1; shift; exec "$@"','x',
            "../$sourcechanges",
@@ -3439,6 +3524,7 @@ sub build_source {
 sub cmd_build_source {
     badusage "build-source takes no additional arguments" if @ARGV;
     build_source();
+    maybe_unapply_patches_again();
     printdone "source built, results in $dscfn and $sourcechanges";
 }
 
@@ -3481,6 +3567,7 @@ sub cmd_sbuild {
            rename "$cf", "$cf.inmulti" or fail "$cf\{,.inmulti}: $!";
        }
     }
+    maybe_unapply_patches_again();
     printdone "build successful, results in $multichanges\n" or die $!;
 }    
 
@@ -3769,6 +3856,8 @@ if (!defined $quilt_mode) {
     $quilt_mode = $1;
 }
 
+$need_split_build_invocation ||= quiltmode_splitbrain();
+
 if (!defined $cleanmode) {
     local $access_forpush;
     $cleanmode = access_cfg('clean-mode', 'RETURN-UNDEF');