chiark / gitweb /
git fetching: Move lrfetch* down in the file
[dgit.git] / dgit
diff --git a/dgit b/dgit
index 7c282532b044daaf9afd64337c5fcb0418af2499..667919c4b38a9705581916ce48b49a00ff26f5e8 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -142,7 +142,7 @@ our %opts_cfg_insertpos = map {
     scalar @{ $opts_opt_map{$_} }
 } keys %opts_opt_map;
 
-sub finalise_opts_opts();
+sub parseopts_late_defaults();
 
 our $keyid;
 
@@ -185,30 +185,6 @@ sub lref () { return "refs/heads/".lbranch(); }
 sub lrref () { return "refs/remotes/$remotename/".server_branch($csuite); }
 sub rrref () { return server_ref($csuite); }
 
-sub lrfetchrefs () { return "refs/dgit-fetch/$csuite"; }
-sub lrfetchref () { return lrfetchrefs.'/'.server_branch($csuite); }
-
-# We fetch some parts of lrfetchrefs/*.  Ideally we delete these
-# locally fetched refs because they have unhelpful names and clutter
-# up gitk etc.  So we track whether we have "used up" head ref (ie,
-# whether we have made another local ref which refers to this object).
-#
-# (If we deleted them unconditionally, then we might end up
-# re-fetching the same git objects each time dgit fetch was run.)
-#
-# So, leach use of lrfetchrefs needs to be accompanied by arrangements
-# in git_fetch_us to fetch the refs in question, and possibly a call
-# to lrfetchref_used.
-
-our (%lrfetchrefs_f, %lrfetchrefs_d);
-# $lrfetchrefs_X{lrfetchrefs."/heads/whatever"} = $objid
-
-sub lrfetchref_used ($) {
-    my ($fullrefname) = @_;
-    my $objid = $lrfetchrefs_f{$fullrefname};
-    $lrfetchrefs_d{$fullrefname} = $objid if defined $objid;
-}
-
 sub stripepoch ($) {
     my ($vsn) = @_;
     $vsn =~ s/^\d+\://;
@@ -727,7 +703,10 @@ sub access_basedistro () {
 
 sub access_nomdistro () {
     my $base = access_basedistro();
-    return cfg("dgit-distro.$base.nominal-distro",'RETURN-UNDEF') // $base;
+    my $r = cfg("dgit-distro.$base.nominal-distro",'RETURN-UNDEF') // $base;
+    $r =~ m/^$distro_re$/ or badcfg
+ "bad syntax for (nominal) distro \`$r' (does not match /^$distro_re$/)";
+    return $r;
 }
 
 sub access_quirk () {
@@ -791,11 +770,11 @@ sub pushing () {
 Push failed, before we got started.
 You can retry the push, after fixing the problem, if you like.
 END
-    finalise_opts_opts();
+    parseopts_late_defaults();
 }
 
 sub notpushing () {
-    finalise_opts_opts();
+    parseopts_late_defaults();
 }
 
 sub supplementary_message ($) {
@@ -1680,6 +1659,7 @@ sub create_remote_git_repo () {
 }
 
 our ($dsc_hash,$lastpush_mergeinput);
+our ($dsc_distro, $dsc_hint_tag, $dsc_hint_url);
 
 our $ud = '.git/dgit/unpack';
 
@@ -2503,19 +2483,34 @@ sub ensure_we_have_orig () {
     }
 }
 
-sub git_fetch_us () {
-    # Want to fetch only what we are going to use, unless
-    # deliberately-not-ff, in which case we must fetch everything.
+#---------- git fetch ----------
 
-    my @specs = deliberately_not_fast_forward ? qw(tags/*) :
-       map { "tags/$_" }
-       (quiltmode_splitbrain
-        ? (map { $_->('*',access_nomdistro) }
-           \&debiantag_new, \&debiantag_maintview)
-        : debiantags('*',access_nomdistro));
-    push @specs, server_branch($csuite);
-    push @specs, $rewritemap;
-    push @specs, qw(heads/*) if deliberately_not_fast_forward;
+sub lrfetchrefs () { return "refs/dgit-fetch/$csuite"; }
+sub lrfetchref () { return lrfetchrefs.'/'.server_branch($csuite); }
+
+# We fetch some parts of lrfetchrefs/*.  Ideally we delete these
+# locally fetched refs because they have unhelpful names and clutter
+# up gitk etc.  So we track whether we have "used up" head ref (ie,
+# whether we have made another local ref which refers to this object).
+#
+# (If we deleted them unconditionally, then we might end up
+# re-fetching the same git objects each time dgit fetch was run.)
+#
+# So, leach use of lrfetchrefs needs to be accompanied by arrangements
+# in git_fetch_us to fetch the refs in question, and possibly a call
+# to lrfetchref_used.
+
+our (%lrfetchrefs_f, %lrfetchrefs_d);
+# $lrfetchrefs_X{lrfetchrefs."/heads/whatever"} = $objid
+
+sub lrfetchref_used ($) {
+    my ($fullrefname) = @_;
+    my $objid = $lrfetchrefs_f{$fullrefname};
+    $lrfetchrefs_d{$fullrefname} = $objid if defined $objid;
+}
+
+sub git_lrfetch_sane {
+    my (@specs) = @_;
 
     # This is rather miserable:
     # When git fetch --prune is passed a fetchspec ending with a *,
@@ -2646,6 +2641,23 @@ END
     }
     printdebug "git_fetch_us: git fetch --no-insane emulation complete\n",
        Dumper(\%lrfetchrefs_f);
+}
+
+sub git_fetch_us () {
+    # Want to fetch only what we are going to use, unless
+    # deliberately-not-ff, in which case we must fetch everything.
+
+    my @specs = deliberately_not_fast_forward ? qw(tags/*) :
+       map { "tags/$_" }
+       (quiltmode_splitbrain
+        ? (map { $_->('*',access_nomdistro) }
+           \&debiantag_new, \&debiantag_maintview)
+        : debiantags('*',access_nomdistro));
+    push @specs, server_branch($csuite);
+    push @specs, $rewritemap;
+    push @specs, qw(heads/*) if deliberately_not_fast_forward;
+
+    git_lrfetch_sane @specs;
 
     my %here;
     my @tagpats = debiantags('*',access_nomdistro);
@@ -2672,6 +2684,8 @@ END
     });
 }
 
+#---------- dsc and archive handling ----------
+
 sub mergeinfo_getclogp ($) {
     # Ensures thit $mi->{Clogp} exists and returns it
     my ($mi) = @_;
@@ -2700,6 +2714,49 @@ sub fetch_from_archive_record_2 ($) {
     }
 }
 
+sub parse_dsc_field ($$) {
+    my ($dsc, $what) = @_;
+    my $f;
+    foreach my $field (@ourdscfield) {
+       $f = $dsc->{$field};
+       last if defined $f;
+    }
+    if (!defined $f) {
+       progress "$what: NO git hash";
+    } elsif (($dsc_hash, $dsc_distro, $dsc_hint_tag, $dsc_hint_url)
+            = $f =~ m/^(\w+) ($distro_re) ($versiontag_re) (\S+)(?:\s|$)/) {
+       progress "$what: specified git info ($dsc_distro)";
+       $dsc_hint_tag = [ $dsc_hint_tag ];
+    } elsif ($f =~ m/^\w+\s*$/) {
+       $dsc_hash = $&;
+       $dsc_distro //= 'debian';
+       $dsc_hint_tag = [ debiantags +(getfield $dsc, 'Version'),
+                         $dsc_distro ];
+       progress "$what: specified git hash";
+    } else {
+       fail "$what: invalid Dgit info";
+    }
+}
+
+sub resolve_dsc_field_commit ($$) {
+    my ($already_distro, $already_mapref) = @_;
+
+    return unless defined $dsc_hash;
+
+    my $rewritemapdata = git_cat_file $already_mapref.':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";
+       }
+    }
+}
+
 sub fetch_from_archive () {
     ensure_setup_existing_tree();
 
@@ -2711,33 +2768,13 @@ sub fetch_from_archive () {
     get_archive_dsc();
 
     if ($dsc) {
-       foreach my $field (@ourdscfield) {
-           $dsc_hash = $dsc->{$field};
-           last if defined $dsc_hash;
-       }
-       if (defined $dsc_hash) {
-           $dsc_hash =~ m/\w+/ or fail "invalid hash in .dsc \`$dsc_hash'";
-           $dsc_hash = $&;
-           progress "last upload to archive specified git hash";
-       } else {
-           progress "last upload to archive has NO git hash";
-       }
+       parse_dsc_field($dsc, 'last upload to archive');
+       resolve_dsc_field_commit access_basedistro,
+           lrfetchrefs."/".$rewritemap
     } else {
        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:
@@ -3723,7 +3760,11 @@ sub push_mktags ($$ $$ $) {
 
     die unless $tagwants->[0]{View} eq 'dgit';
 
-    $dsc->{$ourdscfield[0]} = $tagwants->[0]{Objid};
+    my $declaredistro = access_nomdistro();
+    my $reader_giturl = do { local $access_forpush=0; access_giturl(); };
+    $dsc->{$ourdscfield[0]} = join " ",
+       $tagwants->[0]{Objid}, $declaredistro, $tagwants->[0]{Tag},
+       $reader_giturl;
     $dsc->save("$dscfn.tmp") or die $!;
 
     my $changes = parsecontrol($changesfile,$changesfilewhat);
@@ -3740,7 +3781,6 @@ sub push_mktags ($$ $$ $) {
     # to control the "tagger" (b) we can do remote signing
     my $authline = clogp_authline $clogp;
     my $delibs = join(" ", "",@deliberatelies);
-    my $declaredistro = access_nomdistro();
 
     my $mktag = sub {
        my ($tw) = @_;
@@ -4076,7 +4116,6 @@ END
 
 sub cmd_clone {
     parseopts();
-    notpushing();
     my $dstdir;
     badusage "-p is not allowed with clone; specify as argument instead"
        if defined $package;
@@ -4091,8 +4130,9 @@ sub cmd_clone {
     } else {
        badusage "incorrect arguments to dgit clone";
     }
-    $dstdir ||= "$package";
+    notpushing();
 
+    $dstdir ||= "$package";
     if (stat_exists $dstdir) {
        fail "$dstdir already exists";
     }
@@ -4131,7 +4171,6 @@ sub branchsuite () {
 }
 
 sub fetchpullargs () {
-    notpushing();
     if (!defined $package) {
        my $sourcep = parsecontrol('debian/control','debian/control');
        $package = getfield $sourcep, 'Source';
@@ -4147,6 +4186,7 @@ sub fetchpullargs () {
     } else {
        badusage "incorrect arguments to dgit fetch or dgit pull";
     }
+    notpushing();
 }
 
 sub cmd_fetch {
@@ -5637,6 +5677,7 @@ sub postbuild_mergechanges_vanilla ($) {
 }
 
 sub cmd_build {
+    build_prep_early();
     my @dbp = (@dpkgbuildpackage, qw(-us -uc), changesopts_initial(), @ARGV);
     my $wantsrc = massage_dbp_args \@dbp;
     if ($wantsrc > 0) {
@@ -5729,6 +5770,7 @@ sub cmd_gbp_build {
 sub cmd_git_build { cmd_gbp_build(); } # compatibility with <= 1.0
 
 sub build_source {
+    build_prep_early();
     my $our_cleanmode = $cleanmode;
     if ($need_split_build_invocation) {
        # Pretend that clean is being done some other way.  This
@@ -5789,6 +5831,7 @@ sub build_source {
 }
 
 sub cmd_build_source {
+    build_prep_early();
     badusage "build-source takes no additional arguments" if @ARGV;
     build_source();
     maybe_unapply_patches_again();
@@ -5817,10 +5860,7 @@ END
 
 sub cmd_quilt_fixup {
     badusage "incorrect arguments to dgit quilt-fixup" if @ARGV;
-    my $clogp = parsechangelog();
-    $version = getfield $clogp, 'Version';
-    $package = getfield $clogp, 'Source';
-    check_not_dirty();
+    build_prep_early();
     clean_tree();
     build_maybe_quilt_fixup();
 }
@@ -5888,31 +5928,30 @@ sub cmd_import_dsc {
 
     parse_dscdata();
 
-    my $dgit_commit = $dsc->{$ourdscfield[0]};
-    if (defined $dgit_commit
+    parse_dsc_field($dsc, "Dgit metadata in .dsc");
+
+    if (defined $dsc_hash
        && !forceing [qw(import-dsc-with-dgit-field)]) {
-       $dgit_commit =~ m/\w+/ or fail "invalid hash in .dsc";
-       $dgit_commit = $&;
        progress "dgit: import-dsc of .dsc with Dgit field, using git hash";
        my @cmd = (qw(sh -ec),
-                  "echo $dgit_commit | git cat-file --batch-check");
+                  "echo $dsc_hash | git cat-file --batch-check");
        my $objgot = cmdoutput @cmd;
        if ($objgot =~ m#^\w+ missing\b#) {
            fail <<END
-.dsc contains Dgit field referring to object $dgit_commit
+.dsc contains Dgit field referring to object $dsc_hash
 Your git tree does not have that object.  Try `git fetch' from a
 plausible server (browse.dgit.d.o? alioth?), and try the import-dsc again.
 END
        }
-       if ($oldhash && !is_fast_fwd $oldhash, $dgit_commit) {
+       if ($oldhash && !is_fast_fwd $oldhash, $dsc_hash) {
            if ($force > 0) {
                progress "Not fast forward, forced update.";
            } else {
-               fail "Not fast forward to $dgit_commit";
+               fail "Not fast forward to $dsc_hash";
            }
        }
        @cmd = (@git, qw(update-ref -m), "dgit import-dsc (Dgit): $info",
-               $dstbranch, $dgit_commit);
+               $dstbranch, $dsc_hash);
        runcmd @cmd;
        progress "dgit: import-dsc updated git ref $dstbranch";
        return 0;
@@ -6264,7 +6303,7 @@ END
 }
 
 
-sub finalise_opts_opts () {
+sub parseopts_late_defaults () {
     foreach my $k (keys %opts_opt_map) {
        my $om = $opts_opt_map{$k};
 
@@ -6291,6 +6330,40 @@ sub finalise_opts_opts () {
                     @$om[$insertpos..$#$om] );
        }
     }
+
+    if (!defined $rmchanges) {
+       local $access_forpush;
+       $rmchanges = access_cfg_bool(0, 'rm-old-changes');
+    }
+
+    if (!defined $quilt_mode) {
+       local $access_forpush;
+       $quilt_mode = cfg('dgit.force.quilt-mode', 'RETURN-UNDEF')
+           // access_cfg('quilt-mode', 'RETURN-UNDEF')
+           // 'linear';
+       $quilt_mode =~ m/^($quilt_modes_re)$/ 
+           or badcfg "unknown quilt-mode \`$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) {
+       local $access_forpush;
+       $cleanmode = access_cfg('clean-mode', 'RETURN-UNDEF');
+       $cleanmode //= 'dpkg-source';
+
+       badcfg "unknown clean-mode \`$cleanmode'" unless
+           $cleanmode =~ m/^($cleanmode_re)$(?!\n)/s;
+    }
 }
 
 if ($ENV{$fakeeditorenv}) {
@@ -6315,40 +6388,6 @@ $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');
-}
-
-if (!defined $quilt_mode) {
-    local $access_forpush;
-    $quilt_mode = cfg('dgit.force.quilt-mode', 'RETURN-UNDEF')
-       // access_cfg('quilt-mode', 'RETURN-UNDEF')
-       // 'linear';
-    $quilt_mode =~ m/^($quilt_modes_re)$/ 
-       or badcfg "unknown quilt-mode \`$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) {
-    local $access_forpush;
-    $cleanmode = access_cfg('clean-mode', 'RETURN-UNDEF');
-    $cleanmode //= 'dpkg-source';
-
-    badcfg "unknown clean-mode \`$cleanmode'" unless
-       $cleanmode =~ m/^($cleanmode_re)$(?!\n)/s;
-}
-
 my $fn = ${*::}{"cmd_$cmd"};
 $fn or badusage "unknown operation $cmd";
 $fn->();