chiark / gitweb /
More comprehensive workaround for `3.0 (quilt)'.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Aug 2013 16:47:07 +0000 (17:47 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 24 Aug 2013 16:47:07 +0000 (17:47 +0100)
debian/changelog
dgit
dgit.1

index a6e6f51ff6a2a6b6bb4815cf227b1bd486a2ea42..a0b54f9a44988c4289cfe1803573114518cf4ba2 100644 (file)
@@ -1,6 +1,7 @@
 dgit (0.9) unstable; urgency=low
 
   * New cleaning arrangements.
+  * More comprehensive workaround for `3.0 (quilt)'.
 
  --
 
diff --git a/dgit b/dgit
index b6e79e36bca1ca1b1cd1cd124c0593c626bd275e..df4ea91a0570c512a0f05ed6ddd3bd62aded6d57 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -757,24 +757,35 @@ sub check_not_dirty () {
     }
 }
 
-sub commit_quilty_patch ($) {
-    my ($vsn) = @_;
+sub commit_quilty_patch () {
     my $output = cmdoutput @git, qw(status --porcelain);
-    my %fixups = map {$_=>1}
-        (".pc/debian-changes-$vsn/","debian/patches/debian-changes-$vsn");
-    my @files;
+    my %adds;
+    my $bad=0;
     foreach my $l (split /\n/, $output) {
-       next unless $l =~ s/^\?\? //;
-       next unless $fixups{$l};
-       push @files, $l;
+       next unless $l =~ m/\S/;
+       if ($l =~ m{^\?\? (.pc|debian/patches)}) {
+           $adds{$1}++;
+       } else {
+           print STDERR "git status: $l\n";
+           $bad++;
+       }
     }
-    print DEBUG "checking for quilty\n", Dumper(\@files);
-    if (@files == 2) {
-       my $m = "Commit Debian 3.0 (quilt) metadata";
-       print "$m\n";
-       runcmd_ordryrun @git, qw(add), @files;
-       runcmd_ordryrun @git, qw(commit -m), $m;
+    fail "unexpected output from git status (is tree clean?)" if $bad;
+    if (!%adds) {
+       print "nothing quilty to commit, ok.\n";
+       return;
     }
+    runcmd_ordryrun @git, qw(add), sort keys %adds;
+    my $m = "Commit Debian 3.0 (quilt) metadata";
+    print "$m\n";
+    runcmd_ordryrun @git, qw(commit -m), $m;
+}
+
+sub madformat ($) {
+    my ($format) = @_;
+    return 0 unless $format eq '3.0 (quilt)';
+    print "Format \`$format', urgh\n";
+    return 1;
 }
 
 sub dopush () {
@@ -794,9 +805,8 @@ sub dopush () {
        fail "$dsc is for $dscpackage $dversion".
            " but debian/changelog is for $package $cversion";
     print DEBUG "format $format\n";
-    if ($format eq '3.0 (quilt)') {
-       print "Format \`$format', urgh\n";
-       commit_quilty_patch($dversion);
+    if (madformat($format)) {
+       commit_quilty_patch();
     }
     check_not_dirty();
     prep_ud();
@@ -960,6 +970,68 @@ sub cmd_push {
     dopush();
 }
 
+our $version;
+our $sourcechanges;
+our $dscfn;
+
+our $fakeeditorenv = 'DGIT_FAKE_EDITOR_QUILT';
+
+sub build_maybe_quilt_fixup () {
+    if (!open F, "debian/source/format") {
+       die $! unless $!==&ENOENT;
+       return;
+    }
+    $_ = <F>;
+    F->error and die $!;
+    chomp;
+    return unless madformat($_);
+    # sigh
+    my $headref = rev_parse('HEAD');
+    my $time = time;
+    my $patchname = "auto-$version-$headref-$time";
+    my $author = cmdoutput @git, qw(log -n1), '--pretty=format:%an <%ae>';
+    my $msg = cmdoutput @git, qw(log -n1), "--pretty=format:%s\n%b";
+    my $descfn = ".git/dgit/quilt-description.tmp";
+    open O, '>', $descfn or die "$descfn: $!";
+    $msg =~ s/\n/\n /g;
+    $msg =~ s/^\s+$/ ./mg;
+    print O <<END or die $!;
+Description: $msg
+ [generated from git commit $headref]
+Author: $author
+
+---
+
+END
+    close O or die $!;
+    {
+       local $ENV{'EDITOR'} = cmdoutput qw(realpath --), $0;
+       local $ENV{'VISUAL'} = $ENV{'EDITOR'};
+       local $ENV{$fakeeditorenv} = cmdoutput qw(realpath --), $descfn;
+       runcmd_ordryrun @dpkgsource, qw(--commit .), $patchname;
+    }
+    commit_quilty_patch();
+}
+
+sub quilt_fixup_editor () {
+    my $descfn = $ENV{$fakeeditorenv};
+    my $editing = $ARGV[$#ARGV];
+    open I1, '<', $descfn or die "$descfn: $!";
+    open I2, '<', $editing or die "$editing: $!";
+    unlink $editing or die "$editing: $!";
+    open O, '>', $editing or die "$editing: $!";
+    while (<I1>) { print O or die $!; } I1->error and die $!;
+    my $copying = 0;
+    while (<I2>) {
+       $copying ||= m/^\-\-\- /;
+       next unless $copying;
+       print O or die $!;
+    }
+    I2->error and die $!;
+    close O or die $1;
+    exit 0;
+}
+
 sub cmd_build {
     # we pass further options and args to git-buildpackage
     badusage "-p is not allowed with dgit build" if defined $package;
@@ -967,6 +1039,8 @@ sub cmd_build {
     my $clogp = parsechangelog();
     $isuite = getfield $clogp, 'Distribution';
     $package = getfield $clogp, 'Source';
+    $version = getfield $clogp, 'Version';
+    build_maybe_quilt_fixup();
     my @cmd =
        (qw(git-buildpackage -us -uc --git-no-sign-tags),
         "--git-builder=@dpkgbuildpackage");
@@ -979,19 +1053,16 @@ sub cmd_build {
     printdone "build successful\n";
 }
 
-our $version;
-our $sourcechanges;
-our $dscfn;
-
 sub build_source {
-    check_not_dirty();
     badusage "-p is not allowed with this action" if defined $package;
+    check_not_dirty();
     my $clogp = parsechangelog();
     $package = getfield $clogp, 'Source';
     my $isuite = getfield $clogp, 'Distribution';
     $version = getfield $clogp, 'Version';
     $sourcechanges = "${package}_${version}_source.changes";
     $dscfn = dscfn($version);
+    build_maybe_quilt_fixup();
     if ($cleanmode eq 'dpkg-source') {
        runcmd_ordryrun (@dpkgbuildpackage, qw(-us -uc -S)), changesopts();
     } else {
@@ -1041,9 +1112,10 @@ sub cmd_sbuild {
 }    
 
 sub cmd_quilt_fixup {
-    badusage "incorrect arguments to dgit quilt-fixup";
+    badusage "incorrect arguments to dgit quilt-fixup" if @ARGV;
     my $clogp = parsechangelog();
-    commit_quilty_patch((getfield $clogp, 'Version'));
+    $version = getfield $clogp, 'Version';
+    build_maybe_quilt_fixup();
 }
 
 sub parseopts () {
@@ -1115,6 +1187,10 @@ sub parseopts () {
     }
 }
 
+if ($ENV{$fakeeditorenv}) {
+    quilt_fixup_editor();
+}
+
 parseopts();
 print STDERR "DRY RUN ONLY\n" if $dryrun;
 if (!@ARGV) {
diff --git a/dgit.1 b/dgit.1
index 322bc3b0ab27862663bc302da08a52cae2d71206..1abb7ecdc11480d587611eafd5e5373e4bf4aac6 100644 (file)
--- a/dgit.1
+++ b/dgit.1
@@ -128,12 +128,6 @@ field, runs debsign to sign the upload (.dsc and .changes), pushes the
 signed tag, and finally uses dput to upload the .changes to the
 archive.
 
-For a format `3.0 (quilt)' source package, dgit push
-may also have to make a commit on your current branch to contain
-quilt metadata.  It will do this automatically if necessary.
-You can explicitly request that dgit do just this
-dgit quilt-fixup.
-
 dgit push always uses the package, suite and version specified in the
 debian/changelog and the .dsc, which must agree.
 
@@ -141,15 +135,12 @@ If dgit push fails while uploading, it is fine to simply retry the
 dput on the .changes file at your leisure.
 .TP
 .B dgit quilt-fixup
-Looks to see if there is quilt patch metadata left over by dpkg-source
--b, and if so makes a git commit of it.  This is normally done
-automatically by dgit push.  dgit quilt-fixup takes no additional
-arguments.  Note that it will only process a patch generated by
-dpkg-source for the most recent version (according to the
-debia/changelog).
-
-It is not normally necessary to run dgit quilt-fixup explicitly;
-where necessary it is done as part of dgit push.
+Looks to see if the tree is one which dpkg-source cannot properly
+represent.  If it isn't, dgit will fix it up for you (in quilt terms,
+by making a new debian/ patch containing your unquilty changes) and
+make a commit of the changes it has made.
+
+This is normally done automatically by dgit build and dgit push.
 .SH WORKFLOW - SIMPLE
 It is always possible with dgit to clone or fetch a package, make
 changes in git (using git-commit) on the suite branch
@@ -274,15 +265,34 @@ in git and a fast-forwarding release branch; or you could do your work
 directly in a merging way on the
 .BI dgit/ suite
 branches.  If you do this you should probably use a `1.0' format
-source package.  In the archive, the delta between upstream will be
-represented in the single Debian patch.
-
-Secondly, you can regard your quiltish patch stack in the archive as
-primary.  You will have to use other tools besides dgit to import and
-export this patch stack.  For `3.0 (quilt)' packages, dgit has to do
-more work to work around some braindamage in way dpkg-source handles
-changes made to this format.  See also the BUGS section.  We recommend
-against the use of `3.0 (quilt)'.
+source package if you can.  In the archive, the delta between upstream
+will be represented in the single Debian patch.
+
+Secondly, you can use `3.0 (quilt)', and regard your quiltish patch
+stack in the archive as primary.  You will have to use other tools
+besides dgit to import and export this patch stack.  But see below:
+.SH FORMAT 3.0 (QUILT)
+For a format `3.0 (quilt)' source package, dgit may have to make a
+commit on your current branch to contain metadata used by quilt and
+dpkg-source.
+
+This is because (i) the `3.0 (quilt)' source format cannot represent
+certain trees, and (ii) packing up a tree in `3.0 (quilt)' and then
+unpacking it does not always yield the same tree.  Instead,
+dpkg-source insists on the trees having extra quilty metadata and
+patch files in the debian/ and .pc/ directories, which dpkg-source
+sometimes modifies.
+
+dgit will automatically work around this braindamage for you when
+building and pushing.  The only thing you need to know is that dgit
+build, sbuild, etc., may make a new commit on your HEAD.  If you're
+not a quilt user this commit won't contain any changes to files you
+care about.
+
+You can explicitly request that dgit do just this fixup, by running
+dgit quilt-fixup.
+
+We recommend against the use of `3.0 (quilt)'.
 .SH OPTIONS
 .TP
 .BR --dry-run | -n
@@ -513,14 +523,10 @@ the .orig.tar.gz could be transported via the git repo as git tags.
 Doing this is made more complicated by the possibility of a `3.0
 (quilt)' package with multiple .orig tarballs.
 
-`3.0 (quilt)' packages have an additional difficulty: if these are
-edited in the most normal way, and then fed to dpkg-buildpackage,
-dpkg-source will add extra quilt patch metadata to the source tree
-during the source package build.  This extra metadata is then of
-course not included in the git history.  So dgit push needs to commit
-it for you, to make sure that the git history and archive contents are
-identical.  That this is necessary is a bug in the `3.0 (quilt)'
-format.
+dgit's build functions, and dgit push, should not make any changes to
+your current HEAD.  Sadly this is necessary for packages in the `3.0
+(quilt)' source format.  This is ultimately due to design problems in
+quilt and dpkg-source.
 
 There should be an option which arranges for the `3.0 (quilt)'
 autocommit to not appear on your HEAD, but instead only in the