From: Ian Jackson Date: Tue, 2 Jul 2019 13:36:04 +0000 (+0100) Subject: Merge branch 'buster' X-Git-Tag: archive/debian/9.0~6 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=467846c8b31edae2e091e6ecf232fecefa32e247;hp=8701e2e272b99850f0dac7cf8b06e6ba6a26afaf;p=dgit.git Merge branch 'buster' --- diff --git a/Debian/Dgit.pm b/Debian/Dgit.pm index 61476d9f..887fbb59 100644 --- a/Debian/Dgit.pm +++ b/Debian/Dgit.pm @@ -43,9 +43,10 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw(setup_sigwarn forkcheck_setup forkcheck_mainprocess dep14_version_mangle - debiantags debiantag_old debiantag_new + debiantags debiantag_new debiantag_maintview upstreamversion + upstream_commitish_search resolve_upstream_version stripepoch source_file_leafname is_orig_file_of_p_v server_branch server_ref stat_exists link_ltarget rename_link_xf @@ -59,7 +60,9 @@ BEGIN { git_for_each_tag_referring is_fast_fwd git_check_unmodified git_reflog_action_msg git_update_ref_cmd - make_commit_text + rm_subdir_cached read_tree_subdir + read_tree_debian read_tree_upstream + make_commit hash_commit hash_commit_text reflog_cache_insert reflog_cache_lookup $package_re $component_re $deliberately_re $distro_re $versiontag_re $series_filename_re @@ -233,11 +236,6 @@ sub dep14_version_mangle ($) { return $v; } -sub debiantag_old ($$) { - my ($v,$distro) = @_; - return "$distro/". dep14_version_mangle $v; -} - sub debiantag_new ($$) { my ($v,$distro) = @_; return "archive/$distro/".dep14_version_mangle $v; @@ -250,7 +248,7 @@ sub debiantag_maintview ($$) { sub debiantags ($$) { my ($version,$distro) = @_; - map { $_->($version, $distro) } (\&debiantag_new, \&debiantag_old); + map { $_->($version, $distro) } (\&debiantag_new, \&debiantag_maintview); } sub stripepoch ($) { @@ -622,6 +620,41 @@ sub git_check_unmodified () { } } +sub upstream_commitish_search ($$) { + my ($upstream_version, $tried) = @_; + # todo: at some point maybe use git-deborig to do this + foreach my $tagpfx ('', 'v', 'upstream/') { + my $tag = $tagpfx.(dep14_version_mangle $upstream_version); + my $new_upstream = git_get_ref "refs/tags/$tag"; + push @$tried, $tag; + return $new_upstream if length $new_upstream; + } +} + +sub resolve_upstream_version ($$) { + my ($new_upstream, $upstream_version) = @_; + + my $used = $new_upstream; + my $message = __ 'using specified upstream commitish'; + if (!defined $new_upstream) { + my @tried; + $new_upstream = upstream_commitish_search $upstream_version, \@tried; + if (!length $new_upstream) { + fail f_ + "Could not determine appropriate upstream commitish.\n". + " (Tried these tags: %s)\n". + " Check version, and specify upstream commitish explicitly.", + "@tried"; + } + $used = $tried[-1]; + $message = f_ 'using upstream from git tag %s', $used; + } + $new_upstream = git_rev_parse $new_upstream; + + return ($new_upstream, $used, $message); + # used is a human-readable idea of what we found +} + sub is_fast_fwd ($$) { my ($ancestor,$child) = @_; my @cmd = (qw(git merge-base), $ancestor, $child); @@ -649,6 +682,39 @@ sub git_update_ref_cmd { return qw(git update-ref -m), $msg, @_; } +sub rm_subdir_cached ($) { + my ($subdir) = @_; + runcmd qw(git rm --quiet -rf --cached --ignore-unmatch), $subdir; +} + +sub read_tree_subdir ($$) { + my ($subdir, $new_tree_object) = @_; + # If $new_tree_object is '', the subtree is deleted. + confess unless defined $new_tree_object; + rm_subdir_cached $subdir; + runcmd qw(git read-tree), "--prefix=$subdir/", $new_tree_object + if length $new_tree_object; +} + +sub read_tree_debian ($) { + my ($treeish) = @_; + read_tree_subdir 'debian', "$treeish:debian"; + rm_subdir_cached 'debian/patches'; +} + +sub read_tree_upstream ($;$$) { + my ($treeish, $keep_patches, $tree_with_debian) = @_; + # if $tree_with_debian is supplied, will use that for debian/ + # otherwise will save and restore it. If $tree_with_debian + # is '' then debian/ is deleted. + my $debian = + defined $tree_with_debian ? "$tree_with_debian:debian" + : cmdoutput qw(git write-tree --prefix=debian/); + runcmd qw(git read-tree), $treeish; + read_tree_subdir 'debian', $debian; + rm_subdir_cached 'debian/patches' unless $keep_patches; +} + sub changedir ($) { my ($newdir) = @_; printdebug "CD $newdir\n"; @@ -771,7 +837,21 @@ sub parsechangelog_loop ($$$) { close CLOGS or $?==SIGPIPE or failedcmd @$clogcmd; } -sub make_commit_text ($) { +sub make_commit ($$) { + my ($parents, $message_paras) = @_; + my $tree = cmdoutput qw(git write-tree); + my @cmd = (qw(git commit-tree), $tree); + push @cmd, qw(-p), $_ foreach @$parents; + push @cmd, qw(-m), $_ foreach @$message_paras; + return cmdoutput @cmd; +} + +sub hash_commit ($) { + my ($file) = @_; + return cmdoutput qw(git hash-object -w -t commit), $file; +} + +sub hash_commit_text ($) { my ($text) = @_; my ($out, $in); my @cmd = (qw(git hash-object -w -t commit --stdin)); @@ -812,7 +892,7 @@ sub reflog_cache_insert ($$$) { # git update-ref doesn't always update, in this case. *sigh* my $authline = (ucfirst _us()). ' <'._us().'@example.com> 1000000000 +0000'; - my $dummy = make_commit_text <=8), fakeroot, build-essential, chiark-utils-bin, bc, faketime, quilt, git-debrebase, git-buildpackage, libdpkg-perl, libgit-wrapper-perl, liblist-compare-perl, libstring-shellquote-perl, libtry-tiny-perl + Tests: build-modes-gbp Tests-Directory: tests/tests Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, bc, faketime, git-buildpackage @@ -68,7 +72,7 @@ Tests: trustingpolicy-replay Tests-Directory: tests/tests Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, bc, faketime, dput-ng -Tests: absurd-gitapply badcommit-rewrite build-modes build-modes-long build-modes-source checkout clone-clogsigpipe clone-gitnosuite clone-nogit debpolicy-dbretry debpolicy-newreject debpolicy-quilt-gbp defdistro-rpush defdistro-setup distropatches-reject dpkgsourceignores-correct drs-clone-nogit drs-push-masterupdate drs-push-rejects dsd-clone-nogit dsd-divert fetch-localgitonly fetch-somegit-notlast gbp-orig gitconfig gitworktree import-dsc import-linkorigs import-maintmangle import-native import-nonnative import-tarbomb inarchivecopy mismatches-contents mismatches-dscchanges multisuite newtag-clone-nogit oldnewtagalt oldtag-clone-nogit orig-include-exclude orig-include-exclude-chkquery overwrite-chkclog overwrite-junk overwrite-splitbrains overwrite-version pbuilder protocol-compat push-buildproductsdir push-newpackage push-newrepeat push-nextdgit push-source push-source-with-changes quilt quilt-gbp quilt-gbp-build-modes quilt-singlepatch quilt-splitbrains quilt-useremail rpush rpush-quilt sourceonlypolicy tag-updates unrepresentable version-opt +Tests: absurd-gitapply badcommit-rewrite build-modes build-modes-long build-modes-source checkout clone-clogsigpipe clone-gitnosuite clone-nogit debpolicy-dbretry debpolicy-newreject debpolicy-quilt-gbp debpolicy-taintrm defdistro-rpush defdistro-setup distropatches-reject dpkgsourceignores-correct drs-clone-nogit drs-push-masterupdate drs-push-rejects dsd-clone-nogit dsd-divert fetch-localgitonly fetch-somegit-notlast forcesplit-linear forcesplit-overwrite gbp-orig gitconfig gitworktree import-dsc import-linkorigs import-maintmangle import-native import-nonnative import-tarbomb inarchivecopy mismatches-contents mismatches-dscchanges multisuite orig-include-exclude orig-include-exclude-chkquery overwrite-chkclog overwrite-junk overwrite-splitbrains overwrite-version pbuilder protocol-compat push-buildproductsdir push-newpackage push-newrepeat push-nextdgit push-source push-source-with-changes quilt quilt-gbp quilt-gbp-build-modes quilt-singlepatch quilt-splitbrains quilt-useremail rpush rpush-quilt sourceonlypolicy tag-updates unrepresentable version-opt Tests-Directory: tests/tests Depends: dgit, dgit-infrastructure, devscripts, debhelper (>=8), fakeroot, build-essential, chiark-utils-bin, bc, faketime diff --git a/dgit b/dgit index f1b322ad..2d235a63 100755 --- a/dgit +++ b/dgit @@ -53,7 +53,7 @@ use Debian::Dgit; our $our_version = 'UNRELEASED'; ###substituted### our $absurdity = undef; ###substituted### -our @rpushprotovsn_support = qw(4 3 2); # 4 is new tag format +our @rpushprotovsn_support = qw(4 5); # 5 drops tag format specification our $protovsn; our $cmd; @@ -79,16 +79,19 @@ our $changes_since_version; 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 $quilt_upstream_commitish; +our $quilt_upstream_commitish_used; +our $quilt_upstream_commitish_message; +our $quilt_options_re = 'gbp|dpm|baredebian(?:\+tarball|\+git)?'; +our $quilt_modes_re = "linear|smash|auto|nofix|nocheck|unapplied|$quilt_options_re"; +our $splitview_mode; +our $splitview_modes_re = qr{auto|always|never}; our $dodep14tag; our %internal_object_save; our $we_are_responder; our $we_are_initiator; our $initiator_tempdir; our $patches_applied_dirtily = 00; -our $tagformat_want; -our $tagformat; -our $tagformatfn; our $chase_dsc_distro=1; our %forceopts = map { $_=>0 } @@ -175,7 +178,31 @@ our $keyid; autoflush STDOUT 1; our $supplementary_message = ''; -our $split_brain = 0; +our $made_split_brain = 0; +our $do_split_brain; + +# Interactions between quilt mode and split brain +# (currently, split brain only implemented iff +# madformat_wantfixup && quiltmode_splitting) +# +# source format sane `3.0 (quilt)' +# madformat_wantfixup() +# +# quilt mode normal quiltmode +# (eg linear) _splitbrain +# +# ------------ ------------------------------------------------ +# +# no split no q cache no q cache forbidden, +# brain PM on master q fixup on master prevented +# !do_split_brain() PM on master +# +# split brain no q cache q fixup cached, to dgit view +# PM in dgit view PM in dgit view +# +# PM = pseudomerge to make ff, due to overwrite (or split view) +# "no q cache" = do not record in cache on build, do not check cache +# `3.0 (quilt)' with --quilt=nocheck is treated as sane format END { local ($@, $?); @@ -193,11 +220,6 @@ if (!defined $absurdity) { $absurdity =~ s{/[^/]+$}{/absurd} or die; } -sub debiantag ($$) { - my ($v,$distro) = @_; - return $tagformatfn->($v, $distro); -} - sub madformat ($) { $_[0] eq '3.0 (quilt)' } sub lbranch () { return "$branchprefix/$csuite"; } @@ -275,10 +297,12 @@ sub deliberately_not_fast_forward () { } } -sub quiltmode_splitbrain () { - $quilt_mode =~ m/gbp|dpm|unapplied/; +sub quiltmode_splitting () { + $quilt_mode =~ m/gbp|dpm|unapplied|baredebian/; } +sub do_split_brain () { !!($do_split_brain // confess) } + sub opts_opt_multi_cmd { my $extra = shift; my @cmd; @@ -424,7 +448,7 @@ sub branch_is_gdr ($) { # > progress NBYTES # [NBYTES message] # -# > supplementary-message NBYTES # $protovsn >= 3 +# > supplementary-message NBYTES # [NBYTES message] # # main sequence: @@ -444,7 +468,7 @@ sub branch_is_gdr ($) { # # > param head DGIT-VIEW-HEAD # > param csuite SUITE -# > param tagformat old|new +# > param tagformat new # $protovsn == 4 # > param maint-view MAINT-VIEW-HEAD # # > param buildinfo-filename P_V_X.buildinfo # zero or more times @@ -709,7 +733,6 @@ our %defcfg = ('dgit.default.distro' => 'debian', 'dgit.default.archive-query' => 'madison:', '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', @@ -919,6 +942,20 @@ sub access_forpush () { return $access_forpush; } +sub default_from_access_cfg ($$$;$) { + my ($var, $keybase, $defval, $permit_re) = @_; + return if defined $$var; + + $$var = access_cfg("$keybase-newer", 'RETURN-UNDEF'); + $$var = undef if $$var && $$var !~ m/^$permit_re$/; + + $$var //= access_cfg($keybase, 'RETURN-UNDEF'); + $$var //= $defval; + + badcfg f_ "unknown %s \`%s'", $keybase, $$var + if defined $permit_re and $$var !~ m/$permit_re/; +} + sub pushing () { confess +(__ 'internal error').' '.Dumper($access_forpush)," ?" if defined $access_forpush and !$access_forpush; @@ -936,12 +973,36 @@ sub notpushing () { parseopts_late_defaults(); } +sub determine_whether_split_brain () { + my ($format,) = get_source_format(); + + { + local $access_forpush; + default_from_access_cfg(\$splitview_mode, 'split-view', 'auto', + $splitview_modes_re); + $do_split_brain = 1 if $splitview_mode eq 'always'; + } + + printdebug "format $format, quilt mode $quilt_mode\n"; + + if (madformat_wantfixup($format) && quiltmode_splitting()) { + $splitview_mode ne 'never' or + fail f_ "dgit: quilt mode \`%s' (for format \`%s')". + " implies split view, but split-view set to \`%s'", + $quilt_mode, $format, $splitview_mode; + $do_split_brain = 1; + } + $do_split_brain //= 0; + + return ($format); +} + sub supplementary_message ($) { my ($msg) = @_; if (!$we_are_responder) { $supplementary_message = $msg; return; - } elsif ($protovsn >= 3) { + } else { responder_send_command "supplementary-message ".length($msg) or confess "$!"; print PO $msg or confess "$!"; @@ -1643,58 +1704,6 @@ sub archive_query_dummycat ($$) { sub file_in_archive_dummycat () { return undef; } sub package_not_wholly_new_dummycat () { return undef; } -#---------- tag format handling ---------- -# (untranslated, because everything should be new tag format by now) - -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". - " to use tag format $tagformat_want->[0] ($tagformat_want->[1])". - " - no way to proceed" - if $tagformat_want && $tagformat_want->[0] ne $fmt; - $tagformat_want = [$fmt, $why, $tagformat_want->[2] // 0]; -} - -sub select_tagformat () { - # sets $tagformatfn - return if $tagformatfn && !$tagformat_want; - die 'bug' if $tagformatfn && $tagformat_want; - # ... $tagformat_want assigned after previous select_tagformat - - my (@supported) = grep { $_ =~ m/^(?:old|new)$/ } access_cfg_tagformats(); - printdebug "select_tagformat supported @supported\n"; - - $tagformat_want //= [ $supported[0], "distro access configuration", 0 ]; - printdebug "select_tagformat specified @$tagformat_want\n"; - - my ($fmt,$why,$override) = @$tagformat_want; - - fail "target distro supports tag formats @supported". - " but have to use $fmt ($why)" - unless $override - or grep { $_ eq $fmt } @supported; - - $tagformat_want = undef; - $tagformat = $fmt; - $tagformatfn = ${*::}{"debiantag_$fmt"}; - - fail "trying to use unknown tag format \`$fmt' ($why) !" - unless $tagformatfn; -} - #---------- archive query entrypoints and rest of program ---------- sub canonicalise_suite () { @@ -2109,11 +2118,6 @@ END } } -sub make_commit ($) { - my ($file) = @_; - return cmdoutput @git, qw(hash-object -w -t commit), $file; -} - sub clogp_authline ($) { my ($clogp) = @_; my $author = getfield $clogp, 'Maintainer'; @@ -2267,62 +2271,9 @@ sub dotdot_bpd_transfer_origs ($$$) { closedir DD; } -sub generate_commits_from_dsc () { - # See big comment in fetch_from_archive, below. - # See also README.dsc-import. - prep_ud(); - changedir $playground; - - my $bpd_abs = bpd_abs(); - my $upstreamv = upstreamversion $dsc->{version}; - my @dfi = dsc_files_info(); - - dotdot_bpd_transfer_origs $bpd_abs, $upstreamv, - sub { grep { $_->{Filename} eq $_[0] } @dfi }; - - foreach my $fi (@dfi) { - my $f = $fi->{Filename}; - die "$f ?" if $f =~ m#/|^\.|\.dsc$|\.tmp$#; - my $upper_f = "$bpd_abs/$f"; - - printdebug "considering reusing $f: "; - - if (link_ltarget "$upper_f,fetch", $f) { - printdebug "linked (using ...,fetch).\n"; - } elsif ((printdebug "($!) "), - $! != ENOENT) { - fail f_ "accessing %s: %s", "$buildproductsdir/$f,fetch", $!; - } elsif (link_ltarget $upper_f, $f) { - printdebug "linked.\n"; - } elsif ((printdebug "($!) "), - $! != ENOENT) { - fail f_ "accessing %s: %s", "$buildproductsdir/$f", $!; - } else { - printdebug "absent.\n"; - } - - my $refetched; - complete_file_from_dsc('.', $fi, \$refetched) - or next; - - printdebug "considering saving $f: "; - - if (rename_link_xf 1, $f, $upper_f) { - printdebug "linked.\n"; - } elsif ((printdebug "($@) "), - $! != EEXIST) { - fail f_ "saving %s: %s", "$buildproductsdir/$f", $@; - } elsif (!$refetched) { - printdebug "no need.\n"; - } elsif (rename_link_xf 1, $f, "$upper_f,fetch") { - printdebug "linked (using ...,fetch).\n"; - } elsif ((printdebug "($@) "), - $! != EEXIST) { - fail f_ "saving %s: %s", "$buildproductsdir/$f,fetch", $@; - } else { - printdebug "cannot.\n"; - } - } +sub import_tarball_tartrees ($$) { + my ($upstreamv, $dfi) = @_; + # cwd should be the playground # We unpack and record the orig tarballs first, so that we only # need disk space for one private copy of the unpacked source. @@ -2332,14 +2283,13 @@ sub generate_commits_from_dsc () { my @tartrees; my $orig_f_base = srcfn $upstreamv, ''; - foreach my $fi (@dfi) { + foreach my $fi (@$dfi) { # We actually import, and record as a commit, every tarball # (unless there is only one file, in which case there seems # little point. my $f = $fi->{Filename}; printdebug "import considering $f "; - (printdebug "only one dfi\n"), next if @dfi == 1; (printdebug "not tar\n"), next unless $f =~ m/\.tar(\.\w+)?$/; (printdebug "signature\n"), next if $f =~ m/$orig_f_sig_re$/o; my $compr_ext = $1; @@ -2351,6 +2301,7 @@ sub generate_commits_from_dsc () { $compr_ext, $orig_f_part ), "\n"; + my $path = $fi->{Path} // $f; my $input = new IO::File $f, '<' or die "$f $!"; my $compr_pid; my @compr_cmd; @@ -2416,6 +2367,7 @@ sub generate_commits_from_dsc () { Sort => (!$orig_f_part ? 2 : $orig_f_part =~ m/-/g ? 1 : 0), + OrigPart => $orig_f_part, # 'orig', 'orig-XXX', or undef F => $f, Tree => $tree, }; @@ -2429,36 +2381,15 @@ sub generate_commits_from_dsc () { $a->{F} cmp $b->{F} } @tartrees; - my $any_orig = grep { $_->{Orig} } @tartrees; - - my $dscfn = "$package.dsc"; + @tartrees; +} - my $treeimporthow = 'package'; +sub import_tarball_commits ($$) { + my ($tartrees, $upstreamv) = @_; + # cwd should be a playtree which has a relevant debian/changelog + # fills in $tt->{Commit} for each one - open D, ">", $dscfn or die "$dscfn: $!"; - print D $dscdata or die "$dscfn: $!"; - close D or die "$dscfn: $!"; - my @cmd = qw(dpkg-source); - push @cmd, '--no-check' if $dsc_checked; - if (madformat $dsc->{format}) { - push @cmd, '--skip-patches'; - $treeimporthow = 'unpatched'; - } - push @cmd, qw(-x --), $dscfn; - runcmd @cmd; - - my ($tree,$dir) = mktree_in_ud_from_only_subdir(__ "source package"); - if (madformat $dsc->{format}) { - check_for_vendor_patches(); - } - - my $dappliedtree; - if (madformat $dsc->{format}) { - my @pcmd = qw(dpkg-source --before-build .); - runcmd shell_cmd 'exec >/dev/null', @pcmd; - rmtree '.pc'; - $dappliedtree = git_add_write_tree(); - } + my $any_orig = grep { $_->{Orig} } @$tartrees; my @clogcmd = qw(dpkg-parsechangelog --format rfc822 --all); my $clogp; @@ -2512,20 +2443,22 @@ sub generate_commits_from_dsc () { $changes =~ s/^\n//; # Changes: \n my $cversion = getfield $clogp, 'Version'; - if (@tartrees) { + my $r1authline; + if (@$tartrees) { $r1clogp //= $clogp; # maybe there's only one entry; - my $r1authline = clogp_authline $r1clogp; + $r1authline = clogp_authline $r1clogp; # Strictly, r1authline might now be wrong if it's going to be # unused because !$any_orig. Whatever. printdebug "import tartrees authline $authline\n"; printdebug "import tartrees r1authline $r1authline\n"; - foreach my $tt (@tartrees) { + foreach my $tt (@$tartrees) { printdebug "import tartree $tt->{F} $tt->{Tree}\n"; - my $mbody = f_ "Import %s", $tt->{F}; - $tt->{Commit} = make_commit_text($tt->{Orig} ? <{F}; + $tt->{Commit} = hash_commit_text($tt->{Orig} ? <{Tree} author $r1authline committer $r1authline @@ -2545,6 +2478,104 @@ END_T } } + return ($authline, $r1authline, $clogp, $changes); +} + +sub generate_commits_from_dsc () { + # See big comment in fetch_from_archive, below. + # See also README.dsc-import. + prep_ud(); + changedir $playground; + + my $bpd_abs = bpd_abs(); + my $upstreamv = upstreamversion $dsc->{version}; + my @dfi = dsc_files_info(); + + dotdot_bpd_transfer_origs $bpd_abs, $upstreamv, + sub { grep { $_->{Filename} eq $_[0] } @dfi }; + + foreach my $fi (@dfi) { + my $f = $fi->{Filename}; + die "$f ?" if $f =~ m#/|^\.|\.dsc$|\.tmp$#; + my $upper_f = "$bpd_abs/$f"; + + printdebug "considering reusing $f: "; + + if (link_ltarget "$upper_f,fetch", $f) { + printdebug "linked (using ...,fetch).\n"; + } elsif ((printdebug "($!) "), + $! != ENOENT) { + fail f_ "accessing %s: %s", "$buildproductsdir/$f,fetch", $!; + } elsif (link_ltarget $upper_f, $f) { + printdebug "linked.\n"; + } elsif ((printdebug "($!) "), + $! != ENOENT) { + fail f_ "accessing %s: %s", "$buildproductsdir/$f", $!; + } else { + printdebug "absent.\n"; + } + + my $refetched; + complete_file_from_dsc('.', $fi, \$refetched) + or next; + + printdebug "considering saving $f: "; + + if (rename_link_xf 1, $f, $upper_f) { + printdebug "linked.\n"; + } elsif ((printdebug "($@) "), + $! != EEXIST) { + fail f_ "saving %s: %s", "$buildproductsdir/$f", $@; + } elsif (!$refetched) { + printdebug "no need.\n"; + } elsif (rename_link_xf 1, $f, "$upper_f,fetch") { + printdebug "linked (using ...,fetch).\n"; + } elsif ((printdebug "($@) "), + $! != EEXIST) { + fail f_ "saving %s: %s", "$buildproductsdir/$f,fetch", $@; + } else { + printdebug "cannot.\n"; + } + } + + my @tartrees; + @tartrees = import_tarball_tartrees($upstreamv, \@dfi) + unless @dfi == 1; # only one file in .dsc + + my $dscfn = "$package.dsc"; + + my $treeimporthow = 'package'; + + open D, ">", $dscfn or die "$dscfn: $!"; + print D $dscdata or die "$dscfn: $!"; + close D or die "$dscfn: $!"; + my @cmd = qw(dpkg-source); + push @cmd, '--no-check' if $dsc_checked; + if (madformat $dsc->{format}) { + push @cmd, '--skip-patches'; + $treeimporthow = 'unpatched'; + } + push @cmd, qw(-x --), $dscfn; + runcmd @cmd; + + my ($tree,$dir) = mktree_in_ud_from_only_subdir(__ "source package"); + if (madformat $dsc->{format}) { + check_for_vendor_patches(); + } + + my $dappliedtree; + if (madformat $dsc->{format}) { + my @pcmd = qw(dpkg-source --before-build .); + runcmd shell_cmd 'exec >/dev/null', @pcmd; + rmtree '.pc'; + $dappliedtree = git_add_write_tree(); + } + + my ($authline, $r1authline, $clogp, $changes) = + import_tarball_commits(\@tartrees, $upstreamv); + + my $cversion = getfield $clogp, 'Version'; + printdebug "import main commit\n"; open C, ">../commit.tmp" or confess "$!"; @@ -2564,14 +2595,14 @@ $changes END close C or confess "$!"; - my $rawimport_hash = make_commit qw(../commit.tmp); + my $rawimport_hash = hash_commit qw(../commit.tmp); if (madformat $dsc->{format}) { printdebug "import apply patches...\n"; # regularise the state of the working tree so that # the checkout of $rawimport_hash works nicely. - my $dappliedcommit = make_commit_text(< 1, - Message => (f_ < (sprintf < 0) { @@ -2945,11 +2979,7 @@ sub git_fetch_us () { # 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)); + map { "tags/$_" } debiantags('*',access_nomdistro); push @specs, server_branch($csuite); push @specs, $rewritemap; push @specs, qw(heads/*) if deliberately_not_fast_forward; @@ -3425,7 +3455,7 @@ END } close MC or confess "$!"; - $hash = make_commit $mcf; + $hash = hash_commit $mcf; } else { $hash = $mergeinputs[0]{Commit}; } @@ -3786,7 +3816,7 @@ sub fork_for_multisuite ($) { $commit .= "author $authline\n". "committer $authline\n\n"; - $output = make_commit_text $commit.$msg; + $output = hash_commit_text $commit.$msg; printdebug "multisuite merge generated $output\n"; } @@ -4096,6 +4126,7 @@ sub pseudomerge_version_check ($$) { $cd = $gf->('Distribution'); }; if ($@) { + $@ =~ s/^\n//s; $@ =~ s/^dgit: //gm; fail "$@". f_ "Perhaps debian/changelog does not mention %s ?", $v; @@ -4112,7 +4143,7 @@ END return $i_arch_v; } -sub pseudomerge_make_commit ($$$$ $$) { +sub pseudomerge_hash_commit ($$$$ $$) { my ($clogp, $dgitview, $archive_hash, $i_arch_v, $msg_cmd, $msg_msg) = @_; progress f_ "Declaring that HEAD includes all changes in %s...", @@ -4144,7 +4175,7 @@ $msg_msg END close MC or confess "$!"; - return make_commit($pmf); + return hash_commit($pmf); } sub splitbrain_pseudomerge ($$$$) { @@ -4202,7 +4233,7 @@ ENDT } my $arch_v = $i_arch_v->[0]; - my $r = pseudomerge_make_commit + my $r = pseudomerge_hash_commit $clogp, $dgitview, $archive_hash, $i_arch_v, "dgit --quilt=$quilt_mode", (defined $overwrite_version @@ -4226,7 +4257,7 @@ sub plain_overwrite_pseudomerge ($$$) { my $m = f_ "Declare fast forward from %s", $i_arch_v->[0]; - my $r = pseudomerge_make_commit + my $r = pseudomerge_hash_commit $clogp, $head, $archive_hash, $i_arch_v, "dgit", $m; @@ -4251,7 +4282,7 @@ sub push_parse_changelog ($) { if (!$we_are_initiator) { # rpush initiator can't do this because it doesn't have $isuite yet - my $tag = debiantag($cversion, access_nomdistro); + my $tag = debiantag_new($cversion, access_nomdistro); runcmd @git, qw(check-ref-format), $tag; } @@ -4275,7 +4306,7 @@ sub push_tagwants ($$$$) { my ($cversion, $dgithead, $maintviewhead, $tfbase) = @_; my @tagwants; push @tagwants, { - TagFn => \&debiantag, + TagFn => \&debiantag_new, Objid => $dgithead, TfSuffix => '', View => 'dgit', @@ -4287,14 +4318,7 @@ 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 < \&debiantag_maintview, Objid => $dgithead, @@ -4438,14 +4462,10 @@ Push failed, while preparing your push. You can retry the push, after fixing the problem, if you like. END - need_tagformat 'new', "quilt mode $quilt_mode" - if quiltmode_splitbrain; - prep_ud(); access_giturl(); # check that success is vaguely likely rpush_handle_protovsn_bothends() if $we_are_initiator; - select_tagformat(); my $clogpfn = dgit_privdir()."/changelog.822.tmp"; runcmd shell_cmd "exec >$clogpfn", qw(dpkg-parsechangelog); @@ -4465,13 +4485,12 @@ END push_parse_dsc($dscpath, $dscfn, $cversion); my $format = getfield $dsc, 'Format'; - printdebug "format $format\n"; my $symref = git_get_symref(); my $actualhead = git_rev_parse('HEAD'); if (branch_is_gdr_unstitched_ff($symref, $actualhead, $archive_hash)) { - if (quiltmode_splitbrain()) { + if (quiltmode_splitting()) { my ($ffq_prev, $gdrlast) = branch_gdr_info($symref, $actualhead); fail f_ <= 3; for (;;) { my ($icmd,$iargs) = initiator_expect { @@ -5168,11 +5188,6 @@ sub i_resp_want ($) { pushing(); rpush_handle_protovsn_bothends(); - fail f_ "rpush negotiated protocol version %s". - " which does not support quilt mode %s", - $protovsn, $quilt_mode - if quiltmode_splitbrain && $protovsn < 4; - my @localpaths = i_method "i_want", $keyword; printdebug "[[ $keyword @localpaths\n"; foreach my $localpath (@localpaths) { @@ -5242,11 +5257,10 @@ sub i_want_signed_tag { my $maintview = $i_param{'maint-view'}; die if defined $maintview && $maintview =~ m/[^0-9a-f]/; - select_tagformat(); - if ($protovsn >= 4) { + if ($protovsn == 4) { my $p = $i_param{'tagformat'} // ''; - $p eq $tagformat - or badproto \*RO, "tag format mismatch: $p vs. $tagformat"; + $p eq 'new' + or badproto \*RO, "tag format mismatch: $p vs. new"; } die unless $i_param{'csuite'} =~ m/^$suite_re$/; @@ -5374,19 +5388,11 @@ sub quiltify_tree_sentinelfiles ($) { return $r; } -sub quiltify_splitbrain_needed () { - if (!$split_brain) { - progress __ "dgit view: changes are required..."; - runcmd @git, qw(checkout -q -b dgit-view); - $split_brain = 1; - } -} - -sub quiltify_splitbrain ($$$$$$$) { +sub quiltify_splitting ($$$$$$$) { my ($clogp, $unapplied, $headref, $oldtiptree, $diffbits, $editedignores, $cachekey) = @_; my $gitignore_special = 1; - if ($quilt_mode !~ m/gbp|dpm/) { + if ($quilt_mode !~ m/gbp|dpm|baredebian/) { # treat .gitignore just like any other upstream file $diffbits = { %$diffbits }; $_ = !!$_ foreach values %$diffbits; @@ -5401,6 +5407,8 @@ sub quiltify_splitbrain ($$$$$$$) { local $ENV{GIT_AUTHOR_EMAIL} = $authline[1]; local $ENV{GIT_AUTHOR_DATE} = $authline[2]; + confess unless do_split_brain(); + my $fulldiffhint = sub { my ($x,$y) = @_; my $cmd = "git diff $x $y -- :/ ':!debian'"; @@ -5409,14 +5417,14 @@ sub quiltify_splitbrain ($$$$$$$) { $cmd; }; - if ($quilt_mode =~ m/gbp|unapplied/ && + if ($quilt_mode =~ m/gbp|unapplied|baredebian/ && ($diffbits->{O2H} & 01)) { my $msg = f_ "--quilt=%s specified, implying patches-unapplied git tree\n". " but git tree differs from orig in upstream files.", $quilt_mode; $msg .= $fulldiffhint->($unapplied, 'HEAD'); - if (!stat_exists "debian/patches") { + if (!stat_exists "debian/patches" and $quilt_mode !~ m/baredebian/) { $msg .= __ "\n ... debian/patches is missing; perhaps this is a patch queue branch?"; } @@ -5429,9 +5437,24 @@ sub quiltify_splitbrain ($$$$$$$) { but git tree differs from result of applying debian/patches to upstream END } - if ($quilt_mode =~ m/gbp|unapplied/ && + if ($quilt_mode =~ m/baredebian/) { + # We need to construct a merge which has upstream files from + # upstream and debian/ files from HEAD. + + read_tree_upstream $quilt_upstream_commitish, 1, $headref; + my $version = getfield $clogp, 'Version'; + my $upsversion = upstreamversion $version; + my $merge = make_commit + [ $headref, $quilt_upstream_commitish ], + [ +(f_ <{O2A} & 01)) { # some patches - quiltify_splitbrain_needed(); progress __ "dgit view: creating patches-applied version using gbp pq"; runcmd shell_cmd 'exec >/dev/null', gbp_pq, qw(import); # gbp pq import creates a fresh branch; push back to dgit-view @@ -5448,7 +5471,6 @@ END } if (($diffbits->{O2H} & 02) && # user has modified .gitignore !($diffbits->{O2A} & 02)) { # patches do not change .gitignore - quiltify_splitbrain_needed(); progress __ "dgit view: creating patch to represent .gitignore changes"; ensuredir "debian/patches"; @@ -5488,16 +5510,6 @@ END [dgit ($our_version) update-gitignore-quilt-fixup] ENDU } - - my $dgitview = git_rev_parse 'HEAD'; - - changedir $maindir; - reflog_cache_insert "refs/$splitbraincache", $cachekey, $dgitview; - - changedir "$playground/work"; - - my $saved = maybe_split_brain_save $headref, $dgitview, __ "converted"; - progress f_ "dgit view: created (%s)", $saved; } sub quiltify ($$$$) { @@ -5778,8 +5790,6 @@ sub quiltify ($$$$) { runcmd @git, qw(checkout -q), $cc, qw(debian/changelog); } - - runcmd @git, qw(checkout -q master); } sub build_maybe_quilt_fixup () { @@ -5789,55 +5799,60 @@ sub build_maybe_quilt_fixup () { check_for_vendor_patches(); - if (quiltmode_splitbrain) { - fail <{'single-debian-patch'} - && branch_is_gdr($headref)) { - # This is much faster. It also makes patches that gdr - # likes better for future updates without laundering. - # - # However, it can fail in some casses where we would - # succeed: if there are existing patches, which correspond - # to a prefix of the branch, but are not in gbp/gdr - # format, gdr will fail (exiting status 7), but we might - # be able to figure out where to start linearising. That - # will be slower so hopefully there's not much to do. - my @cmd = (@git_debrebase, - qw(--noop-ok -funclean-mixed -funclean-ordering - 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 not ($? == 7*256 or - $? == -1 && $!==ENOENT); - } else { - dryrun_report @cmd; - } - $headref = git_rev_parse('HEAD'); - } + my $upstreamversion = upstreamversion $version; prep_ud(); changedir $playground; - my $upstreamversion = upstreamversion $version; + my $splitbrain_cachekey; + + if (do_split_brain()) { + my $cachehit; + ($cachehit, $splitbrain_cachekey) = + quilt_check_splitbrain_cache($headref, $upstreamversion); + if ($cachehit) { + changedir $maindir; + return; + } + } + + unpack_playtree_need_cd_work($headref); + if (do_split_brain()) { + runcmd @git, qw(checkout -q -b dgit-view); + # so long as work is not deleted, its current branch will + # remain dgit-view, rather than master, so subsequent calls to + # unpack_playtree_need_cd_work + # will DTRT, resetting dgit-view. + confess if $made_split_brain; + $made_split_brain = 1; + } + chdir '..'; if ($fopts->{'single-debian-patch'}) { + fail f_ + "quilt mode %s does not make sense (or is not supported) with single-debian-patch", + $quilt_mode + if quiltmode_splitting(); quilt_fixup_singlepatch($clogp, $headref, $upstreamversion); } else { - quilt_fixup_multipatch($clogp, $headref, $upstreamversion); + quilt_fixup_multipatch($clogp, $headref, $upstreamversion, + $splitbrain_cachekey); + } + + if (do_split_brain()) { + my $dgitview = git_rev_parse 'HEAD'; + + changedir $maindir; + reflog_cache_insert "refs/$splitbraincache", + $splitbrain_cachekey, $dgitview; + + changedir "$playground/work"; + + my $saved = maybe_split_brain_save $headref, $dgitview, __ "converted"; + progress f_ "dgit view: created (%s)", $saved; } changedir $maindir; @@ -5845,12 +5860,22 @@ END @git, qw(pull --ff-only -q), "$playground/work", qw(master); } -sub unpack_playtree_mkwork ($) { +sub build_check_quilt_splitbrain () { + build_maybe_quilt_fixup(); +} + +sub unpack_playtree_need_cd_work ($) { my ($headref) = @_; - mkdir "work" or confess "$!"; - changedir "work"; - mktree_in_ud_here(); + # prep_ud() must have been called already. + if (!chdir "work") { + # Check in the filesystem because sometimes we run prep_ud + # in between multiple calls to unpack_playtree_need_cd_work. + confess "$!" unless $!==ENOENT; + mkdir "work" or confess "$!"; + changedir "work"; + mktree_in_ud_here(); + } runcmd @git, qw(reset -q --hard), $headref; } @@ -5899,7 +5924,7 @@ sub quilt_fixup_singlepatch ($$$) { # necessary to build the source package. unpack_playtree_linkorigs($upstreamversion, sub { }); - unpack_playtree_mkwork($headref); + unpack_playtree_need_cd_work($headref); rmtree("debian/patches"); @@ -5915,9 +5940,14 @@ sub quilt_fixup_singlepatch ($$$) { commit_quilty_patch(); } -sub quilt_make_fake_dsc ($) { +sub quilt_need_fake_dsc ($) { + # cwd should be playground my ($upstreamversion) = @_; + return if stat_exists "fake.dsc"; + # ^ OK to test this as a sentinel because if we created it + # we must either have done the rest too, or crashed. + my $fakeversion="$upstreamversion-~~DGITFAKE"; my $fakedsc=new IO::File 'fake.dsc', '>' or confess "$!"; @@ -5961,8 +5991,9 @@ END sub quilt_fakedsc2unapplied ($$) { my ($headref, $upstreamversion) = @_; # must be run in the playground - # quilt_make_fake_dsc must have been called + # quilt_need_fake_dsc must have been called + quilt_need_fake_dsc($upstreamversion); runcmd qw(sh -ec), 'exec dpkg-source --no-check --skip-patches -x fake.dsc >/dev/null'; @@ -5990,6 +6021,8 @@ sub quilt_check_splitbrain_cache ($$) { # Computes the cache key and looks in the cache. # Returns ($dgit_view_commitid, $cachekey) or (undef, $cachekey) + quilt_need_fake_dsc($upstreamversion); + my $splitbrain_cachekey; progress f_ @@ -6001,6 +6034,7 @@ sub quilt_check_splitbrain_cache ($$) { push @cachekey, $upstreamversion; push @cachekey, $quilt_mode; push @cachekey, $headref; + push @cachekey, $quilt_upstream_commitish // '-'; push @cachekey, hashfile('fake.dsc'); @@ -6021,12 +6055,12 @@ sub quilt_check_splitbrain_cache ($$) { "refs/$splitbraincache", $splitbrain_cachekey; if ($cachehit) { - unpack_playtree_mkwork($headref); + unpack_playtree_need_cd_work($headref); my $saved = maybe_split_brain_save $headref, $cachehit, "cache-hit"; if ($cachehit ne $headref) { progress f_ "dgit view: found cached (%s)", $saved; runcmd @git, qw(checkout -q -b dgit-view), $cachehit; - $split_brain = 1; + $made_split_brain = 1; return ($cachehit, $splitbrain_cachekey); } progress __ "dgit view: found cached, no changes required"; @@ -6037,8 +6071,32 @@ sub quilt_check_splitbrain_cache ($$) { return (undef, $splitbrain_cachekey); } +sub baredebian_origtarballs_scan ($$$) { + my ($fakedfi, $upstreamversion, $dir) = @_; + if (!opendir OD, $dir) { + return if $! == ENOENT; + fail "opendir $dir (origs): $!"; + } + + while ($!=0, defined(my $leaf = readdir OD)) { + { + local ($debuglevel) = $debuglevel-1; + printdebug "BDOS $dir $leaf ?\n"; + } + next unless is_orig_file_of_vsn $leaf, $upstreamversion; + next if grep { $_->{Filename} eq $leaf } @$fakedfi; + push @$fakedfi, { + Filename => $leaf, + Path => "$dir/$leaf", + }; + } + + die "$dir; $!" if $!; + closedir OD; +} + sub quilt_fixup_multipatch ($$$) { - my ($clogp, $headref, $upstreamversion) = @_; + my ($clogp, $headref, $upstreamversion, $splitbrain_cachekey) = @_; progress f_ "examining quilt state (multiple patches, %s mode)", $quilt_mode; @@ -6112,16 +6170,39 @@ sub quilt_fixup_multipatch ($$$) { # afterwards with dpkg-source --before-build. That lets us save a # tree object corresponding to .origs. - my $splitbrain_cachekey; + if ($quilt_mode eq 'linear' + && branch_is_gdr($headref)) { + # This is much faster. It also makes patches that gdr + # likes better for future updates without laundering. + # + # However, it can fail in some casses where we would + # succeed: if there are existing patches, which correspond + # to a prefix of the branch, but are not in gbp/gdr + # format, gdr will fail (exiting status 7), but we might + # be able to figure out where to start linearising. That + # will be slower so hopefully there's not much to do. - quilt_make_fake_dsc($upstreamversion); + unpack_playtree_need_cd_work $headref; - if (quiltmode_splitbrain()) { - my $cachehit; - ($cachehit, $splitbrain_cachekey) = - quilt_check_splitbrain_cache($headref, $upstreamversion); - return if $cachehit; + my @cmd = (@git_debrebase, + qw(--noop-ok -funclean-mixed -funclean-ordering + 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 not ($? == 7*256 or + $? == -1 && $!==ENOENT); + } else { + dryrun_report @cmd; + } + $headref = git_rev_parse('HEAD'); + + chdir '..'; } + my $unapplied=quilt_fakedsc2unapplied($headref, $upstreamversion); ensuredir '.pc'; @@ -6140,7 +6221,7 @@ END changedir '..'; - unpack_playtree_mkwork($headref); + unpack_playtree_need_cd_work($headref); my $mustdeletepc=0; if (stat_exists ".pc") { @@ -6161,15 +6242,97 @@ END # We calculate some guesswork now about what kind of tree this might # be. This is mostly for error reporting. + my $tentries = cmdoutput @git, qw(ls-tree --name-only -z), $headref; + my $onlydebian = $tentries eq "debian\0"; + + my $uheadref = $headref; + my $uhead_whatshort = 'HEAD'; + + if ($quilt_mode =~ m/baredebian\+tarball/) { + # We need to make a tarball import. Yuk. + # We want to do this here so that we have a $uheadref value + + my @fakedfi; + baredebian_origtarballs_scan \@fakedfi, $upstreamversion, bpd_abs(); + baredebian_origtarballs_scan \@fakedfi, $upstreamversion, + "$maindir/.." unless $buildproductsdir eq '..'; + changedir '..'; + + my @tartrees = import_tarball_tartrees $upstreamversion, \@fakedfi; + + fail __ "baredebian quilt fixup: could not find any origs" + unless @tartrees; + + changedir 'work'; + my ($authline, $r1authline, $clogp,) = + import_tarball_commits \@tartrees, $upstreamversion; + + if (@tartrees == 1) { + $uheadref = $tartrees[0]{Commit}; + # TRANSLATORS: this translation must fit in the ASCII art + # quilt differences display. The untranslated display + # says %9.9s, so with that display it must be at most 9 + # characters. + $uhead_whatshort = __ 'tarball'; + } else { + # on .dsc import we do not make a separate commit, but + # here we need to do so + rm_subdir_cached '.'; + my $parents; + foreach my $ti (@tartrees) { + my $c = $ti->{Commit}; + if ($ti->{OrigPart} eq 'orig') { + runcmd qw(git read-tree), $c; + } elsif ($ti->{OrigPart} =~ m/orig-/) { + read_tree_subdir $', $c; + } else { + confess "$ti->OrigPart} ?" + } + $parents .= "parent $c\n"; + } + my $tree = git_write_tree(); + my $mbody = f_ 'Combine orig tarballs for %s %s', + $package, $upstreamversion; + $uheadref = hash_commit_text < quiltify_trees_differ($unapplied,$headref, 1, + O2H => quiltify_trees_differ($unapplied,$uheadref, 1, \%editedignores, \@unrepres), - H2A => quiltify_trees_differ($headref, $oldtiptree,1), + H2A => quiltify_trees_differ($uheadref, $oldtiptree,1), O2A => quiltify_trees_differ($unapplied,$oldtiptree,1), }; @@ -6184,13 +6347,23 @@ END progress f_ "%s: base trees orig=%.20s o+d/p=%.20s", $us, $unapplied, $oldtiptree; + # TRANSLATORS: Try to keep this ascii-art layout right. The 0s in + # %9.00009s will be ignored and are there to make the format the + # same length (9 characters) as the output it generates. If you + # change the value 9, your translations of "upstream" and + # 'tarball' must fit into the new length, and you should change + # the number of 0s. Do not reduce it below 4 as HEAD has to fit + # too. progress f_ "%s: quilt differences: src: %s orig %s gitignores: %s orig %s\n". -"%s: quilt differences: HEAD %s o+d/p HEAD %s o+d/p", +"%s: quilt differences: %9.00009s %s o+d/p %9.00009s %s o+d/p", $us, $dl[0], $dl[1], $dl[3], $dl[4], - $us, $dl[2], $dl[5]; + $us, $uhead_whatshort, $dl[2], $uhead_whatshort, $dl[5]; - if (@unrepres) { + if (@unrepres && $quilt_mode !~ m/baredebian/) { + # With baredebian, even if the upstream commitish has this + # problem, we don't want to print this message, as nothing + # is going to try to make a patch out of it anyway. print STDERR f_ "dgit: cannot represent change: %s: %s\n", $_->[1], $_->[0] foreach @unrepres; @@ -6200,7 +6373,11 @@ END } my @failsuggestion; - if (!($diffbits->{O2H} & $diffbits->{O2A})) { + if ($onlydebian) { + push @failsuggestion, [ 'onlydebian', __ + "This has only a debian/ directory; you probably want --quilt=bare debian." ] + unless $quilt_mode =~ m/baredebian/; + } elsif (!($diffbits->{O2H} & $diffbits->{O2A})) { push @failsuggestion, [ 'unapplied', __ "This might be a patches-unapplied branch." ]; } elsif (!($diffbits->{H2A} & $diffbits->{O2A})) { @@ -6215,17 +6392,20 @@ END if stat_exists '.gitattributes'; push @failsuggestion, [ 'origs', __ - "Maybe orig tarball(s) are not identical to git representation?" ]; - - if (quiltmode_splitbrain()) { - quiltify_splitbrain($clogp, $unapplied, $headref, $oldtiptree, - $diffbits, \%editedignores, - $splitbrain_cachekey); + "Maybe orig tarball(s) are not identical to git representation?" ] + unless $onlydebian && $quilt_mode !~ m/baredebian/; + # ^ in that case, we didn't really look properly + + if (quiltmode_splitting()) { + quiltify_splitting($clogp, $unapplied, $headref, $oldtiptree, + $diffbits, \%editedignores, + $splitbrain_cachekey); return; } progress f_ "starting quiltify (multiple patches, %s mode)", $quilt_mode; quiltify($clogp,$headref,$oldtiptree,\@failsuggestion); + runcmd @git, qw(checkout -q), (qw(master dgit-view)[do_split_brain()]); if (!open P, '>>', ".pc/applied-patches") { $!==&ENOENT or confess "$!"; @@ -6260,7 +6440,7 @@ sub quilt_fixup_editor () { } sub maybe_apply_patches_dirtily () { - return unless $quilt_mode =~ m/gbp|unapplied/; + return unless $quilt_mode =~ m/gbp|unapplied|baredebian/; print STDERR __ < !$includedirty return !$includedirty; } @@ -6699,6 +6912,8 @@ sub build_source { unlink "$buildproductsdir/$sourcechanges" or $!==ENOENT or fail f_ "remove %s: %s", $sourcechanges, $!; } +# confess unless !!$made_split_brain == do_split_brain(); + my @cmd = (@dpkgsource, qw(-b --)); my $leafdir; if (building_source_in_playtree()) { @@ -6707,12 +6922,12 @@ sub build_source { # If we are in split brain, there is already a playtree with # the thing we should package into a .dsc (thanks to quilt # fixup). If not, make a playtree - prep_ud() unless $split_brain; + prep_ud() unless $made_split_brain; changedir $playground; - unless ($split_brain) { + unless ($made_split_brain) { my $upstreamversion = upstreamversion $version; unpack_playtree_linkorigs($upstreamversion, sub { }); - unpack_playtree_mkwork($headref); + unpack_playtree_need_cd_work($headref); changedir '..'; } } else { @@ -6779,7 +6994,7 @@ sub cmd_push_source { "dgit push-source: --include-dirty/--ignore-dirty does not make". "sense with push-source!" if $includedirty; - build_maybe_quilt_fixup(); + build_check_quilt_splitbrain(); if ($changesfile) { my $changes = parsecontrol("$buildproductsdir/$changesfile", __ "source changes file"); @@ -6878,7 +7093,6 @@ sub cmd_print_unapplied_treeish { prep_ud(); changedir $playground; my $uv = upstreamversion $version; - quilt_make_fake_dsc($uv); my $u = quilt_fakedsc2unapplied($headref, $uv); print $u, "\n" or confess "$!"; } @@ -7070,7 +7284,7 @@ END my $version = getfield $dsc, 'Version'; my $clogp = commit_getclogp $newhash; my $authline = clogp_authline $clogp; - $newhash = make_commit_text <I, where I is +the upstream version you plan to put in I. The +B prefix ensures that your tag will not clash with any tags +upstream later creates. + +For example, suppose that the latest upstream release is 1.2.2 and you +want to package git commit ab34c21 which was made on 2013-12-11. A +common convention is to use the upstream version number +1.2.2+git20131211.ab34c21 and so you could use + +=over 4 + + % git tag -s upstream/1.2.2+git20131211.ab34c21 ab34c21 + +=back + +to obtain a release tag, and then proceed as above. + +=back + =head2 When upstream releases only tarballs Because we want to work in git, we need a virtual upstream branch with @@ -331,6 +357,10 @@ release, and importing that release using git-debrebase(1). =back +If you want to package an untagged upstream commit (because upstream +does not tag releases or because you want to package an upstream +development snapshot), see "Using untagged upstream commits" above. + =head3 When upstream releases only tarballs You will need the I from "When upstream releases only @@ -375,9 +405,10 @@ release: =back -Pass I<--stat> just to see the list of changed files, which is useful -to determine whether there are any new or deleted files that may need -accounting for in your copyright file. +Also, diff with I<--name-status> and I<--diff-filter=ADR> to see +just the list of added or removed files, which is useful to determine +whether there are any new or deleted files that may need accounting +for in your copyright file. If you obtained a tarball from upstream, you are ready to try a build. If you merged a git tag from upstream, you will first need to generate diff --git a/dgit-maint-merge.7.pod b/dgit-maint-merge.7.pod index c20a2525..0ccd8c7e 100644 --- a/dgit-maint-merge.7.pod +++ b/dgit-maint-merge.7.pod @@ -120,6 +120,32 @@ upstream's tarball instead of running git-deborig(1). =back +=head3 Using untagged upstream commits + +=over 4 + +Sometimes upstream does not tag their releases, or you want to package +an unreleased git snapshot. In such a case you can create your own +upstream release tag, of the form BI, where I is +the upstream version you plan to put in I. The +B prefix ensures that your tag will not clash with any tags +upstream later creates. + +For example, suppose that the latest upstream release is 1.2.2 and you +want to package git commit ab34c21 which was made on 2013-12-11. A +common convention is to use the upstream version number +1.2.2+git20131211.ab34c21 and so you could use + +=over 4 + + % git tag -s upstream/1.2.2+git20131211.ab34c21 ab34c21 + +=back + +to obtain a release tag, and then proceed as above. + +=back + =head2 When upstream releases only tarballs We need a virtual upstream branch with virtual release tags. @@ -340,6 +366,10 @@ to git), you can just run dpkg-buildpackage(1) or debuild(1) instead. =back +If you want to package an untagged upstream commit (because upstream +does not tag releases or because you want to package an upstream +development snapshot), see "Using untagged upstream commits" above. + =head3 When upstream releases only tarballs You will need the I from "When upstream releases only @@ -371,7 +401,7 @@ accounting for in your copyright file: =over 4 - % git diff --stat master..1.2.3 -- . ':!debian' + % git diff --name-status --diff-filter=ADR master..1.2.3 -- . ':!debian' =back diff --git a/dgit.1 b/dgit.1 index 682562ca..6e0c4f11 100644 --- a/dgit.1 +++ b/dgit.1 @@ -642,6 +642,18 @@ include the changes from your working tree. This can be useful with build, if you plan to commit later. (dgit push will still ensure that the .dsc you upload and the git tree you push are identical, so this option won't make broken pushes.) + +Note that this does +.BR not +prevent dgit from cleaning your tree, so if the changes in your +working tree are in the form of untracked files, those might still be +deleted, especially with --clean=git. +If you want to include untracked files in the build, you can +use --clean=none or --clean=dpkg-source[-d] +in addition to --include-dirty. +Note that this +combination can fail if the untracked files are under +\fIdebian/patches/\fR. .TP .BR --ignore-dirty Deprecated alias for --include-dirty. @@ -695,7 +707,7 @@ of git merge -s ours) to stitch the archive's version into your own git history, so that your push is a fast forward from the archive. (In quilt mode -.BR gbp ", " dpm " or " unpatched , +.BR gbp ", " dpm ", " unpatched " or " baredebian *, implying a split between the dgit view and the maintainer view, the pseudo-merge will appear only in the dgit view.) .TP @@ -742,7 +754,7 @@ it can mean that dgit fails to find necessary git commits. .TP .BR \-\-save-dgit-view= \fIbranch\fR|\fIref\fR -Specifies that when a split view quilt mode is in operation, +Specifies that when split view is in operation, and dgit calculates (or looks up in its cache) a dgit view corresponding to your HEAD, @@ -753,10 +765,7 @@ so don't specify a branch you want to keep. This option is effective only with the following operations: quilt-fixup; push; all builds. -And it is only effective with -\-\-[quilt=]gbp, -\-\-[quilt=]dpm, -\-\-quilt=unpatched. +And it is only effective when split view is actually in operation. If ref does not start with refs/ it is taken to be a branch - @@ -786,7 +795,7 @@ Debian, use this when you are making a renewed upload of an entirely new source package whose previous version was not accepted for release from NEW because of problems with copyright or redistributibility. -In split view quilt modes, +When split view is in operation, this also prevents the construction by dgit of a pseudomerge to make the dgit view fast forwarding. Normally only one of @@ -856,13 +865,17 @@ Do not check whether source format `3.0 (quilt)' metadata needs fixing up. If you use this option and the metadata did in fact need fixing up, dgit push will fail. .TP -.BR -- [ quilt= ] gbp " | " -- [ quilt= ] dpm " | " --quilt=unapplied +.BR -- [ quilt= ] gbp " | " -- [ quilt= ] dpm " | " --quilt=unapplied " | " -- [ quilt= ] baredebian [ +git | +tarball ] Tell dgit that you are using a nearly-dgit-compatible git branch, aka a .BR "maintainer view" , and do not want your branch changed by dgit. +These quilt modes are known as +.BR "splitting quilt modes" . +See --split-view, below. + .B --gbp (short for .BR --quilt=gbp ) @@ -884,7 +897,32 @@ specifies that your HEAD is a patches-unapplied git branch (and that any changes to upstream .gitignore files are represented as patches in debian/patches). -With --quilt=gbp|dpm|unapplied, +.B --quilt=baredebian +(or its alias +.BR --quilt=baredebian+git ) +specifies that your HEAD contains only a debian/ directory, +with any changes to upstream files represented as +patches in debian/patches. +The upstream source must be available in git, +by default, in a suitably named git tag; +see --upstream-commitish. +In this mode, dgit cannot check that +all edited upstream files are properly represented as patches: +dgit relies on +debian/patches being correct. + +.B --quilt=baredebian+tarball +is like --quilt=baredebian, +but is used when there is no appropriate upstream git history. +To construct the dgit view, +dgit will import your orig tarballs' contents into git. +In this mode, dgit cannot check that +the upstream parts of your upload correspond to what you intend: +dgit relies on +the right orig tarball(s) existing, and +debian/patches being correct. + +With --quilt=gbp|dpm|unapplied|baredebian*, dgit push (or precursors like quilt-fixup and build) will automatically generate a conversion of your git branch into the right form. dgit push will push the @@ -931,6 +969,42 @@ for fetching (and, for dgit push, altering) a variety of information both in the archive and in dgit-repos. How to set this up is not yet documented. .TP +.BR \-\-split-view=auto | always | never +Controls whether dgit operates a split view, +separating your own branch (as Debian maintainer) +from that shown to users of dgit clone and dgit fetch. + +When split view is in operation +dgit will not make or merge any commits onto your own branch. +Specifically, only the dgit view will contain +dgit's pseudomerges, +which bring into the git history previous uploads made with dgit push, +and any commits in debian/patches required +to make a correct `3.0 (quilt)' source package. + +.B auto +is the default, and splits the view only when needed: +i.e., when you are working with a `3.0 (quilt)' source package +and a splitting quilt mode: +\-\-[quilt=]gbp, dpm, unpatched or baredebian*. + +.B always +splits the view regardless of the source format and the quilt mode. + +.B never +will cause dgit to fail if split view is needed. + +When split view is in operation, the dgit view is visible +in your local git clone, +but only in refs specific to dgit: +notably +.BI remotes/dgit/dgit/ suite +and +.BR archive/ \fIdistro\fR / \fIversion\fR. + +Note that split view does not affect dgit fetch, +and is not compatible with dgit pull. +.TP .BI \-C changesfile Specifies the .changes file which is to be uploaded. By default dgit push looks for a single .changes file in the parent directory whose @@ -945,6 +1019,14 @@ otherwise, the changes file is expected in that directory (by default, in .BR .. ). .TP +.BI \-\-upstream-commitish= upstream +For use with --quilt=baredebian only. +Specifies the commit containing the upstream source. +This commit must be identical to your .orig tarball. +The default is to look for one of the git tags +.IB U " v" U " upstream/" U +(in that order), where U is the upstream version. +.TP .B \-\-rm-old-changes When doing a build, delete any changes files matching .IB package _ version _*.changes @@ -983,19 +1065,14 @@ Do not delete the destination directory if clone fails. Generates a DEP-14 tag (eg .BR debian/ \fIversion\fR) as well as a dgit tag (eg -.BR archive/debian/ \fIversion\fR) -where possible. This is the default. +.BR archive/debian/ \fIversion\fR). +This is the default. .TP .BI --no-dep14tag -Do not generate a DEP-14 tag, except in split quilt view mode. -(On servers where only the old tag format is supported, -the dgit tag will have the DEP-14 name. -This option does not prevent that.) +Do not generate a DEP-14 tag, except when split view is in operation. .TP -.BI --dep14tag-always -Insist on generating a DEP-14 tag -as well as a dgit tag. -If the server does not support that, dgit push will fail. +.BI --always-dep14tag +Obsolete alias for --dep14tag, retained for compatibility. .TP .BI -D Prints debugging information to stderr. Repeating the option produces @@ -1298,6 +1375,8 @@ to provide a single git config compatible with different dgit versions. One of the values for the command line \-\-quilt= option; used if \-\-quilt is not specified. .TP +.BR dgit-distro. \fIdistro\fR .split-view +.TP .BR dgit-distro. \fIdistro\fR .rm-old-changes Boolean, used if neither \-\-rm-old-changes nor \-\-no-rm-old-changes is specified. The default is not to remove. @@ -1402,7 +1481,7 @@ or when pushing and .TP .BI dgit-distro. distro .dgit-tag-format .TP -.BR dgit-distro. \fIdistro\fR .dep14tag " " want | no | always +.BR dgit-distro. \fIdistro\fR .dep14tag " " want | no [| always ] .TP .BI dgit-distro. distro .ssh .TP diff --git a/dgit.7 b/dgit.7 index 8325c06b..d1e5c7ea 100644 --- a/dgit.7 +++ b/dgit.7 @@ -393,7 +393,7 @@ this problem can occur if you have provided Debian git tooling such as git-debrebase, git-dpm or git-buildpackage with upstream git commit(s) or tag(s) which are not 100% identical to your orig tarball(s). -.SH SPLIT VIEW QUILT MODE +.SH SPLIT VIEW AND SPLITTING QUILT MODES When working with git branches intended for use with the `3.0 (quilt)' source format dgit can automatically convert a suitable @@ -401,21 +401,33 @@ maintainer-provided git branch (in one of a variety of formats) into a dgit branch. -When a split view mode is engaged +When a splitting quilt mode is selected dgit build commands and dgit push will, on each invocation, convert the user's HEAD into the dgit view, so that it can be built and/or uploaded. -dgit push in split view mode will push the dgit view to the dgit +Split view mode can also be enabled explicitly +with +the --split-view command line option +and +the .split-view access configuration key. + +When split view is in operation, +regardless of the quilt mode, +any dgit-generated pseudomerges +and any quilt fixup commits +will appear only in the dgit view. +dgit push +will push the dgit view to the dgit git server. The dgit view is always a descendant of the maintainer view. dgit push will also make a maintainer view tag according to DEP-14 and push that to the dgit git server. -Split view mode must be enabled explicitly +Splitting quilt modes must be enabled explicitly (by the use of the applicable command line options, subcommands, or configuration). This is because it is not possible to reliably tell diff --git a/git-debrebase b/git-debrebase index 71bf39dc..01429fb4 100755 --- a/git-debrebase +++ b/git-debrebase @@ -355,44 +355,6 @@ sub calculate_committer_authline () { return $&; } -sub rm_subdir_cached ($) { - my ($subdir) = @_; - runcmd @git, qw(rm --quiet -rf --cached --ignore-unmatch), $subdir; -} - -sub read_tree_subdir ($$) { - my ($subdir, $new_tree_object) = @_; - rm_subdir_cached $subdir; - runcmd @git, qw(read-tree), "--prefix=$subdir/", $new_tree_object; -} - -sub read_tree_debian ($) { - my ($treeish) = @_; - read_tree_subdir 'debian', "$treeish:debian"; - rm_subdir_cached 'debian/patches'; -} - -sub read_tree_upstream ($;$$) { - my ($treeish, $keep_patches, $tree_with_debian) = @_; - # if $tree_with_debian is supplied, will use that for debian/ - # otherwise will save and restore it. - my $debian = - $tree_with_debian ? "$tree_with_debian:debian" - : cmdoutput @git, qw(write-tree --prefix=debian/); - runcmd @git, qw(read-tree), $treeish; - read_tree_subdir 'debian', $debian; - rm_subdir_cached 'debian/patches' unless $keep_patches; -}; - -sub make_commit ($$) { - my ($parents, $message_paras) = @_; - my $tree = cmdoutput @git, qw(write-tree); - my @cmd = (@git, qw(commit-tree), $tree); - push @cmd, qw(-p), $_ foreach @$parents; - push @cmd, qw(-m), $_ foreach @$message_paras; - return cmdoutput @cmd; -} - our @snag_force_opts; sub snag ($$;@) { my ($tag,$msg) = @_; # ignores extra args, for benefit of keycommits @@ -768,7 +730,7 @@ sub merge_series_patchqueue_convert ($$$) { open C, ">", "../mcommit" or confess "$!"; print C $commit or confess "$!"; close C or confess "$!"; - $build = cmdoutput @git, qw(hash-object -w -t commit ../mcommit); + $build = hash_commit '../mcommit'; } $result = $build; mwrecknote($wrecknotes, 'merged-result', $result); @@ -1994,39 +1956,6 @@ sub do_stitch ($;$) { stitch($dangling_head, $ffq_prev, $gdrlast, $ffq_prev_commitish, $prose); } -sub upstream_commitish_search ($$) { - my ($upstream_version, $tried) = @_; - # todo: at some point maybe use git-deborig to do this - foreach my $tagpfx ('', 'v', 'upstream/') { - my $tag = $tagpfx.(dep14_version_mangle $upstream_version); - my $new_upstream = git_get_ref "refs/tags/$tag"; - push @$tried, $tag; - return $new_upstream if length $new_upstream; - } -} - -sub resolve_upstream_version ($$) { - my ($new_upstream, $upstream_version) = @_; - - my $used = $new_upstream; - if (!defined $new_upstream) { - my @tried; - $new_upstream = upstream_commitish_search $upstream_version, \@tried; - if (!length $new_upstream) { - fail f_ - "Could not determine appropriate upstream commitish.\n". - " (Tried these tags: %s)\n". - " Check version, and specify upstream commitish explicitly.", - "@tried"; - } - $used = $tried[-1]; - } - $new_upstream = git_rev_parse $new_upstream; - - return ($new_upstream, $used); - # used is a human-readable idea of what we found -} - sub cmd_new_upstream () { # automatically and unconditionally launders before rebasing # if rebase --abort is used, laundering has still been done @@ -2733,7 +2662,7 @@ sub cmd_convert_from_dgit_view () { my $spec = shift @ARGV; my $commit = git_rev_parse "$spec^{commit}"; push @upstreams, { Commit => $commit, - Source => (f_ "%s, from command line", $ARGV[0]), + Source => (f_ "%s, from command line", $spec), Only => 1, }; } diff --git a/git-debrebase.1.pod b/git-debrebase.1.pod index cbdf292b..af6e3646 100644 --- a/git-debrebase.1.pod +++ b/git-debrebase.1.pod @@ -531,7 +531,7 @@ This is provided mostly for the benefit of the test suite. Requests (more) debugging. May be repeated. -=item --experimntal-merge-resolution +=item --experimental-merge-resolution Enable experimental code for handling general merges (see L). diff --git a/infra/dgit-repos-policy-debian b/infra/dgit-repos-policy-debian index f7e5e53b..bc370d27 100755 --- a/infra/dgit-repos-policy-debian +++ b/infra/dgit-repos-policy-debian @@ -546,6 +546,7 @@ for (;;) { die unless defined $rcode; $poldbh->commit; + printdebug "poldbh commit\n"; }; last unless length $@; die $@ unless ref $@ eq $db_busy_exception; diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index a8b9400b..7c7262f5 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -539,15 +539,12 @@ sub readupdates () { STDIN->error and die $!; reject "push is missing tag ref update" unless %tags; - my @newtags = grep { m#^archive/# } keys %tags; - my @omtags = grep { !m#^archive/# } keys %tags; - reject "pushing too many similar tags" if @newtags>1 || @omtags>1; - if (@newtags) { - ($tagname) = @newtags; - ($maint_tagname) = @omtags; - } else { - ($tagname) = @omtags or die; - } + my @dtags = grep { m#^archive/# } keys %tags; + reject "need exactly one archive/* tag" if @dtags!=1; + my @mtags = grep { !m#^archive/# } keys %tags; + reject "pushing too many non-dgit tags" if @mtags>1; + ($tagname) = @dtags; + ($maint_tagname) = @mtags; $tagval = $tags{$tagname}; $maint_tagval = $tags{$maint_tagname // ''}; @@ -862,8 +859,7 @@ sub checks () { grep { $tagname eq $_ } @expecttagnames or die; foreach my $othertag (grep { $_ ne $tagname } @expecttagnames) { - reject "tag $othertag (pushed with differing dgit version)". - " already exists -". + reject "tag $othertag already exists -". " not replacing previously-pushed version" if git_get_ref "refs/tags/".$othertag; } diff --git a/tests/enumerate-tests b/tests/enumerate-tests index a532b526..8ee34bec 100755 --- a/tests/enumerate-tests +++ b/tests/enumerate-tests @@ -52,6 +52,9 @@ restriction-gencontrol () { gencontrol-add-deps () { for dep in "$@"; do + case " $dependencies," in + *" "$dep","*) continue ;; + esac dependencies+="${dependencies:+, }$dep" done } @@ -64,6 +67,13 @@ dependencies-gencontrol () { GDR) gencontrol-add-deps \ git-debrebase git-buildpackage ;; + DEBORIG) gencontrol-add-deps \ + devscripts libdpkg-perl \ + libgit-wrapper-perl liblist-compare-perl \ + libstring-shellquote-perl libtry-tiny-perl \ + # NB git-deborig is not compatible with + # t-tstunt-parsechangelog + ;; *) gencontrol-add-deps "$dep" ;; esac done @@ -104,21 +114,29 @@ finish-gencontrol () { seddery () { local seddery=$1 - sed <$t -n ' + sed <$tf -n ' 20q; /^: t-enumerate-tests-end$/q; '"$seddery"' ' } -for t in $(run-parts --list tests/tests); do - test-begin-$mode +allsedderies () { + local tf=$1 for r in $(seddery 's/^t-restrict //p'); do restriction-$mode done for deps in $(seddery 's/^t-dependencies //p'); do dependencies-$mode done + for import in $(seddery 's/^t-setup-import //p'); do + allsedderies tests/setup/$import + done +} + +for t in $(run-parts --list tests/tests); do + test-begin-$mode + allsedderies $t test-done-$mode done diff --git a/tests/lib b/tests/lib index fa553af9..28b08e61 100644 --- a/tests/lib +++ b/tests/lib @@ -520,6 +520,14 @@ t-setup-done () { ' $vn "$(eval "printf '%s\n' \"\$$vn\"")" done + perl >&4 -"I$root" -MDebian::Dgit -we ' + foreach my $vn (grep m/^DGIT_TEST_REAL_/, keys %ENV) { + print STDERR "saving-exporting $vn\n"; + printf "export %s=%s\n", $vn, shellquote $ENV{$vn} + or die $!; + } + ' + (set -e; cd $tmp; tar cf $import.tar $savedirs) printf >&4 "\n%s\n" "$importeval" @@ -736,6 +744,7 @@ t-splitbrain-pushed-good--unpack () { ln -s $tmp/incoming/*.orig*.tar* . ||: ln -s $incoming_dsc . ln -s ${incoming_dsc/.dsc/.debian.tar}* . + ln -s ${incoming_dsc/.dsc/.tar}* . ||: dpkg-source "$@" -x *.dsc cd */. git init @@ -782,16 +791,21 @@ t-splitbrain-pushed-good-end-made-dep14 () { cd $tmp/$p } -t-splitbrain-rm-gitignore-patch () { +t-splitbrain-rm-1-patch () { + local patchname=$1 perl -i -pe ' - next unless $_ eq "auto-gitignore\n"; + next unless $_ eq "'"$patchname"'\n"; die if $counter++; chomp; - rename "debian/patches/$_", "../t-auto-gitignore" or die $!; + rename "debian/patches/$_", "../t-'"$patchname"'" or die $!; $_ = ""; ' debian/patches/series } +t-splitbrain-rm-gitignore-patch () { + t-splitbrain-rm-1-patch auto-gitignore +} + t-gbp-pushed-good () { local suite=${1:-sid} t-splitbrain-pushed-good-start @@ -826,18 +840,27 @@ t-gbp-pushed-good () { } t-unapplied-pushed-good () { + local suite=${1:-sid} t-splitbrain-pushed-good-start t-splitbrain-pushed-good--unpack --skip-patches t-splitbrain-pushed-good-end-made-dep14 } t-dpm-pushed-good () { + local suite=${1:-sid} t-splitbrain-pushed-good-start t-splitbrain-pushed-good--unpack t-splitbrain-rm-gitignore-patch t-splitbrain-pushed-good-end-made-dep14 } +t-split-unchanged-pushed-good () { + local suite=${1:-sid} + t-splitbrain-pushed-good-start + t-splitbrain-pushed-good--unpack + t-splitbrain-pushed-good-end-made-dep14 +} + t-commit-build-push-expect-log () { local msg=$1 local mpat=$2 @@ -1092,7 +1115,6 @@ t-drs () { t-git-config dgit-distro.test-dummy.git-url "ext::$troot/drs-git-ext %S " t-git-config dgit-distro.test-dummy.git-check true t-git-config dgit-distro.test-dummy.git-create true - t-git-config dgit-distro.test-dummy.dgit-tag-format new,old,maint cp $troot/gnupg/{dd.gpg,dm.gpg,dm.txt} $tmp/. cp $troot/suites $tmp/. cp $troot/suites $tmp/suites-master @@ -1114,15 +1136,6 @@ t-drs () { ln -sf /bin/true $drs_dispatch/policy-hook } -t-newtag () { - export tagpfx=archive/test-dummy - t-git-config dgit-distro.test-dummy.dgit-tag-format new,maint -} -t-oldtag () { - export tagpfx=test-dummy - t-git-config dgit-distro.test-dummy.dgit-tag-format old -} - t-dsd () { t-drs t-git-config dgit-distro.test-dummy.ssh "$troot/dsd-ssh" diff --git a/tests/lib-baredebian b/tests/lib-baredebian new file mode 100644 index 00000000..3ef6569d --- /dev/null +++ b/tests/lib-baredebian @@ -0,0 +1,93 @@ +# + +baredebian-test-vars () { + quiltmode=baredebian + v=1.0-1 + suite=sid + uv=${v%-*} + uvtag=v$uv + origbase=${p}_${uv}.orig + xorigcomps='' +} + +baredebian-tarball-mode () { + git tag -d $uvtag + uvtag='' + quiltmode=baredebian+tarball +} + +baredebian-test-minimum () { + t-expect-fail 'contradicts clean mode git-ff' \ + t-dgit -wgf --dgit-view-save=split.f1 --$quiltmode quilt-fixup + + t-dgit -wn --dgit-view-save=split.f1 --$quiltmode quilt-fixup +} + +baredebian-test-core () { + tar --strip-components=1 -axf ../$origbase.tar.* + for comp in $xorigcomps; do + mkdir $comp + cd $comp + tar --strip-components=1 -axf ../../$origbase-$comp.tar.* + cd .. + done + + cd debian + git clean -xdff + git checkout HEAD -- . + cd .. + + # Now we are in this insane state that people seem to expect + + export QUILT_PATCHES=debian/patches + quilt push -a + + git add -Af . + git reset .pc + git diff --cached --exit-code split.f1 -- :/ :!/debian + git diff --exit-code HEAD..split.f1 -- :/debian + git reset + + quilt new made-with-quilt + quilt add src.c + echo //omg >>src.c + quilt refresh + + git add debian/patches/. + t-commit 'extra patch made with quilt' 1.0-2 + + dpkg-buildpackage -uc -us --build=source + # ^ Do this by hand here not because we expect users to do this + # (rather than dgit build), but so that we can check that our + # output is the same as users are used to. + + t-dgit -wn --quilt=$quiltmode --dgit-view-save=split.b quilt-fixup + t-dgit -wn --quilt=$quiltmode --dgit-view-save=split.p --new push + + git merge-base --is-ancestor HEAD split.p + if [ "$uvtag" ]; then + git merge-base --is-ancestor $uvtag split.p + set +e; git merge-base HEAD $uvtag; rc=$?; set -e; [ $rc = 1 ] + fi + + git clean -xdff + # t-pushed-good-* wants a clean tree to start with, but this + # workflow expects a mess + + t-splitbrain-pushed-good-start + t-splitbrain-pushed-good--unpack + + find . -mindepth 1 -maxdepth 1 \ + \! -path ./debian \ + \! -path ./.git \ + -print0 \ + | xargs -0r rm -rf -- + + t-splitbrain-pushed-good-end-made-dep14 +} + +baredebian-test () { + baredebian-test-vars + baredebian-test-minimum + baredebian-test-core +} diff --git a/tests/setup/baredebian b/tests/setup/baredebian new file mode 100755 index 00000000..bbd901f6 --- /dev/null +++ b/tests/setup/baredebian @@ -0,0 +1,34 @@ +#!/bin/bash +set -e +. tests/lib +. $troot/lib-gdr + +t-dependencies GDR DEBORIG quilt + +t-archive-none example +t-git-none + +t-gdr-gbp-import-core-with-queue + +git-deborig + +for b in \ + patch-queue/quilt-tip \ + gitish-only \ + quilt-tip-1.1 \ + quilt-tip-2 \ + indep-arch \ +; do + git branch -D $b +done + +git rm -rf . # yikes +git checkout HEAD -- debian +t=$(git write-tree) +t=$(git commit-tree -m 'Convert to bare debian' $t) +git reset --hard $t + +t-setup-done '' "$(echo $p*) git mirror aq" ' + t-select-package example + t-git-next-date +' diff --git a/tests/tests/baredebian-multitar b/tests/tests/baredebian-multitar new file mode 100755 index 00000000..39b66685 --- /dev/null +++ b/tests/tests/baredebian-multitar @@ -0,0 +1,46 @@ +#!/bin/bash +set -e +. tests/lib +. $troot/lib-baredebian + +t-dependencies quilt + +t-setup-import baredebian +t-tstunt-parsechangelog + +cd $p +baredebian-test-vars +baredebian-tarball-mode + +rm -f ../example_1.0.orig.tar.* +cp $troot/pkg-srcs/${p}_${uv}.orig*.tar.* .. +xorigcomps=docs + +git tag -d $uvtag + +baredebian-test-minimum +baredebian-test-core + +combine=$( + git log --pretty=format:%H \ + --grep "Combine orig tarballs for example $uv" split.p +) + +parentnum=0 +for comp in '' $xorigcomps; do + parentnum=$(( $parentnum + 1 )) + fn=${origbase}${comp:+-}${comp}.tar.gz + + git checkout --orphan imp$parentnum + git rm -rf . + tar --strip-components=1 -axf ../$fn + git add -Af . + + git commit -m P$parentnum + git diff --stat --exit-code $combine^$parentnum + + count=$(git log $combine^$parentnum | grep -Fc $fn) + [ $count = 2 ] +done + +t-ok diff --git a/tests/tests/baredebian-plusgit b/tests/tests/baredebian-plusgit new file mode 100755 index 00000000..5c53fdd0 --- /dev/null +++ b/tests/tests/baredebian-plusgit @@ -0,0 +1,17 @@ +#!/bin/bash +set -e +. tests/lib +. $troot/lib-baredebian + +t-dependencies quilt + +t-setup-import baredebian +t-tstunt-parsechangelog + +cd $p +baredebian-test-vars +quiltmode=baredebian+git + +baredebian-test-minimum + +t-ok diff --git a/tests/tests/baredebian-push b/tests/tests/baredebian-push new file mode 100755 index 00000000..f0956012 --- /dev/null +++ b/tests/tests/baredebian-push @@ -0,0 +1,14 @@ +#!/bin/bash +set -e +. tests/lib +. $troot/lib-baredebian + +t-dependencies quilt + +t-setup-import baredebian +t-tstunt-parsechangelog + +cd $p +baredebian-test + +t-ok diff --git a/tests/tests/baredebian-tarball b/tests/tests/baredebian-tarball new file mode 100755 index 00000000..00b2ad29 --- /dev/null +++ b/tests/tests/baredebian-tarball @@ -0,0 +1,21 @@ +#!/bin/bash +set -e +. tests/lib +. $troot/lib-baredebian + +t-dependencies quilt + +t-setup-import baredebian +t-tstunt-parsechangelog + +cd $p +baredebian-test-vars +baredebian-tarball-mode + +t-expect-fail 'Could not determine appropriate upstream commitish' \ +t-dgit -wn --dgit-view-save=split.g --baredebian quilt-fixup + +baredebian-test-minimum +baredebian-test-core + +t-ok diff --git a/tests/tests/debpolicy-taintrm b/tests/tests/debpolicy-taintrm new file mode 100755 index 00000000..8655fb5d --- /dev/null +++ b/tests/tests/debpolicy-taintrm @@ -0,0 +1,58 @@ +#!/bin/bash +set -e +. tests/lib + +t-tstunt-parsechangelog + +t-debpolicy +t-prep-newpackage example 1.0 + +cd $p +revision=1 +git tag start +t-dgit setup-mergechangelogs + + +: upload + +t-dgit push-source --new + +: cut + +rm $tmp/incoming/* +t-archive-none example + +touch -d 'now -1 day' $tmp/git/example* + +t-policy-periodic # xxx maybe want test both with and without this + +: edit +t-commit 'edit after cut' + +: push, needs --deliberately + +t-expect-push-fail \ + 'all previously pushed versions were found to have been removed from NEW' \ +t-dgit push-source --new + +t-dgit push-source --new --deliberately-include-questionable-history + +t-archive-process-incoming new + +# : t-policy-periodic # maybe want test with this + +: accept + +mv -f $tmp/aq/package.{new,sid}.$p +t-aq-archive-updated sid $p + +# : t-policy-periodic # maybe want test with this + +t-git-dir-time-passes + +: 3rd push, no deliberately + +t-commit 'edit after accept' +t-dgit push-source + +t-ok diff --git a/tests/tests/drs-push-rejects b/tests/tests/drs-push-rejects index afaed4cf..f102d953 100755 --- a/tests/tests/drs-push-rejects +++ b/tests/tests/drs-push-rejects @@ -110,7 +110,7 @@ mustfail 'push is missing tag ref update' $push_spec1 mustfail 'push is missing head ref update' +$push_spec2 mustfail 'pushing unexpected ref' $push_spec HEAD:refs/wombat mustfail 'pushing multiple heads' $push_spec HEAD:refs/dgit/wombat -mustfail E:'pushing multiple tags|pushing too many similar tags' \ +mustfail E:'pushing multiple tags|pushing too many similar tags|need exactly one archive' \ $push_spec HEAD:refs/tags/$tagpfx/wombat prep unstable sid @@ -162,7 +162,6 @@ git commit --allow-empty -m 'Dummy update' mktag mustfail 'not replacing previously-pushed version' +$push_spec1 +$push_spec2 -t-newtag re-prep mktag mustfail 'not replacing previously-pushed version' +$push_spec1 +$push_spec2 diff --git a/tests/tests/forcesplit-linear b/tests/tests/forcesplit-linear new file mode 100755 index 00000000..4856d6ad --- /dev/null +++ b/tests/tests/forcesplit-linear @@ -0,0 +1,45 @@ +#!/bin/bash +set -e +. tests/lib + +t-tstunt-parsechangelog +t-buildproductsdir-config + +t-archive example 1.0-1 +t-select-package example +t-git-none + +t-dgit clone $p +cd $p + +echo '/* More patch */' >>src.c +git add src.c + +t-commit 'More patch' 1.0-2 + +t-refs-same-start +t-ref-head +t-dgit --split-view push-source +t-ref-head + + +t-commit 'More more patch' 1.0-3 + +t-dgit --split-view --save-dgit-view=split.b quilt-fixup + +git reflog expire --expire=all refs/dgit-intern/quilt-cache +test "x$(git reflog refs/dgit-intern/quilt-cache)" = x + +t-refs-same-start +t-ref-head +t-dgit --split-view --save-dgit-view=split.p push-source +t-ref-head + +suite=sid + +t-splitbrain-pushed-good-start +t-splitbrain-pushed-good--unpack +t-splitbrain-rm-1-patch more-patch.patch +t-splitbrain-pushed-good-end-made-dep14 + +t-ok diff --git a/tests/tests/forcesplit-overwrite b/tests/tests/forcesplit-overwrite new file mode 100755 index 00000000..9600d3a8 --- /dev/null +++ b/tests/tests/forcesplit-overwrite @@ -0,0 +1,37 @@ +#!/bin/bash +set -e +. tests/lib + +# This tests a native package with split view, including that the +# pseudomerges end up in the right place. + +t-setup-import examplegit + +t-select-package example +cd example + +suite=stable + +t-commit 'No changes, just send to stable' '' stable + +t-refs-same-start +t-ref-head + +try () { + t-dgit -wgf --split-view "$@" --dgit-view-save=split.p \ + push-source stable +} + +t-expect-fail E:'maintainer view tag.*not fast forward' \ +try + +t-expect-fail F:'debian/changelog does not mention 1.2' \ +try --overwrite + +try --overwrite=1.2 +git branch -f split.b split.p + +t-ref-head +t-split-unchanged-pushed-good $suite + +t-ok diff --git a/tests/tests/newtag-clone-nogit b/tests/tests/newtag-clone-nogit deleted file mode 100755 index 915f9d3f..00000000 --- a/tests/tests/newtag-clone-nogit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -e -. tests/lib -t-alt-test diff --git a/tests/tests/oldnewtagalt b/tests/tests/oldnewtagalt deleted file mode 100755 index 6730918b..00000000 --- a/tests/tests/oldnewtagalt +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e -. tests/lib - -t-setup-import examplegit -t-tstunt-parsechangelog - -cd $p - -test-push () { - t-commit "$1" - t-dgit -wgf build-source - t-dgit push -} - -for count in 1 2; do - t-oldtag - test-push "oldtag $count" - - t-newtag - test-push "newtag $count" -done - -t-ok - diff --git a/tests/tests/oldtag-clone-nogit b/tests/tests/oldtag-clone-nogit deleted file mode 100755 index 915f9d3f..00000000 --- a/tests/tests/oldtag-clone-nogit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -e -. tests/lib -t-alt-test diff --git a/tests/tests/overwrite-splitbrains b/tests/tests/overwrite-splitbrains index 06d1a987..815c207b 100755 --- a/tests/tests/overwrite-splitbrains +++ b/tests/tests/overwrite-splitbrains @@ -5,7 +5,6 @@ set -e t-tstunt-parsechangelog t-gbp-example-prep-no-ff -t-newtag t-dgit --quilt=gbp --dgit-view-save=split.b build-source diff --git a/tests/tests/quilt-gbp b/tests/tests/quilt-gbp index cf148f61..e502f6b2 100755 --- a/tests/tests/quilt-gbp +++ b/tests/tests/quilt-gbp @@ -25,11 +25,6 @@ t-gbp-example-prep t-expect-fail 'quilt fixup cannot be linear' \ t-dgit build-source -t-git-config dgit-distro.test-dummy.dgit-tag-format new -t-expect-fail 'requires split view so server needs to support' \ -t-dgit -wgf --quilt=gbp build-source -t-newtag - t-dgit --quilt=gbp --dgit-view-save=split.b1 build-source git rev-parse split.b1 diff --git a/tests/tests/quilt-splitbrains b/tests/tests/quilt-splitbrains index 6886cf89..f8d8091f 100755 --- a/tests/tests/quilt-splitbrains +++ b/tests/tests/quilt-splitbrains @@ -12,8 +12,6 @@ suitespecs+=' stable' t-tstunt-parsechangelog -t-newtag - # Easiest way to make a patches-unapplied but not-gbp tree is # to take the patches-unapplied tree and by-hand commit the .gitignore # changes as a debian patch. @@ -29,7 +27,7 @@ want-success () { t-dgit "$@" --quilt=$qmode --dgit-view-save=split.b build-source t-dgit "$@" --quilt=$qmode --dgit-view-save=split.p push - t-$qmode-pushed-good + t-$qmode-pushed-good $suite } diff --git a/tests/tests/rpush-quilt b/tests/tests/rpush-quilt index 10df9ae4..bb49fc61 100755 --- a/tests/tests/rpush-quilt +++ b/tests/tests/rpush-quilt @@ -4,8 +4,6 @@ set -e t-tstunt-parsechangelog -t-newtag - t-gbp-example-prep t-dgit -wgf --quilt=gbp --dgit-view-save=split.b build-source