X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=dgit;h=3a737d0b0bbd607dc002542fdd9f582bf14edfaa;hp=2cf78ec7274e39d8c8fada21f8b0155c5be827e5;hb=2a7411655b752fddfc8955f2967dbdc504d50451;hpb=0effa0aab06b3a56382729f79fbea79ae36531b8 diff --git a/dgit b/dgit index 2cf78ec7..3a737d0b 100755 --- a/dgit +++ b/dgit @@ -90,6 +90,7 @@ our $chase_dsc_distro=1; our %forceopts = map { $_=>0 } qw(unrepresentable unsupported-source-format dsc-changes-mismatch changes-origs-exactly + uploading-binaries uploading-source-only import-gitapply-absurd import-gitapply-no-absurd import-dsc-with-dgit-field); @@ -614,9 +615,11 @@ our %defcfg = ('dgit.default.distro' => 'debian', 'dgit.default.sshpsql-dbname' => 'service=projectb', 'dgit.default.aptget-components' => 'main', 'dgit.default.dgit-tag-format' => 'new,old,maint', + 'dgit.default.source-only-uploads' => 'ok', 'dgit.dsc-url-proto-ok.http' => 'true', 'dgit.dsc-url-proto-ok.https' => 'true', 'dgit.dsc-url-proto-ok.git' => 'true', + 'dgit.vcs-git.suites', => 'sid', # ;-separated 'dgit.default.dsc-url-proto-ok' => 'false', # old means "repo server accepts pushes with old dgit tags" # new means "repo server accepts pushes with new dgit tags" @@ -627,6 +630,7 @@ our %defcfg = ('dgit.default.distro' => 'debian', 'dgit-distro.debian.git-check' => 'url', 'dgit-distro.debian.git-check-suffix' => '/info/refs', 'dgit-distro.debian.new-private-pushers' => 't', + 'dgit-distro.debian.source-only-uploads' => 'not-wholly-new', 'dgit-distro.debian/push.git-url' => '', 'dgit-distro.debian/push.git-host' => 'push.dgit.debian.org', 'dgit-distro.debian/push.git-user-force' => 'dgit', @@ -1178,6 +1182,12 @@ sub file_in_archive_ftpmasterapi { my $info = api_query($data, "file_in_archive/$pat", 1); } +sub package_not_wholly_new_ftpmasterapi { + my ($proto,$data,$pkg) = @_; + my $info = api_query($data,"madison?package=${pkg}&f=json"); + return !!@$info; +} + #---------- `aptget' archive query method ---------- our $aptget_base; @@ -1341,34 +1351,55 @@ sub archive_query_aptget { } sub file_in_archive_aptget () { return undef; } +sub package_not_wholly_new_aptget () { return undef; } #---------- `dummyapicat' archive query method ---------- sub archive_query_dummycatapi { archive_query_ftpmasterapi @_; } sub canonicalise_suite_dummycatapi { canonicalise_suite_ftpmasterapi @_; } -sub file_in_archive_dummycatapi ($$$) { - my ($proto,$data,$filename) = @_; +sub dummycatapi_run_in_mirror ($@) { + # runs $fn with FIA open onto rune + my ($rune, $argl, $fn) = @_; + my $mirror = access_cfg('mirror'); $mirror =~ s#^file://#/# or die "$mirror ?"; - my @out; - my @cmd = (qw(sh -ec), ' - cd "$1" - find -name "$2" -print0 | - xargs -0r sha256sum - ', qw(x), $mirror, $filename); + my @cmd = (qw(sh -ec), 'cd "$1"; shift'."\n".$rune, + qw(x), $mirror, @$argl); debugcmd "-|", @cmd; open FIA, "-|", @cmd or die $!; - while () { - chomp or die; - printdebug "| $_\n"; - m/^(\w+) (\S+)$/ or die "$_ ?"; - push @out, { sha256sum => $1, filename => $2 }; - } - close FIA or die failedcmd @cmd; + my $r = $fn->(); + close FIA or ($!==0 && $?==141) or die failedcmd @cmd; + return $r; +} + +sub file_in_archive_dummycatapi ($$$) { + my ($proto,$data,$filename) = @_; + my @out; + dummycatapi_run_in_mirror ' + find -name "$1" -print0 | + xargs -0r sha256sum + ', [$filename], sub { + while () { + chomp or die; + printdebug "| $_\n"; + m/^(\w+) (\S+)$/ or die "$_ ?"; + push @out, { sha256sum => $1, filename => $2 }; + } + }; return \@out; } +sub package_not_wholly_new_dummycatapi { + my ($proto,$data,$pkg) = @_; + dummycatapi_run_in_mirror " + find -name ${pkg}_*.dsc + ", [], sub { + local $/ = undef; + !!; + }; +} + #---------- `madison' archive query method ---------- sub archive_query_madison { @@ -1419,6 +1450,7 @@ sub canonicalise_suite_madison { } sub file_in_archive_madison { return undef; } +sub package_not_wholly_new_madison { return undef; } #---------- `sshpsql' archive query method ---------- @@ -1496,6 +1528,7 @@ END } sub file_in_archive_sshpsql ($$$) { return undef; } +sub package_not_wholly_new_sshpsql ($$$) { return undef; } #---------- `dummycat' archive query method ---------- @@ -1540,6 +1573,7 @@ sub archive_query_dummycat ($$) { } sub file_in_archive_dummycat () { return undef; } +sub package_not_wholly_new_dummycat () { return undef; } #---------- tag format handling ---------- @@ -1974,12 +2008,12 @@ END if ($found_same) { # in archive, delete from .changes if it's there $changed{$file} = "removed" if - $changes->{$fname} =~ s/^.* \Q$file\E$(?:)\n//m; - } elsif ($changes->{$fname} =~ m/^.* \Q$file\E$(?:)\n/m) { + $changes->{$fname} =~ s/\n.* \Q$file\E$(?:)$//m; + } elsif ($changes->{$fname} =~ m/^.* \Q$file\E$(?:)$/m) { # not in archive, but it's here in the .changes } else { my $dsc_data = getfield $dsc, $fname; - $dsc_data =~ m/^(.* \Q$file\E$)\n/m or die "$dsc_data $file ?"; + $dsc_data =~ m/^(.* \Q$file\E$)$/m or die "$dsc_data $file ?"; my $extra = $1; $extra =~ s/ \d+ /$&$placementinfo / or die "$fname $extra >$dsc_data< ?" @@ -2757,6 +2791,11 @@ END my $want = $wantr{$rrefname}; next if $got eq $want; if (!defined $objgot{$want}) { + fail <{'Vcs-Git'}; + if (length $vcsgiturl and + (grep { $csuite eq $_ } + split /\;/, + cfg 'dgit.vcs-git.suites')) { + my $current = cfg 'remote.vcs-git.url', 'RETURN-UNDEF'; + if (defined $current && $current ne $vcsgiturl) { + print STDERR < message fragment "$saved" describing disposition of $dgitview return "commit id $dgitview" unless defined $split_brain_save; my @cmd = (shell_cmd 'cd "$1"; shift', $maindir, - @git, qw(update-ref -m), + git_update_ref_cmd "dgit --dgit-view-save $msg HEAD=$headref", $split_brain_save, $dgitview); runcmd @cmd; @@ -3994,10 +4050,12 @@ sub splitbrain_pseudomerge ($$$$) { infopair_cond_ff($i_dep14, [ $maintview, 'HEAD' ]); 1; }) { + $@ =~ s/^\n//; chomp $@; print STDERR <[0] into your HEAD."; return $r; @@ -4296,7 +4354,8 @@ END } } - if (defined $overwrite_version && !defined $maintviewhead) { + if (defined $overwrite_version && !defined $maintviewhead + && $archive_hash) { $dgithead = plain_overwrite_pseudomerge($clogp, $dgithead, $archive_hash); @@ -4392,6 +4451,29 @@ END files_compare_inputs($dsc, $changes) unless forceing [qw(dsc-changes-mismatch)]; + # Check whether this is a source only upload + my $hasdebs = $changes->{Files} =~ m{\.deb$}m; + my $sourceonlypolicy = access_cfg 'source-only-uploads'; + if ($sourceonlypolicy eq 'ok') { + } elsif ($sourceonlypolicy eq 'always') { + forceable_fail [qw(uploading-binaries)], + "uploading binaries, although distroy policy is source only" + if $hasdebs; + } elsif ($sourceonlypolicy eq 'never') { + forceable_fail [qw(uploading-source-only)], + "source-only upload, although distroy policy requires .debs" + if !$hasdebs; + } elsif ($sourceonlypolicy eq 'not-wholly-new') { + forceable_fail [qw(uploading-source-only)], + "source-only upload, even though package is entirely NEW\n". + "(this is contrary to policy in ".(access_nomdistro()).")" + if !$hasdebs + && $new_package + && !(archive_query('package_not_wholly_new', $package) // 1); + } else { + badcfg "unknown source-only-uploads policy \`$sourceonlypolicy'"; + } + # Perhaps adjust .dsc to contain right set of origs changes_update_origs_from_dsc($dsc, $changes, $upstreamversion, $changesfile) @@ -4475,7 +4557,7 @@ END runcmd_ordryrun @git, qw(-c push.followTags=false push), access_giturl(), @pushrefs; - runcmd_ordryrun @git, qw(update-ref -m), 'dgit push', lrref(), $dgithead; + runcmd_ordryrun git_update_ref_cmd 'dgit push', lrref(), $dgithead; supplementary_message(<<'END'); Push failed, while obtaining signatures on the .changes and .dsc. @@ -4575,11 +4657,15 @@ sub branchsuite () { } } -sub fetchpullargs () { +sub package_from_d_control () { if (!defined $package) { my $sourcep = parsecontrol('debian/control','debian/control'); $package = getfield $sourcep, 'Source'; } +} + +sub fetchpullargs () { + package_from_d_control(); if (@ARGV==0) { $isuite = branchsuite(); if (!$isuite) { @@ -4598,9 +4684,7 @@ sub fetchpullargs () { sub cmd_fetch { parseopts(); fetchpullargs(); - my $multi_fetched = fork_for_multisuite(sub { }); - finish 0 if $multi_fetched; - fetch(); + dofetch(); } sub cmd_pull { @@ -4615,6 +4699,86 @@ END pull(); } +sub cmd_checkout { + parseopts(); + package_from_d_control(); + @ARGV==1 or badusage "dgit checkout needs a suite argument"; + ($isuite) = @ARGV; + notpushing(); + + foreach my $canon (qw(0 1)) { + if (!$canon) { + $csuite= $isuite; + } else { + undef $csuite; + canonicalise_suite(); + } + if (length git_get_ref lref()) { + # local branch already exists, yay + last; + } + if (!length git_get_ref lrref()) { + if (!$canon) { + # nope + next; + } + dofetch(); + } + # now lrref exists + runcmd (@git, qw(update-ref), lref(), lrref(), ''); + last; + } + local $ENV{GIT_REFLOG_ACTION} = git_reflog_action_msg + "dgit checkout $isuite"; + runcmd (@git, qw(checkout), lbranch()); +} + +sub cmd_update_vcs_git () { + my $specsuite; + if (@ARGV==0 || $ARGV[0] =~ m/^-/) { + ($specsuite,) = split /\;/, cfg 'dgit.vcs-git.suites'; + } else { + ($specsuite) = (@ARGV); + shift @ARGV; + } + my $dofetch=1; + if (@ARGV) { + if ($ARGV[0] eq '-') { + $dofetch = 0; + } elsif ($ARGV[0] eq '-') { + shift; + } + } + + package_from_d_control(); + my $ctrl; + if ($specsuite eq '.') { + $ctrl = parsecontrol 'debian/control', 'debian/control'; + } else { + $isuite = $specsuite; + get_archive_dsc(); + $ctrl = $dsc; + } + my $url = getfield $ctrl, 'Vcs-Git'; + + my @cmd; + my $orgurl = cfg 'remote.vcs-git.url', 'RETURN-UNDEF'; + if (!defined $orgurl) { + print STDERR "setting up vcs-git: $url\n"; + @cmd = (@git, qw(remote add vcs-git), $url); + } elsif ($orgurl eq $url) { + print STDERR "vcs git already configured: $url\n"; + } else { + print STDERR "changing vcs-git url to: $url\n"; + @cmd = (@git, qw(remote set-url vcs-git), $url); + } + runcmd_ordryrun_local @cmd; + if ($dofetch) { + print "fetching (@ARGV)\n"; + runcmd_ordryrun_local @git, qw(fetch vcs-git), @ARGV; + } +} + sub prep_push () { parseopts(); build_or_push_prep_early(); @@ -5062,13 +5226,15 @@ sub quiltify_splitbrain_needed () { } } -sub quiltify_splitbrain ($$$$$$) { - my ($clogp, $unapplied, $headref, $diffbits, +sub quiltify_splitbrain ($$$$$$$) { + my ($clogp, $unapplied, $headref, $oldtiptree, $diffbits, $editedignores, $cachekey) = @_; + my $gitignore_special = 1; if ($quilt_mode !~ m/gbp|dpm/) { # treat .gitignore just like any other upstream file $diffbits = { %$diffbits }; $_ = !!$_ foreach values %$diffbits; + $gitignore_special = 0; } # We would like any commits we generate to be reproducible my @authline = clogp_authline($clogp); @@ -5079,11 +5245,19 @@ sub quiltify_splitbrain ($$$$$$) { local $ENV{GIT_AUTHOR_EMAIL} = $authline[1]; local $ENV{GIT_AUTHOR_DATE} = $authline[2]; + my $fulldiffhint = sub { + my ($x,$y) = @_; + my $cmd = "git diff $x $y -- :/ ':!debian'"; + $cmd .= " ':!/.gitignore' ':!*/.gitignore'" if $gitignore_special; + return "\nFor full diff showing the problem(s), type:\n $cmd\n"; + }; + if ($quilt_mode =~ m/gbp|unapplied/ && ($diffbits->{O2H} & 01)) { my $msg = "--quilt=$quilt_mode specified, implying patches-unapplied git tree\n". " but git tree differs from orig in upstream files."; + $msg .= $fulldiffhint->($unapplied, 'HEAD'); if (!stat_exists "debian/patches") { $msg .= "\n ... debian/patches is missing; perhaps this is a patch queue branch?"; @@ -5092,7 +5266,7 @@ sub quiltify_splitbrain ($$$$$$) { } if ($quilt_mode =~ m/dpm/ && ($diffbits->{H2A} & 01)) { - fail <($oldtiptree,'HEAD'); --quilt=$quilt_mode specified, implying patches-applied git tree but git tree differs from result of applying debian/patches to upstream END @@ -5108,7 +5282,7 @@ END } if ($quilt_mode =~ m/gbp|dpm/ && ($diffbits->{O2A} & 02)) { - fail <($notp), "\n"; } print STDERR "$us: $_\n" foreach @$failsuggestion; - fail "quilt fixup naive history linearisation failed.\n". + fail + "quilt history linearisation failed. Search \`quilt fixup' in dgit(7).\n". "Use dpkg-source --commit by hand; or, --quilt=smash for one ugly patch"; } elsif ($quilt_mode eq 'smash') { } elsif ($quilt_mode eq 'auto') { @@ -5491,8 +5666,9 @@ END make-patches --quiet-would-amend)); # We tolerate soe snags that gdr wouldn't, by default. if (act_local()) { + debugcmd "+",@cmd; $!=0; $?=-1; - failedcmd @cmd if system @cmd and $?!=7; + failedcmd @cmd if system @cmd and $?!=7*256; } else { dryrun_report @cmd; } @@ -5876,7 +6052,7 @@ END " --[quilt=]gbp --[quilt=]dpm --quilt=unapplied ?"; if (quiltmode_splitbrain()) { - quiltify_splitbrain($clogp, $unapplied, $headref, + quiltify_splitbrain($clogp, $unapplied, $headref, $oldtiptree, $diffbits, \%editedignores, $splitbrain_cachekey); return; @@ -6018,13 +6194,21 @@ sub changesopts_initial () { sub changesopts_version () { if (!defined $changes_since_version) { - my @vsns = archive_query('archive_query'); - my @quirk = access_quirk(); - if ($quirk[0] eq 'backports') { - local $isuite = $quirk[2]; - local $csuite; - canonicalise_suite(); - push @vsns, archive_query('archive_query'); + my @vsns; + unless (eval { + @vsns = archive_query('archive_query'); + my @quirk = access_quirk(); + if ($quirk[0] eq 'backports') { + local $isuite = $quirk[2]; + local $csuite; + canonicalise_suite(); + push @vsns, archive_query('archive_query'); + } + 1; + }) { + print STDERR $@; + fail + "archive query failed (queried because --since-version not specified)"; } if (@vsns) { @vsns = map { $_->[0] } @vsns; @@ -6350,7 +6534,7 @@ sub cmd_quilt_fixup { sub import_dsc_result { my ($dstref, $newhash, $what_log, $what_msg) = @_; - my @cmd = (@git, qw(update-ref -m), $what_log, $dstref, $newhash); + my @cmd = (git_update_ref_cmd $what_log, $dstref, $newhash); runcmd @cmd; check_gitattrs($newhash, "source tree");