chiark / gitweb /
changelog: Fix location of a bugfix entry
[dgit.git] / dgit
diff --git a/dgit b/dgit
index b4b6d9c..150c115 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -77,6 +77,9 @@ our %format_ok = map { $_=>1 } ("1.0","3.0 (native)","3.0 (quilt)");
 
 our $suite_re = '[-+.0-9a-z]+';
 our $cleanmode_re = 'dpkg-source(?:-d)?|git|git-ff|check|none';
+our $orig_f_comp_re = 'orig(?:-[-0-9a-z]+)?';
+our $orig_f_sig_re = '\\.(?:asc|gpg|pgp)';
+our $orig_f_tail_re = "$orig_f_comp_re\\.tar(?:\\.\\w+)?(?:$orig_f_sig_re)?";
 
 our $git_authline_re = '^([^<>]+) \<(\S+)\> (\d+ [-+]\d+)$';
 our $splitbraincache = 'dgit-intern/quilt-cache';
@@ -94,7 +97,8 @@ 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 (@gbp) = qw(gbp);
+our (@gbp_build) = ('');
+our (@gbp_pq) = ('gbp pq');
 our (@changesopts) = ('');
 
 our %opts_opt_map = ('dget' => \@dget, # accept for compatibility
@@ -109,7 +113,8 @@ our %opts_opt_map = ('dget' => \@dget, # accept for compatibility
                      'dpkg-source' => \@dpkgsource,
                      'dpkg-buildpackage' => \@dpkgbuildpackage,
                      'dpkg-genchanges' => \@dpkggenchanges,
-                     'gbp' => \@gbp,
+                     'gbp-build' => \@gbp_build,
+                     'gbp-pq' => \@gbp_pq,
                      'ch' => \@changesopts,
                      'mergechanges' => \@mergechanges);
 
@@ -243,6 +248,17 @@ sub quiltmode_splitbrain () {
     $quilt_mode =~ m/gbp|dpm|unapplied/;
 }
 
+sub opts_opt_multi_cmd {
+    my @cmd;
+    push @cmd, split /\s+/, shift @_;
+    push @cmd, @_;
+    @cmd;
+}
+
+sub gbp_pq {
+    return opts_opt_multi_cmd @gbp_pq;
+}
+
 #---------- remote protocol support, common ----------
 
 # remote push initiator/responder protocol:
@@ -1434,14 +1450,14 @@ sub is_orig_file_in_dsc ($$) {
     return 0 if @$dsc_files_info <= 1;
     # One file means no origs, and the filename doesn't have a "what
     # part of dsc" component.  (Consider versions ending `.orig'.)
-    return 0 unless $f =~ m/\.orig(?:-\w+)?\.tar(?:\.\w+)?$/;
+    return 0 unless $f =~ m/\.$orig_f_tail_re$/o;
     return 1;
 }
 
 sub is_orig_file_of_vsn ($$) {
     my ($f, $upstreamvsn) = @_;
     my $base = srcfn $upstreamvsn, '';
-    return 0 unless $f =~ m/^\Q$base\E\.orig(?:-\w+)?\.tar(?:\.\w+)?$/;
+    return 0 unless $f =~ m/^\Q$base\E\.$orig_f_tail_re$/;
     return 1;
 }
 
@@ -1550,6 +1566,7 @@ sub check_for_vendor_patches () {
 
 sub generate_commits_from_dsc () {
     # See big comment in fetch_from_archive, below.
+    # See also README.dsc-import.
     prep_ud();
     changedir $ud;
 
@@ -1591,6 +1608,7 @@ sub generate_commits_from_dsc () {
        printdebug "import considering $f ";
        (printdebug "only one dfi\n"), next if @dfi == 1;
        (printdebug "not tar\n"), next unless $f =~ m/\.tar(\.\w+)?$/;
+       (printdebug "signature\n"), next if $f =~ m/$orig_f_sig_re$/o;
        my $compr_ext = $1;
 
        my ($orig_f_part) =
@@ -1707,8 +1725,11 @@ sub generate_commits_from_dsc () {
     my $clogp;
     my $r1clogp;
 
+    printdebug "import clog search...\n";
+
     for (;;) {
        my $stanzatext = do { local $/=""; <CLOGS>; };
+       printdebug "import clogp ".Dumper($stanzatext) if $debuglevel>1;
        last if !defined $stanzatext;
 
        my $desc = "package changelog, entry no.$.";
@@ -1716,6 +1737,8 @@ sub generate_commits_from_dsc () {
        my $thisstanza = parsecontrolfh $stanzafh, $desc, 1;
        $clogp //= $thisstanza;
 
+       printdebug "import clog $thisstanza->{version} $desc...\n";
+
        last if !$any_orig; # we don't need $r1clogp
 
        # We look for the first (most recent) changelog entry whose
@@ -1740,8 +1763,12 @@ sub generate_commits_from_dsc () {
        # versions were created in a non-monotic order rather than
        # that the changelog entries have been misordered.
 
+       printdebug "import clog $thisstanza->{version} vs $upstreamv...\n";
+
        last if version_compare($thisstanza->{version}, $upstreamv) < 0;
        $r1clogp = $thisstanza;
+
+       printdebug "import clog $r1clogp->{version} becomes r1\n";
     }
     die $! if CLOGS->error;
     close CLOGS or $?==(SIGPIPE<<8) or failedcmd @clogcmd;
@@ -1758,7 +1785,12 @@ sub generate_commits_from_dsc () {
        # Strictly, r1authline might now be wrong if it's going to be
        # unused because !$any_orig.  Whatever.
 
+       printdebug "import tartrees authline   $authline\n";
+       printdebug "import tartrees r1authline $r1authline\n";
+
        foreach my $tt (@tartrees) {
+           printdebug "import tartree $tt->{F} $tt->{Tree}\n";
+
            $tt->{Commit} = make_commit_text($tt->{Orig} ? <<END_O : <<END_T);
 tree $tt->{Tree}
 author $r1authline
@@ -1779,6 +1811,8 @@ END_T
        }
     }
 
+    printdebug "import main commit\n";
+
     open C, ">../commit.tmp" or die $!;
     print C <<END or die $!;
 tree $tree
@@ -1799,6 +1833,8 @@ END
     my $rawimport_hash = make_commit qw(../commit.tmp);
 
     if (madformat $dsc->{format}) {
+       printdebug "import apply patches...\n";
+
        # regularise the state of the working tree so that
        # the checkout of $rawimport_hash works nicely.
        my $dappliedcommit = make_commit_text(<<END);
@@ -1808,10 +1844,28 @@ committer $authline
 
 [dgit dummy commit]
 END
-       runcmd @git, qw(checkout -b dapplied), $dappliedcommit;
+       runcmd @git, qw(checkout -q -b dapplied), $dappliedcommit;
+
+       runcmd @git, qw(checkout -q -b unpa), $rawimport_hash;
+
+       # We need the answers to be reproducible
+       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];
+       local $ENV{GIT_AUTHOR_NAME} =  $authline[0];
+       local $ENV{GIT_AUTHOR_EMAIL} = $authline[1];
+       local $ENV{GIT_AUTHOR_DATE} =  $authline[2];
+
+       eval {
+           runcmd shell_cmd 'exec >/dev/null 2>../../gbp-pq-output',
+               gbp_pq, qw(import);
+       };
+       if ($@) {
+           { local $@; eval { runcmd qw(cat ../../gbp-pq-output); }; }
+           die $@;
+       }
 
-       runcmd @git, qw(checkout -b unpa), $rawimport_hash;
-       runcmd shell_cmd 'exec >/dev/null', @gbp, qw(pq import);
        my $gapplied = git_rev_parse('HEAD');
        my $gappliedtree = cmdoutput @git, qw(rev-parse HEAD:);
        $gappliedtree eq $dappliedtree or
@@ -2383,7 +2437,7 @@ END
     } else {
        $hash = $mergeinputs[0]{Commit};
     }
-    progress "fetch hash=$hash\n";
+    printdebug "fetch hash=$hash\n";
 
     my $chkff = sub {
        my ($lasth, $what) = @_;
@@ -2576,7 +2630,11 @@ sub commit_quilty_patch () {
     }
     my @adds = map { s/[][*?\\]/\\$&/g; $_; } sort keys %adds;
     runcmd_ordryrun_local @git, qw(add -f), @adds;
-    commit_admin "Commit Debian 3.0 (quilt) metadata";
+    commit_admin <<END
+Commit Debian 3.0 (quilt) metadata
+
+[dgit ($our_version) quilt-fixup]
+END
 }
 
 sub get_source_format () {
@@ -3583,13 +3641,10 @@ sub quiltify_dpkg_commit ($$$;$) {
     mkpath '.git/dgit';
     my $descfn = ".git/dgit/quilt-description.tmp";
     open O, '>', $descfn or die "$descfn: $!";
-    $msg =~ s/\s+$//g;
-    $msg =~ s/\n/\n /g;
-    $msg =~ s/^\s+$/ ./mg;
+    $msg =~ s/\n+/\n\n/;
     print O <<END or die $!;
-Description: $msg
-Author: $author
-$xinfo
+From: $author
+${xinfo}Subject: $msg
 ---
 
 END
@@ -3657,7 +3712,10 @@ sub quiltify_splitbrain ($$$$$$) {
     local $ENV{GIT_COMMITTER_NAME} =  $authline[0];
     local $ENV{GIT_COMMITTER_EMAIL} = $authline[1];
     local $ENV{GIT_COMMITTER_DATE} =  $authline[2];
-       
+    local $ENV{GIT_AUTHOR_NAME} =  $authline[0];
+    local $ENV{GIT_AUTHOR_EMAIL} = $authline[1];
+    local $ENV{GIT_AUTHOR_DATE} =  $authline[2];
+
     if ($quilt_mode =~ m/gbp|unapplied/ &&
        ($diffbits->{H2O} & 01)) {
        my $msg =
@@ -3680,7 +3738,7 @@ END
        ($diffbits->{O2A} & 01)) { # some patches
        quiltify_splitbrain_needed();
        progress "dgit view: creating patches-applied version using gbp pq";
-       runcmd shell_cmd 'exec >/dev/null', @gbp, qw(pq import);
+       runcmd shell_cmd 'exec >/dev/null', gbp_pq, qw(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);
@@ -3710,7 +3768,7 @@ The Debian packaging git branch contains these updates to the upstream
 .gitignore file(s).  This patch is autogenerated, to provide these
 updates to users of the official Debian archive view of the package.
 
-[dgit version $our_version]
+[dgit ($our_version) update-gitignore]
 ---
 END
         close GIPATCH or die "$gipatch: $!";
@@ -3724,7 +3782,11 @@ END
        print SERIES "auto-gitignore\n" or die $!;
        close SERIES or die  $!;
         runcmd @git, qw(add -- debian/patches/series), $gipatch;
-        commit_admin "Commit patch to update .gitignore";
+        commit_admin <<END
+Commit patch to update .gitignore
+
+[dgit ($our_version) update-gitignore-quilt-fixup]
+END
     }
 
     my $dgitview = git_rev_parse 'refs/heads/dgit-view';
@@ -3919,15 +3981,65 @@ sub quiltify ($$$$) {
        $commitdata =~ m/^author (.*) \d+ [-+0-9]+$/m or die "$cc ?";
        my $author = $1;
 
+       my $commitdate = cmdoutput
+           @git, qw(log -n1 --pretty=format:%aD), $cc;
+
        $msg =~ s/^(.*)\n*/$1\n/ or die "$cc $msg ?";
 
+       my $strip_nls = sub { $msg =~ s/\n+$//; $msg .= "\n"; };
+       $strip_nls->();
+
        my $title = $1;
-       my $patchname = $title;
-       $patchname =~ s/[.:]$//;
-       $patchname =~ y/ A-Z/-a-z/;
-       $patchname =~ y/-a-z0-9_.+=~//cd;
-       $patchname =~ s/^\W/x-$&/;
-       $patchname = substr($patchname,0,40);
+       my $patchname;
+       my $patchdir;
+
+       my $gbp_check_suitable = sub {
+           $_ = shift;
+           my ($what) = @_;
+
+           eval {
+               die "contains unexpected slashes\n" if m{//} || m{/$};
+               die "contains leading punctuation\n" if m{^\W} || m{/\W};
+               die "contains bad character(s)\n" if m{[^-a-z0-9_.+=~/]}i;
+               die "too long" if length > 200;
+           };
+           return $_ unless $@;
+           print STDERR "quiltifying commit $cc:".
+               " ignoring/dropping Gbp-Pq $what: $@";
+           return undef;
+       };
+
+       if ($msg =~ s/^ (?: gbp(?:-pq)? : \s* name \s+ |
+                          gbp-pq-name: \s* )
+                      (\S+) \s* \n //ixm) {
+           $patchname = $gbp_check_suitable->($1, 'Name');
+       }
+       if ($msg =~ s/^ (?: gbp(?:-pq)? : \s* topic \s+ |
+                          gbp-pq-topic: \s* )
+                      (\S+) \s* \n //ixm) {
+           $patchdir = $gbp_check_suitable->($1, 'Topic');
+       }
+
+       $strip_nls->();
+
+       if (!defined $patchname) {
+           $patchname = $title;
+           $patchname =~ s/[.:]$//;
+           $patchname =~ y/ A-Z/-a-z/;
+           $patchname =~ y/-a-z0-9_.+=~//cd;
+           $patchname =~ s/^\W/x-$&/;
+           $patchname = substr($patchname,0,40);
+       }
+       if (!defined $patchdir) {
+           $patchdir = '';
+       }
+       if (length $patchdir) {
+           $patchname = "$patchdir/$patchname";
+       }
+       if ($patchname =~ m{^(.*)/}) {
+           mkpath "debian/patches/$1";
+       }
+
        my $index;
        for ($index='';
             stat "debian/patches/$patchname$index";
@@ -3945,6 +4057,7 @@ sub quiltify ($$$$) {
        runcmd @git, qw(checkout -q), $target, qw(debian/changelog);
 
        quiltify_dpkg_commit "$patchname$index", $author, $msg,
+           "Date: $commitdate\n".
            "X-Dgit-Generated: $clogp->{Version} $cc\n";
 
        runcmd @git, qw(checkout -q), $cc, qw(debian/changelog);
@@ -4020,7 +4133,11 @@ sub quilt_fixup_linkorigs ($$) {
 
 sub quilt_fixup_delete_pc () {
     runcmd @git, qw(rm -rqf .pc);
-    commit_admin "Commit removal of .pc (quilt series tracking data)";
+    commit_admin <<END
+Commit removal of .pc (quilt series tracking data)
+
+[dgit ($our_version) upgrade quilt-remove-pc]
+END
 }
 
 sub quilt_fixup_singlepatch ($$$) {
@@ -4554,17 +4671,24 @@ sub cmd_build {
     printdone "build successful\n";
 }
 
+sub pre_gbp_build {
+    $quilt_mode //= 'gbp';
+}
+
 sub cmd_gbp_build {
     my @dbp = @dpkgbuildpackage;
 
     my $wantsrc = massage_dbp_args \@dbp, \@ARGV;
 
-    my @cmd;
-    if (length executable_on_path('git-buildpackage')) {
-       @cmd = qw(git-buildpackage);
-    } else {
-       @cmd = qw(gbp buildpackage);
+    if (!length $gbp_build[0]) {
+       if (length executable_on_path('git-buildpackage')) {
+           $gbp_build[0] = qw(git-buildpackage);
+       } else {
+           $gbp_build[0] = 'gbp buildpackage';
+       }
     }
+    my @cmd = opts_opt_multi_cmd @gbp_build;
+
     push @cmd, (qw(-us -uc --git-no-sign-tags), "--git-builder=@dbp");
 
     if ($wantsrc > 0) {
@@ -4981,6 +5105,9 @@ if (!@ARGV) {
 my $cmd = shift @ARGV;
 $cmd =~ y/-/_/;
 
+my $pre_fn = ${*::}{"pre_$cmd"};
+$pre_fn->() if $pre_fn;
+
 if (!defined $rmchanges) {
     local $access_forpush;
     $rmchanges = access_cfg_bool(0, 'rm-old-changes');