X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=dgit;h=667919c4b38a9705581916ce48b49a00ff26f5e8;hp=5207e0b96780124fbb106843e51f0fd4b3fe1ba3;hb=2fe296ae59c5cde0420f58c8a958b2e72a8a3402;hpb=1d34fdab75a2cab04ee30c10f6bcd32f02620b17 diff --git a/dgit b/dgit index 5207e0b9..667919c4 100755 --- 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) { @@ -5790,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(); @@ -5886,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 < 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; @@ -6262,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}; @@ -6289,31 +6330,7 @@ sub finalise_opts_opts () { @$om[$insertpos..$#$om] ); } } -} - -if ($ENV{$fakeeditorenv}) { - git_slurp_config(); - quilt_fixup_editor(); -} -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" - if $dryrun_level == 1; -if (!@ARGV) { - print STDERR $helpmsg or die $!; - exit 8; -} -my $cmd = shift @ARGV; -$cmd =~ y/-/_/; - -my $pre_fn = ${*::}{"pre_$cmd"}; -$pre_fn->() if $pre_fn; - -sub parseopts_late_defaults () { if (!defined $rmchanges) { local $access_forpush; $rmchanges = access_cfg_bool(0, 'rm-old-changes'); @@ -6349,7 +6366,27 @@ sub parseopts_late_defaults () { } } -parseopts_late_defaults(); +if ($ENV{$fakeeditorenv}) { + git_slurp_config(); + quilt_fixup_editor(); +} + +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" + if $dryrun_level == 1; +if (!@ARGV) { + print STDERR $helpmsg or die $!; + exit 8; +} +my $cmd = shift @ARGV; +$cmd =~ y/-/_/; + +my $pre_fn = ${*::}{"pre_$cmd"}; +$pre_fn->() if $pre_fn; my $fn = ${*::}{"cmd_$cmd"}; $fn or badusage "unknown operation $cmd";