chiark / gitweb /
Merge branch 'stable'
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 9 Jul 2017 15:29:38 +0000 (16:29 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 9 Jul 2017 15:29:38 +0000 (16:29 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Debian/Dgit.pm
debian/changelog
dgit
dgit-badcommit-fixup
infra/dgit-repos-server
tests/lib-core
tests/tests/badcommit-rewrite
tests/tests/multisuite
tests/tests/quilt

index ba1c288..dcecbd1 100644 (file)
@@ -50,7 +50,7 @@ BEGIN {
                      git_get_ref git_for_each_ref
                       git_for_each_tag_referring is_fast_fwd
                       $package_re $component_re $deliberately_re
-                     $distro_re $versiontag_re
+                     $distro_re $versiontag_re $series_filename_re
                       $branchprefix
                       initdebug enabledebug enabledebuglevel
                       printdebug debugcmd
@@ -69,6 +69,7 @@ our $deliberately_re = "(?:TEST-)?$package_re";
 our $distro_re = $component_re;
 our $versiontag_re = qr{[-+.\%_0-9a-zA-Z/]+};
 our $branchprefix = 'dgit';
+our $series_filename_re = qr{(?:^|\.)series(?!\n)$}s;
 
 # policy hook exit status bits
 # see dgit-repos-server head comment for documentation
index 9286859..1d57cfa 100644 (file)
@@ -12,6 +12,43 @@ dgit (4.0) experimental; urgency=low
 
  -- Ian Jackson <ijackson@chiark.greenend.org.uk>  Sun, 12 Feb 2017 22:22:31 +0000
 
+dgit (3.12~) unstable; urgency=medium
+
+  Important bugfixes to dgit:
+  * Pass --no-renames to git diff-tree -z, avoiding potential trouble.
+  * Defend against commit subject lines which would generate patches which
+    look like series files, etc.  Involves adding .patch to all generated
+    patch filenames.
+
+ --
+
+dgit (3.11) unstable; urgency=high
+
+  Important bugfixes to dgit:
+  * Fix rpush+buildinfo: Transfer buildinfos for signing.  Closes:#867693.
+  * Cope if the archive server sends an HTTP redirect,
+    by passing -L to curl.  Closes:#867185,#867309.
+  * Cope with newer git which hates --local outside a tree.  Closes:#865863.
+  * rpush: Honour local git config from build host working tree.
+  * Tolerate compressor terminating with SIGPIPE.  Closes:#857694.
+  * Honour more pre-tree git config options in our private trees sharing
+    the user's object store.  In particular, core.sharedRepository.
+    Prompted by #867603.
+  * Clone multisuite works even without --no-rm-on-error.  Closes:#867434.
+  * Work if "git init" does not create $GIT/info.  Closes:#858054.
+  * Actually understand foo,-security (!)  Closes:#867189.
+
+  Important bugfixes to other components:
+  * dgit-badcommit-fixup: Honour core.sharedRepository.   Closes:#867603.
+  * infrastructure: Cope with new git-receive-pack which has
+    quarantine feature: ie, work around #867702.
+
+  Test suite:
+  * Cope with git restricting ext:: protocols.
+  * multisuite: Test clone without --rm-on-error.
+
+ -- Ian Jackson <ijackson@chiark.greenend.org.uk>  Sat, 08 Jul 2017 22:40:15 +0100
+
 dgit (3.10) unstable; urgency=medium
 
   Bugfixes:
diff --git a/dgit b/dgit
index caa2d75..b8d6826 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -100,7 +100,7 @@ our $rewritemap = 'dgit-rewrite/map';
 
 our (@git) = qw(git);
 our (@dget) = qw(dget);
-our (@curl) = qw(curl);
+our (@curl) = (qw(curl --proto-redir), '-all,http,https', qw(-L));
 our (@dput) = qw(dput);
 our (@debsign) = qw(debsign);
 our (@gpg) = qw(gpg);
@@ -316,6 +316,9 @@ sub gbp_pq {
 #  > param tagformat old|new
 #  > param maint-view MAINT-VIEW-HEAD
 #
+#  > param buildinfo-filename P_V_X.buildinfo   # zero or more times
+#  > file buildinfo                             # for buildinfos to sign
+#
 #  > previously REFNAME=OBJNAME       # if --deliberately-not-fast-forward
 #                                     # goes into tag, for replay prevention
 #
@@ -332,6 +335,9 @@ sub gbp_pq {
 #  [etc]
 #  < data-block NBYTES    [transfer of signed changes]
 #  [etc]
+#  < data-block NBYTES    [transfer of each signed buildinfo
+#  [etc]                   same number and order as "file buildinfo"]
+#  ...
 #  < files-end
 #
 #  > complete
@@ -560,6 +566,9 @@ sub nextarg {
     return scalar shift @ARGV;
 }
 
+sub pre_help () {
+    no_local_git_cfg();
+}
 sub cmd_help () {
     print $helpmsg or die $!;
     exit 0;
@@ -698,6 +707,11 @@ sub cfg {
        "$us: distro or suite appears not to be (properly) supported";
 }
 
+sub no_local_git_cfg () {
+    # needs to be called from pre_*
+    @gitcfgsources = grep { $_ ne 'local' } @gitcfgsources;
+}
+
 sub access_basedistro__noalias () {
     if (defined $idistro) {
        return $idistro;
@@ -1699,7 +1713,10 @@ sub prep_ud (;$) {
 sub mktree_in_ud_here () {
     runcmd qw(git init -q);
     runcmd qw(git config gc.auto 0);
-    foreach my $copy (qw(user.email user.name user.useConfigOnly)) {
+    foreach my $copy (qw(user.email user.name user.useConfigOnly
+                         core.sharedRepository
+                         core.compression core.looseCompression
+                         core.bigFileThreshold core.fsyncObjectFiles)) {
        my $v = $gitcfgs{local}{$copy};
        next unless $v;
        runcmd qw(git config), $copy, $_ foreach @$v;
@@ -2167,7 +2184,7 @@ sub generate_commits_from_dsc () {
                if defined $compr_ext && !defined $cname;
            my $compr_proc =
                new Dpkg::Compression::Process compression => $cname;
-           my @compr_cmd = $compr_proc->get_uncompress_cmdline();
+           @compr_cmd = $compr_proc->get_uncompress_cmdline();
            my $compr_fh = new IO::Handle;
            my $compr_pid = open $compr_fh, "-|" // die $!;
            if (!$compr_pid) {
@@ -2194,7 +2211,7 @@ sub generate_commits_from_dsc () {
        !$? or failedcmd @tarcmd;
 
        close $input or
-           (@compr_cmd ? failedcmd @compr_cmd
+           (@compr_cmd ? ($?==SIGPIPE || failedcmd @compr_cmd)
             : die $!);
        # finally, we have the results in "tarball", but maybe
        # with the wrong permissions
@@ -2513,7 +2530,7 @@ sub complete_file_from_dsc ($$;$) {
        $fi->{Digester}->reset();
        $fi->{Digester}->addfile(*F);
        F->error and die $!;
-       my $got = $fi->{Digester}->hexdigest();
+       $got = $fi->{Digester}->hexdigest();
        return $got eq $fi->{Hash};
     };
 
@@ -3363,6 +3380,7 @@ END
        return;
     }
     my $af = ".git/info/attributes";
+    ensuredir '.git/info';
     open GAO, "> $af.new" or die $!;
     print GAO <<END or die $!;
 *      dgit-defuse-attrs
@@ -3481,6 +3499,7 @@ sub fork_for_multisuite ($) {
     $before_fetch_merge->();
 
     foreach my $tsuite (@suites[1..$#suites]) {
+       $tsuite =~ s/^-/$cbasesuite-/;
        my $csubsuite = multisuite_suite_child($tsuite, \@mergeinputs,
                                               sub {
             @end = ();
@@ -3595,6 +3614,9 @@ END
 }
 
 sub clone ($) {
+    # in multisuite, returns twice!
+    # once in parent after first suite fetched,
+    # and then again in child after everything is finished
     my ($dstdir) = @_;
     badusage "dry run makes no sense with clone" unless act_local();
 
@@ -3606,7 +3628,7 @@ sub clone ($) {
         printdebug "multi clone after fetch merge\n";
        clone_set_head();
        clone_finish($dstdir);
-       exit 0;
+       return;
     }
     printdebug "clone main body\n";
 
@@ -4297,6 +4319,14 @@ END
        responder_send_command("param maint-view $maintviewhead");
     }
 
+    # Perhaps send buildinfo(s) for signing
+    my $changes_files = getfield $changes, 'Files';
+    my @buildinfos = ($changes_files =~ m/ .* (\S+\.buildinfo)$/mg);
+    foreach my $bi (@buildinfos) {
+       responder_send_command("param buildinfo-filename $bi");
+       responder_send_file('buildinfo', "$buildproductsdir/$bi");
+    }
+
     if (deliberately_not_fast_forward) {
        git_for_each_ref(lrfetchrefs, sub {
            my ($objid,$objtype,$lrfetchrefname,$reftail) = @_;
@@ -4367,9 +4397,10 @@ If you need to change the package, you must use a new version number.
 END
     if ($we_are_responder) {
        my $dryrunsuffix = act_local() ? "" : ".tmp";
+       my @rfiles = ($dscpath, $changesfile);
+       push @rfiles, map { "$buildproductsdir/$_" } @buildinfos;
        responder_receive_files('signed-dsc-changes',
-                               "$dscpath$dryrunsuffix",
-                               "$changesfile$dryrunsuffix");
+                               map { "$_$dryrunsuffix" } @rfiles);
     } else {
        if (act_local()) {
            rename "$dscpath.tmp",$dscpath or die "$dscfn $!";
@@ -4395,6 +4426,9 @@ END
     responder_send_command("complete");
 }
 
+sub pre_clone () {
+    no_local_git_cfg();
+}
 sub cmd_clone {
     parseopts();
     my $dstdir;
@@ -4528,7 +4562,7 @@ sub cmd_push {
 
 #---------- remote commands' implementation ----------
 
-sub cmd_remote_push_build_host {
+sub pre_remote_push_build_host {
     my ($nrargs) = shift @ARGV;
     my (@rargs) = @ARGV[0..$nrargs-1];
     @ARGV = @ARGV[$nrargs..$#ARGV];
@@ -4558,11 +4592,14 @@ sub cmd_remote_push_build_host {
         " but invocation host has $vsnwant"
        unless defined $protovsn;
 
-    responder_send_command("dgit-remote-push-ready $protovsn");
     changedir $dir;
+}
+sub cmd_remote_push_build_host {
+    responder_send_command("dgit-remote-push-ready $protovsn");
     &cmd_push;
 }
 
+sub pre_remote_push_responder { pre_remote_push_build_host(); }
 sub cmd_remote_push_responder { cmd_remote_push_build_host(); }
 # ... for compatibility with proto vsn.1 dgit (just so that user gets
 #     a good error message)
@@ -4602,6 +4639,9 @@ sub i_method {
     { no strict qw(refs); &{"${base}_${selector}"}(@args); }
 }
 
+sub pre_rpush () {
+    no_local_git_cfg();
+}
 sub cmd_rpush {
     my $host = nextarg;
     my $dir;
@@ -4720,7 +4760,7 @@ sub i_resp_want ($) {
     print RI "files-end\n" or die $!;
 }
 
-our ($i_clogp, $i_version, $i_dscfn, $i_changesfn);
+our ($i_clogp, $i_version, $i_dscfn, $i_changesfn, @i_buildinfos);
 
 sub i_localname_parsed_changelog {
     return "remote-changelog.822";
@@ -4737,6 +4777,31 @@ sub i_localname_dsc {
 }
 sub i_file_dsc { }
 
+sub i_localname_buildinfo ($) {
+    my $bi = $i_param{'buildinfo-filename'};
+    defined $bi or badproto \*RO, "buildinfo before filename";
+    defined $i_changesfn or badproto \*RO, "buildinfo before changes";
+    $bi =~ m{^\Q$package\E_[!-.0-~]*\.buildinfo$}s
+       or badproto \*RO, "improper buildinfo filename";
+    return $&;
+}
+sub i_file_buildinfo {
+    my $bi = $i_param{'buildinfo-filename'};
+    my $bd = parsecontrol "$i_tmp/$bi", $bi;
+    my $ch = parsecontrol "$i_tmp/$i_changesfn", 'changes';
+    if (!forceing [qw(buildinfo-changes-mismatch)]) {
+       files_compare_inputs($bd, $ch);
+       (getfield $bd, $_) eq (getfield $ch, $_) or
+           fail "buildinfo mismatch $_"
+           foreach qw(Source Version);
+       !defined $bd->{$_} or
+           fail "buildinfo contains $_"
+           foreach qw(Changes Changed-by Distribution);
+    }
+    push @i_buildinfos, $bi;
+    delete $i_param{'buildinfo-filename'};
+}
+
 sub i_localname_changes {
     defined $i_dscfn or badproto \*RO, "dsc (before parsed-changelog)";
     $i_changesfn = $i_dscfn;
@@ -4778,7 +4843,7 @@ sub i_want_signed_tag {
 sub i_want_signed_dsc_changes {
     rename "$i_dscfn.tmp","$i_dscfn" or die "$i_dscfn $!";
     sign_changes $i_changesfn;
-    return ($i_dscfn, $i_changesfn);
+    return ($i_dscfn, $i_changesfn, @i_buildinfos);
 }
 
 #---------- building etc. ----------
@@ -4827,7 +4892,7 @@ sub quiltify_trees_differ ($$;$$$) {
     #  a list of unrepresentable changes (removals of upstream files
     #  (as messages)
     local $/=undef;
-    my @cmd = (@git, qw(diff-tree -z));
+    my @cmd = (@git, qw(diff-tree -z --no-renames));
     push @cmd, qw(--name-only) unless $unrepres;
     push @cmd, qw(-r) if $finegrained || $unrepres;
     push @cmd, $x, $y;
@@ -5210,6 +5275,7 @@ sub quiltify ($$$$) {
                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 "is series file\n" if m{$series_filename_re}o;
                die "too long" if length > 200;
            };
            return $_ unless $@;
@@ -5248,6 +5314,7 @@ sub quiltify ($$$$) {
            $patchname =~ y/-a-z0-9_.+=~//cd;
            $patchname =~ s/^\W/x-$&/;
            $patchname = substr($patchname,0,40);
+           $patchname .= ".patch";
        }
        if (!defined $patchdir) {
            $patchdir = '';
@@ -6333,6 +6400,9 @@ END
        "results are in in git ref $dstbranch";
 }
 
+sub pre_archive_api_query () {
+    no_local_git_cfg();
+}
 sub cmd_archive_api_query {
     badusage "need only 1 subpath argument" unless @ARGV==1;
     my ($subpath) = @ARGV;
@@ -6349,6 +6419,9 @@ sub repos_server_url () {
     my $url = access_giturl();
 }    
 
+sub pre_clone_dgit_repos_server () {
+    no_local_git_cfg();
+}
 sub cmd_clone_dgit_repos_server {
     badusage "need destination argument" unless @ARGV==1;
     my ($destdir) = @ARGV;
@@ -6358,6 +6431,9 @@ sub cmd_clone_dgit_repos_server {
     exec @cmd or fail "exec git clone: $!\n";
 }
 
+sub pre_print_dgit_repos_server_source_url () {
+    no_local_git_cfg();
+}
 sub cmd_print_dgit_repos_server_source_url {
     badusage "no arguments allowed to dgit print-dgit-repos-server-source-url"
        if @ARGV;
@@ -6739,7 +6815,6 @@ if ($ENV{$fakeeditorenv}) {
 
 parseopts();
 check_env_sanity();
-git_slurp_config();
 
 print STDERR "DRY RUN ONLY\n" if $dryrun_level > 1;
 print STDERR "DAMP RUN - WILL MAKE LOCAL (UNSIGNED) CHANGES\n"
@@ -6754,6 +6829,8 @@ $cmd =~ y/-/_/;
 my $pre_fn = ${*::}{"pre_$cmd"};
 $pre_fn->() if $pre_fn;
 
+git_slurp_config();
+
 my $fn = ${*::}{"cmd_$cmd"};
 $fn or badusage "unknown operation $cmd";
 $fn->();
index 8b202c0..3995ceb 100755 (executable)
@@ -59,6 +59,17 @@ my $bare = `git rev-parse --is-bare-repository`;
 die "$? $!" if $?;
 chomp $bare or die;
 
+our @configs;
+foreach my $k (qw(core.sharedRepository)) {
+    $?=0; $!=0; my $v = `set -x; git config --local $k`;
+    if (defined $v && $?==0 && chomp $v) {
+       push @configs, [ $k, $v ];
+    } elsif (defined $v && $?==256 && $v eq '') {
+    } else {
+       die "git-config --local $k => $v $? $! ?";
+    }
+}
+
 sub getobj ($$) {
     my ($obj, $type) = @_;
     print GCFI $obj, "\n" or die $!;
@@ -163,6 +174,9 @@ sub edit_rewrite_map ($) {
     runcmd qw(git config gc.auto 0);
     runcmd qw(rm -rf .git/objects);
     symlink "../../objects", ".git/objects" or die $!;
+    foreach my $c (@configs) {
+       runcmd qw(git config), $c->[0], $c->[1];
+    }
 
     my %map;
 
index 6131774..55dc81f 100755 (executable)
@@ -407,16 +407,21 @@ sub makeworkingclone () {
     rmtree "${workrepo}_fresh";
 }
 
+sub mkscript ($$) {
+    my ($path,$contents) = @_;
+    my $fh = new IO::File $path, O_WRONLY|O_CREAT|O_TRUNC, 0777
+       or die "$path: $!";
+    print $fh $contents or die "$path: $!";
+    close $fh or die "$path: $!";
+}
+
 sub setupstunthook () {
     my $prerecv = "$workrepo/hooks/pre-receive";
-    my $fh = new IO::File $prerecv, O_WRONLY|O_CREAT|O_TRUNC, 0777
-       or die "$prerecv: $!";
-    print $fh <<END or die "$prerecv: $!";
+    mkscript $prerecv, <<END;
 #!/bin/sh
 set -e
 exec $0 --pre-receive-hook $package
 END
-    close $fh or die "$prerecv: $!";
     $ENV{'DGIT_DRS_WORK'}= $workrepo;
     $ENV{'DGIT_DRS_DEST'}= $destrepo;
     printdebug " stunt hook set up $prerecv\n";
@@ -938,6 +943,17 @@ sub onwardpush () {
     my @cmdbase = (qw(git send-pack), $destrepo);
     push @cmdbase, qw(--force) if $policy & NOFFCHECK;
 
+    if ($ENV{GIT_QUARANTINE_PATH}) {
+       my $recv_wrapper = "$ENV{GIT_QUARANTINE_PATH}/dgit-recv-wrapper";
+       mkscript $recv_wrapper, <<'END';
+#!/bin/sh
+set -e
+unset GIT_QUARANTINE_PATH
+exec git receive-pack "$@"
+END
+       push @cmdbase, "--receive-pack=$recv_wrapper";
+    }
+
     my @cmd = @cmdbase;
     push @cmd, "$commit:refs/dgit/$suite",
               "$tagval:refs/tags/$tagname";
index 6cdffeb..d65a1ff 100644 (file)
@@ -24,6 +24,7 @@ t-set-using-tmp () {
        export GNUPGHOME=$tmp/nonexistent
        git config --global user.email 'dgit-test@debian.example.net'
        git config --global user.name 'dgit test git user'
+       git config --global protocol.ext.allow always
 }
 
 t-filter-out-git-hyphen-dir () {
index b7fc701..3e2f37e 100755 (executable)
@@ -5,7 +5,12 @@ set -e
 t-setup-import examplegit
 t-tstunt-parsechangelog
 
-cd example
+cd $tmp/git/$p.git
+git config core.sharedRepository true
+chmod -R g+w objects
+umask 022
+
+cd $tmp/example
 
 suite=stable
 
@@ -26,6 +31,9 @@ t-has-parent-or-is $rstable $badcommit
 fixup=${DGIT_BADCOMMIT_FIXUP-dgit-badcommit-fixup}
 
 cd $tmp/git/$p.git
+git gc --aggressive --prune=all
+rmdir objects/* ||:
+
 $fixup --real
 
 cd $tmp/$p
@@ -44,4 +52,11 @@ t-dgit fetch stable
 t-expect-fail "child $rstable lacks parent $badcommit" \
 t-has-parent-or-is $rstable $badcommit
 
+check_shared () {
+       find "$1" -perm -200 \! -perm -020 -ls |tee $tmp/badperm
+       test -f $tmp/badperm -a ! -s $tmp/badperm
+}
+
+check_shared $tmp/git/$p.git/objects
+
 t-ok
index d39475b..fe655d0 100755 (executable)
@@ -32,7 +32,7 @@ multi-good
 
 cd ..
 
-t-dgit clone --no-rm-on-error $p stable,unstable ./$p.clone
+t-dgit clone $p stable,unstable ./$p.clone
 
 cd $p.clone
 
index 1a921b3..f26f744 100755 (executable)
@@ -41,8 +41,8 @@ iteration
 
 diff <<END - debian/patches/series
 ups-topic/ups-yml
-spongiform-upstream-new-file-incl-change
-zorkmid-options-=-42
+spongiform-upstream-new-file-incl-change.patch
+zorkmid-options-=-42.patch
 END
 
 for f in `cat debian/patches/series`; do