chiark / gitweb /
Change name of rewrite map ref (needs an extra / for git)
[dgit.git] / dgit
diff --git a/dgit b/dgit
index 4f54379ecdf3f0886d028ca8b0056b0935d1e9fb..555e1c00905f30f0da4c18f54ac40c39b8d59ae8 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -69,6 +69,8 @@ our $rmchanges;
 our $overwrite_version; # undef: not specified; '': check changelog
 our $quilt_mode;
 our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|dpm|unapplied';
+our $dodep14tag;
+our $dodep14tag_re = 'want|no|always';
 our $split_brain_save;
 our $we_are_responder;
 our $initiator_tempdir;
@@ -94,6 +96,7 @@ 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';
+our $rewritemap = 'dgit-rewrite/map';
 
 our (@git) = qw(git);
 our (@dget) = qw(dget);
@@ -171,8 +174,7 @@ sub debiantag ($$) {
 
 sub debiantag_maintview ($$) { 
     my ($v,$distro) = @_;
-    $v =~ y/~:/_%/;
-    return "$distro/$v";
+    return "$distro/".dep14_version_mangle $v;
 }
 
 sub madformat ($) { $_[0] eq '3.0 (quilt)' }
@@ -1520,6 +1522,15 @@ sub access_cfg_tagformats () {
     split /\,/, access_cfg('dgit-tag-format');
 }
 
+sub access_cfg_tagformats_can_splitbrain () {
+    my %y = map { $_ => 1 } access_cfg_tagformats;
+    foreach my $needtf (qw(new maint)) {
+       next if $y{$needtf};
+       return 0;
+    }
+    return 1;
+}
+
 sub need_tagformat ($$) {
     my ($fmt, $why) = @_;
     fail "need to use tag format $fmt ($why) but also need".
@@ -1698,7 +1709,8 @@ sub git_add_write_tree () {
     return git_write_tree();
 }
 
-sub remove_stray_gits () {
+sub remove_stray_gits ($) {
+    my ($what) = @_;
     my @gitscmd = qw(find -name .git -prune -print0);
     debugcmd "|",@gitscmd;
     open GITS, "-|", @gitscmd or die $!;
@@ -1706,7 +1718,7 @@ sub remove_stray_gits () {
        local $/="\0";
        while (<GITS>) {
            chomp or die;
-           print STDERR "$us: warning: removing from source package: ",
+           print STDERR "$us: warning: removing from $what: ",
                (messagequote $_), "\n";
            rmtree $_;
        }
@@ -1714,8 +1726,8 @@ sub remove_stray_gits () {
     $!=0; $?=0; close GITS or failedcmd @gitscmd;
 }
 
-sub mktree_in_ud_from_only_subdir (;$) {
-    my ($raw) = @_;
+sub mktree_in_ud_from_only_subdir ($;$) {
+    my ($what,$raw) = @_;
 
     # changes into the subdir
     my (@dirs) = <*/.>;
@@ -1724,7 +1736,7 @@ sub mktree_in_ud_from_only_subdir (;$) {
     my $dir = $1;
     changedir $dir;
 
-    remove_stray_gits();
+    remove_stray_gits($what);
     mktree_in_ud_here();
     if (!$raw) {
        my ($format, $fopts) = get_source_format();
@@ -1733,8 +1745,7 @@ sub mktree_in_ud_from_only_subdir (;$) {
        }
     }
 
-    runcmd @git, qw(add -Af);
-    my $tree=git_write_tree();
+    my $tree=git_add_write_tree();
     return ($tree,$dir);
 }
 
@@ -2151,7 +2162,7 @@ sub generate_commits_from_dsc () {
 
        runcmd qw(chmod -R +rwX _unpack-tar);
        changedir "_unpack-tar";
-       remove_stray_gits();
+       remove_stray_gits($f);
        mktree_in_ud_here();
        
        my ($tree) = git_add_write_tree();
@@ -2202,7 +2213,7 @@ sub generate_commits_from_dsc () {
     push @cmd, qw(-x --), $dscfn;
     runcmd @cmd;
 
-    my ($tree,$dir) = mktree_in_ud_from_only_subdir();
+    my ($tree,$dir) = mktree_in_ud_from_only_subdir("source package");
     if (madformat $dsc->{format}) { 
        check_for_vendor_patches();
     }
@@ -2212,8 +2223,7 @@ sub generate_commits_from_dsc () {
        my @pcmd = qw(dpkg-source --before-build .);
        runcmd shell_cmd 'exec >/dev/null', @pcmd;
        rmtree '.pc';
-       runcmd @git, qw(add -Af);
-       $dappliedtree = git_write_tree();
+       $dappliedtree = git_add_write_tree();
     }
 
     my @clogcmd = qw(dpkg-parsechangelog --format rfc822 --all);
@@ -2358,6 +2368,8 @@ END
        my $path = $ENV{PATH} or die;
 
        foreach my $use_absurd (qw(0 1)) {
+           runcmd @git, qw(checkout -q unpa);
+           runcmd @git, qw(update-ref -d refs/heads/patch-queue/unpa);
            local $ENV{PATH} = $path;
            if ($use_absurd) {
                chomp $@;
@@ -2374,11 +2386,12 @@ END
                die "only absurd git-apply!\n" if !$use_absurd
                    && forceing [qw(import-gitapply-absurd)];
 
-               local $ENV{PATH} = $path if $use_absurd;
+               local $ENV{DGIT_ABSURD_DEBUG} = $debuglevel if $use_absurd;
+               local $ENV{PATH} = $path                    if $use_absurd;
 
                my @showcmd = (gbp_pq, qw(import));
                my @realcmd = shell_cmd
-                   'exec >/dev/null 2>../../gbp-pq-output', @showcmd;
+                   'exec >/dev/null 2>>../../gbp-pq-output', @showcmd;
                debugcmd "+",@realcmd;
                if (system @realcmd) {
                    die +(shellquote @showcmd).
@@ -2501,6 +2514,7 @@ sub git_fetch_us () {
            \&debiantag_new, \&debiantag_maintview)
         : debiantags('*',access_nomdistro));
     push @specs, server_branch($csuite);
+    push @specs, $rewritemap;
     push @specs, qw(heads/*) if deliberately_not_fast_forward;
 
     # This is rather miserable:
@@ -2712,6 +2726,18 @@ sub fetch_from_archive () {
        progress "no version available from the archive";
     }
 
+    my $rewritemapdata = git_cat_file lrfetchrefs."/".$rewritemap.':map';
+    if (defined $rewritemapdata
+       && $rewritemapdata =~ m/^$dsc_hash(?:[ \t](\w+))/m) {
+       progress "server's git history rewrite map contains a relevant entry!";
+       $dsc_hash = $1;
+       if (defined $dsc_hash) {
+           progress "using rewritten git hash in place of .dsc value";
+       } else {
+           progress "server data says .dsc hash is to be disregarded";
+       }
+    }
+
     # If the archive's .dsc has a Dgit field, there are three
     # relevant git commitids we need to choose between and/or merge
     # together:
@@ -3262,7 +3288,7 @@ sub clone_finish ($) {
     runcmd qw(bash -ec), <<'END';
         set -o pipefail
         git ls-tree -r --name-only -z HEAD | \
-        xargs -0r touch -r . --
+        xargs -0r touch -h -r . --
 END
     printdone "ready for work in $dstdir";
 }
@@ -3526,7 +3552,7 @@ tree $tree
 parent $dgitview
 parent $archive_hash
 author $authline
-commiter $authline
+committer $authline
 
 $msg_msg
 
@@ -3667,7 +3693,21 @@ sub push_tagwants ($$$$) {
            TfSuffix => '-maintview',
             View => 'maint',
         };
-    }
+    } elsif ($dodep14tag eq 'no' ? 0
+            : $dodep14tag eq 'want' ? access_cfg_tagformats_can_splitbrain
+            : $dodep14tag eq 'always'
+            ? (access_cfg_tagformats_can_splitbrain or fail <<END)
+--dep14tag-always (or equivalent in config) means server must support
+ both "new" and "maint" tag formats, but config says it doesn't.
+END
+           : die "$dodep14tag ?") {
+       push @tagwants, {
+           TagFn => \&debiantag_maintview,
+           Objid => $dgithead,
+           TfSuffix => '-dgit',
+           View => 'dgit',
+        };
+    };
     foreach my $tw (@tagwants) {
        $tw->{Tag} = $tw->{TagFn}($cversion, access_nomdistro);
        $tw->{Tfn} = sub { $tfbase.$tw->{TfSuffix}.$_[0]; };
@@ -3814,7 +3854,7 @@ END
 
     my $dscpath = "$buildproductsdir/$dscfn";
     stat_exists $dscpath or
-       fail "looked for .dsc $dscfn, but $!;".
+       fail "looked for .dsc $dscpath, but $!;".
            " maybe you forgot to build";
 
     responder_send_file('dsc', $dscpath);
@@ -3881,7 +3921,7 @@ END
     progress "checking that $dscfn corresponds to HEAD";
     runcmd qw(dpkg-source -x --),
         $dscpath =~ m#^/# ? $dscpath : "../../../$dscpath";
-    my ($tree,$dir) = mktree_in_ud_from_only_subdir();
+    my ($tree,$dir) = mktree_in_ud_from_only_subdir("source package");
     check_for_vendor_patches() if madformat($dsc->{format});
     changedir '../../../..';
     my @diffcmd = (@git, qw(diff --quiet), $tree, $dgithead);
@@ -3997,8 +4037,12 @@ END
     runcmd_ordryrun @git, qw(update-ref -m), 'dgit push', lrref(), $dgithead;
 
     supplementary_message(<<'END');
-Push failed, after updating the remote git repository.
-If you want to try again, you must use a new version number.
+Push failed, while obtaining signatures on the .changes and .dsc.
+If it was just that the signature failed, you may try again by using
+debsign by hand to sign the changes
+   $changesfile
+and then dput to complete the upload.
+If you need to change the package, you must use a new version number.
 END
     if ($we_are_responder) {
        my $dryrunsuffix = act_local() ? "" : ".tmp";
@@ -4432,7 +4476,7 @@ END
        local $ENV{'EDITOR'} = cmdoutput qw(realpath --), $0;
        local $ENV{'VISUAL'} = $ENV{'EDITOR'};
        local $ENV{$fakeeditorenv} = cmdoutput qw(realpath --), $descfn;
-       runcmd @dpkgsource, qw(--commit .), $patchname;
+       runcmd @dpkgsource, qw(--commit --include-removal .), $patchname;
     }
 }
 
@@ -4467,17 +4511,21 @@ sub quiltify_trees_differ ($$;$$$) {
 
        if ($unrepres) {
            eval {
-               die "deleted\n" unless $newmode =~ m/[^0]/;
-               die "not a plain file\n" unless $newmode =~ m/^10\d{4}$/;
-               if ($oldmode =~ m/[^0]/) {
+               die "not a plain file\n"
+                   unless $newmode =~ m/^10\d{4}$/ ||
+                          $oldmode =~ m/^10\d{4}$/;
+               if ($oldmode =~ m/[^0]/ &&
+                   $newmode =~ m/[^0]/) {
                    die "mode changed\n" if $oldmode ne $newmode;
                } else {
-                   die "non-default mode\n" unless $newmode =~ m/^100644$/;
+                   die "non-default mode\n"
+                       unless $newmode =~ m/^100644$/ ||
+                              $oldmode =~ m/^100644$/;
                }
            };
            if ($@) {
                local $/="\n"; chomp $@;
-               push @$unrepres, [ $f, $@ ];
+               push @$unrepres, [ $f, "$@ ($oldmode->$newmode)" ];
            }
        }
 
@@ -4910,13 +4958,10 @@ sub build_maybe_quilt_fixup () {
     check_for_vendor_patches();
 
     if (quiltmode_splitbrain) {
-       foreach my $needtf (qw(new maint)) {
-           next if grep { $_ eq $needtf } access_cfg_tagformats;
-           fail <<END
+       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();
@@ -5205,7 +5250,7 @@ sub quilt_fixup_multipatch ($$$) {
 
     changedir 'fake';
 
-    remove_stray_gits();
+    remove_stray_gits("source package");
     mktree_in_ud_here();
 
     rmtree '.pc';
@@ -5899,7 +5944,7 @@ END
        $there .= "/$f";
        symlink $there, $here or fail "symlink $there to $here: $!";
        progress "made symlink $here -> $there";
-       print STDERR Dumper($fi);
+#      print STDERR Dumper($fi);
     }
     my @mergeinputs = generate_commits_from_dsc();
     die unless @mergeinputs == 1;
@@ -5913,10 +5958,14 @@ END
            progress "Import, merging.";
            my $tree = cmdoutput @git, qw(rev-parse), "$newhash:";
            my $version = getfield $dsc, 'Version';
+           my $clogp = commit_getclogp $newhash;
+           my $authline = clogp_authline $clogp;
            $newhash = make_commit_text <<END;
 tree $tree
 parent $newhash
 parent $oldhash
+author $authline
+committer $authline
 
 Merge $package ($version) import into $dstbranch
 END
@@ -6087,6 +6136,15 @@ sub parseopts () {
            } elsif (m/^--overwrite=(.+)$/s) {
                push @ropts, $_;
                $overwrite_version = $1;
+           } elsif (m/^--dep14tag$/s) {
+               push @ropts, $_;
+               $dodep14tag= 'want';
+           } elsif (m/^--no-dep14tag$/s) {
+               push @ropts, $_;
+               $dodep14tag= 'no';
+           } elsif (m/^--always-dep14tag$/s) {
+               push @ropts, $_;
+               $dodep14tag= 'always';
            } elsif (m/^--delayed=(\d+)$/s) {
                push @ropts, $_;
                push @dput, $_;
@@ -6271,6 +6329,14 @@ if (!defined $quilt_mode) {
     $quilt_mode = $1;
 }
 
+if (!defined $dodep14tag) {
+    local $access_forpush;
+    $dodep14tag = access_cfg('dep14tag', 'RETURN-UNDEF') // 'want';
+    $dodep14tag =~ m/^($dodep14tag_re)$/ 
+       or badcfg "unknown dep14tag setting \`$dodep14tag'";
+    $dodep14tag = $1;
+}
+
 $need_split_build_invocation ||= quiltmode_splitbrain();
 
 if (!defined $cleanmode) {