our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|unapplied';
our $we_are_responder;
our $initiator_tempdir;
+our $patches_applied_dirtily = 00;
our %format_ok = map { $_=>1 } ("1.0","3.0 (native)","3.0 (quilt)");
'dpkg-source' => \@dpkgsource,
'dpkg-buildpackage' => \@dpkgbuildpackage,
'dpkg-genchanges' => \@dpkggenchanges,
+ 'gbp' => \@gbp,
'ch' => \@changesopts,
'mergechanges' => \@mergechanges);
my $cversion = getfield $clogp, 'Version';
progress "synthesised git commit from .dsc $cversion";
if ($lastpush_hash) {
- runcmd @git, qw(reset --hard), $lastpush_hash;
+ runcmd @git, qw(reset -q --hard), $lastpush_hash;
runcmd qw(sh -ec), 'dpkg-parsechangelog >>../changelogold.tmp';
my $oldclogp = parsecontrol('../changelogold.tmp','previous changelog');
my $oversion = getfield $oldclogp, 'Version';
sub madformat ($) {
my ($format) = @_;
return 0 unless $format eq '3.0 (quilt)';
+ our $quilt_mode_warned;
if ($quilt_mode eq 'nocheck') {
- progress "Not doing any fixup of \`$format' due to --no-quilt-fixup";
+ progress "Not doing any fixup of \`$format' due to".
+ " ----no-quilt-fixup or --quilt=nocheck"
+ unless $quilt_mode_warned++;
return 0;
}
- progress "Format \`$format', checking/updating patch stack";
+ progress "Format \`$format', need to check/update patch stack"
+ unless $quilt_mode_warned++;
return 1;
}
qw(-- debian/rules debian/control);
$r =~ s/\n/,/g;
return $r;
- }
+}
sub quiltify_splitbrain_needed () {
if (!$split_brain) {
- progress "creating dgit view";
+ progress "dgit view: changes are required...";
runcmd @git, qw(checkout -q -b dgit-view);
$split_brain = 1;
}
if ($quilt_mode =~ m/gbp|unapplied/ &&
($diffbits->{O2A} & 01)) { # some patches
quiltify_splitbrain_needed();
- progress "creating patches-applied version using gbp pq";
+ progress "dgit view: creating patches-applied version using gbp pq";
runcmd shell_cmd 'exec >/dev/null', @gbp, qw(pq import);
# gbp pq import creates a fresh branch; push back to dgit-view
runcmd @git, qw(update-ref refs/heads/dgit-view HEAD);
if (($diffbits->{H2O} & 02) && # user has modified .gitignore
!($diffbits->{O2A} & 02)) { # patches do not change .gitignore
quiltify_splitbrain_needed();
- progress "creating patch to represent .gitignore changes";
+ progress "dgit view: creating patch to represent .gitignore changes";
ensuredir "debian/patches";
my $gipatch = "debian/patches/auto-gitignore";
open GIPATCH, ">>", "$gipatch" or die "$gipatch: $!";
runcmd @git, qw(update-ref -m), $cachekey, "refs/$splitbraincache",
$dgitview;
+ progress "dgit view: created (commit id $dgitview)";
+
changedir '.git/dgit/unpack/work';
}
chdir "work";
commit_quilty_patch();
+}
+
+sub quilt_make_fake_dsc ($) {
+ my ($upstreamversion) = @_;
+
+ my $fakeversion="$upstreamversion-~~DGITFAKE";
+
+ my $fakedsc=new IO::File 'fake.dsc', '>' or die $!;
+ print $fakedsc <<END or die $!;
+Format: 3.0 (quilt)
+Source: $package
+Version: $fakeversion
+Files:
+END
+
+ my $dscaddfile=sub {
+ my ($b) = @_;
+
+ my $md = new Digest::MD5;
+
+ my $fh = new IO::File $b, '<' or die "$b $!";
+ stat $fh or die $!;
+ my $size = -s _;
+
+ $md->addfile($fh);
+ print $fakedsc " ".$md->hexdigest." $size $b\n" or die $!;
+ };
+ quilt_fixup_linkorigs($upstreamversion, $dscaddfile);
+
+ my @files=qw(debian/source/format debian/rules
+ debian/control debian/changelog);
+ foreach my $maybe (qw(debian/patches debian/source/options
+ debian/tests/control)) {
+ next unless stat_exists "../../../$maybe";
+ push @files, $maybe;
+ }
+
+ my $debtar= srcfn $fakeversion,'.debian.tar.gz';
+ runcmd qw(env GZIP=-1n tar -zcf), "./$debtar", qw(-C ../../..), @files;
+
+ $dscaddfile->($debtar);
+ close $fakedsc or die $!;
+}
+
+sub quilt_check_splitbrain_cache ($$) {
+ my ($headref, $upstreamversion) = @_;
+ # Called only if we are in (potentially) split brain mode.
+ # Called in $ud.
+ # Computes the cache key and looks in the cache.
+ # Returns ($dgit_view_commitid, $cachekey) or (undef, $cachekey)
+
+ my $splitbrain_cachekey;
+ progress
+ "dgit: split brain (separate dgit view) may needed (--quilt=$quilt_mode).";
+ # we look in the reflog of dgit-intern/quilt-cache
+ # we look for an entry whose message is the key for the cache lookup
+ my @cachekey = (qw(dgit), $our_version);
+ push @cachekey, $upstreamversion;
+ push @cachekey, $quilt_mode;
+ push @cachekey, $headref;
+
+ push @cachekey, hashfile('fake.dsc');
+
+ my $srcshash = Digest::SHA->new(256);
+ my %sfs = ( %INC, '$0(dgit)' => $0 );
+ foreach my $sfk (sort keys %sfs) {
+ next unless m/^\$0\b/ || m{^Debian/Dgit\b};
+ $srcshash->add($sfk," ");
+ $srcshash->add(hashfile($sfs{$sfk}));
+ $srcshash->add("\n");
+ }
+ push @cachekey, $srcshash->hexdigest();
+ $splitbrain_cachekey = "@cachekey";
+
+ my @cmd = (@git, qw(reflog), '--pretty=format:%H %gs',
+ $splitbraincache);
+ printdebug "splitbrain cachekey $splitbrain_cachekey\n";
+ debugcmd "|(probably)",@cmd;
+ my $child = open GC, "-|"; defined $child or die $!;
+ if (!$child) {
+ chdir '../../..' or die $!;
+ if (!stat ".git/logs/refs/$splitbraincache") {
+ $! == ENOENT or die $!;
+ printdebug ">(no reflog)\n";
+ exit 0;
+ }
+ exec @cmd; die $!;
+ }
+ while (<GC>) {
+ chomp;
+ printdebug ">| ", $_, "\n" if $debuglevel > 1;
+ next unless m/^(\w+) (\S.*\S)$/ && $2 eq $splitbrain_cachekey;
+
+ my $cachehit = $1;
+ quilt_fixup_mkwork($headref);
+ if ($cachehit ne $headref) {
+ progress "dgit view: found cached (commit id $cachehit)";
+ runcmd @git, qw(checkout -q -b dgit-view), $cachehit;
+ $split_brain = 1;
+ return ($cachehit, $splitbrain_cachekey);
+ }
+ progress "dgit view: found cached, no changes required";
+ return ($headref, $splitbrain_cachekey);
+ }
+ die $! if GC->error;
+ failedcmd unless close GC;
+
+ printdebug "splitbrain cache miss\n";
+ return (undef, $splitbrain_cachekey);
}
sub quilt_fixup_multipatch ($$$) {
my ($clogp, $headref, $upstreamversion) = @_;
- progress "starting quiltify (multiple patches, $quilt_mode mode)";
+ progress "examining quilt state (multiple patches, $quilt_mode mode)";
# Our objective is:
# - honour any existing .pc in case it has any strangeness
# afterwards with dpkg-source --before-build. That lets us save a
# tree object corresponding to .origs.
- my $fakeversion="$upstreamversion-~~DGITFAKE";
-
- my $fakedsc=new IO::File 'fake.dsc', '>' or die $!;
- print $fakedsc <<END or die $!;
-Format: 3.0 (quilt)
-Source: $package
-Version: $fakeversion
-Files:
-END
-
- my $dscaddfile=sub {
- my ($b) = @_;
-
- my $md = new Digest::MD5;
-
- my $fh = new IO::File $b, '<' or die "$b $!";
- stat $fh or die $!;
- my $size = -s _;
-
- $md->addfile($fh);
- print $fakedsc " ".$md->hexdigest." $size $b\n" or die $!;
- };
-
- quilt_fixup_linkorigs($upstreamversion, $dscaddfile);
-
- my @files=qw(debian/source/format debian/rules
- debian/control debian/changelog);
- foreach my $maybe (qw(debian/patches debian/source/options
- debian/tests/control)) {
- next unless stat_exists "../../../$maybe";
- push @files, $maybe;
- }
+ my $splitbrain_cachekey;
- my $debtar= srcfn $fakeversion,'.debian.tar.gz';
- runcmd qw(env GZIP=-1 tar -zcf), "./$debtar", qw(-C ../../..), @files;
+ quilt_make_fake_dsc($upstreamversion);
- $dscaddfile->($debtar);
- close $fakedsc or die $!;
-
- my $splitbrain_cachekey;
if (quiltmode_splitbrain()) {
- # we look in the reflog of dgit-intern/quilt-cache
- # we look for an entry whose message is the key for the cache lookup
- my @cachekey = (qw(dgit), $our_version);
- push @cachekey, $upstreamversion;
- push @cachekey, $quilt_mode;
- push @cachekey, $headref;
-
- push @cachekey, hashfile('fake.dsc');
-
- my $srcshash = Digest::SHA->new(256);
- my %sfs = ( %INC, '$0(dgit)' => $0 );
- foreach my $sfk (sort keys %sfs) {
- $srcshash->add($sfk," ");
- $srcshash->add(hashfile($sfs{$sfk}));
- $srcshash->add("\n");
- }
- push @cachekey, $srcshash->hexdigest();
- $splitbrain_cachekey = "@cachekey";
-
- my @cmd = (@git, qw(reflog), '--pretty=format:%H %gs',
- $splitbraincache);
- printdebug "splitbrain cachekey $splitbrain_cachekey\n";
- debugcmd "|(probably)",@cmd;
- my $child = open GC, "-|"; defined $child or die $!;
- if (!$child) {
- chdir '../../..' or die $!;
- if (!stat ".git/logs/refs/$splitbraincache") {
- $! == ENOENT or die $!;
- printdebug ">(no reflog)\n";
- exit 0;
- }
- exec @cmd; die $!;
- }
- while (<GC>) {
- chomp;
- printdebug ">| ", $_, "\n" if $debuglevel > 1;
- next unless m/^(\w+) (\S.*\S)$/ && $2 eq $splitbrain_cachekey;
-
- my $cachehit = $1;
- quilt_fixup_mkwork($headref);
- if ($cachehit ne $headref) {
- progress "quilt fixup ($quilt_mode mode) found cached tree";
- runcmd @git, qw(checkout -q -b dgit-view), $cachehit;
- $split_brain = 1;
- return;
- }
- progress "quilt fixup ($quilt_mode mode)".
- " found cached indication that no changes needed";
- return;
- }
- die $! if GC->error;
- failedcmd unless close GC;
-
- printdebug "splitbrain cache miss\n";
+ my $cachehit;
+ ($cachehit, $splitbrain_cachekey) =
+ quilt_check_splitbrain_cache($headref, $upstreamversion);
+ return if $cachehit;
}
runcmd qw(sh -ec),
return;
}
+ progress "starting quiltify (multiple patches, $quilt_mode mode)";
quiltify($clogp,$headref,$oldtiptree,\@failsuggestion);
if (!open P, '>>', ".pc/applied-patches") {
exit 0;
}
+sub maybe_apply_patches_dirtily () {
+ return unless $quilt_mode =~ m/gbp|unapplied/;
+ print STDERR <<END or die $!;
+
+dgit: Building, or cleaning with rules target, in patches-unapplied tree.
+dgit: Have to apply the patches - making the tree dirty.
+dgit: (Consider specifying --clean=git and (or) using dgit sbuild.)
+
+END
+ $patches_applied_dirtily = 01;
+ $patches_applied_dirtily |= 02 unless stat_exists '.pc';
+ runcmd qw(dpkg-source --before-build .);
+}
+
+sub maybe_unapply_patches_again () {
+ progress "dgit: Unapplying patches again to tidy up the tree."
+ if $patches_applied_dirtily;
+ runcmd qw(dpkg-source --after-build .)
+ if $patches_applied_dirtily & 01;
+ rmtree '.pc'
+ if $patches_applied_dirtily & 02;
+}
+
#----- other building -----
our $clean_using_builder;
sub clean_tree () {
return if $clean_using_builder;
if ($cleanmode eq 'dpkg-source') {
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean);
} elsif ($cleanmode eq 'dpkg-source-d') {
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @dpkgbuildpackage, qw(-d -T clean);
} elsif ($cleanmode eq 'git') {
runcmd_ordryrun_local @git, qw(clean -xdf);
badusage "clean takes no additional arguments" if @ARGV;
notpushing();
clean_tree();
+ maybe_unapply_patches_again();
}
sub build_prep () {
}
if ($wantsrc < 2) {
push @dbp, changesopts_version();
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @dbp;
}
+ maybe_unapply_patches_again();
printdone "build successful\n";
}
push @cmd, "--git-debian-branch=".lbranch();
}
push @cmd, changesopts();
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @cmd, @ARGV;
}
+ maybe_unapply_patches_again();
printdone "build successful\n";
}
sub cmd_git_build { cmd_gbp_build(); } # compatibility with <= 1.0
}
$dscfn = dscfn($version);
if ($our_cleanmode eq 'dpkg-source') {
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc -S),
changesopts();
} elsif ($our_cleanmode eq 'dpkg-source-d') {
+ maybe_apply_patches_dirtily();
runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc -S -d),
changesopts();
} else {
sub cmd_build_source {
badusage "build-source takes no additional arguments" if @ARGV;
build_source();
+ maybe_unapply_patches_again();
printdone "source built, results in $dscfn and $sourcechanges";
}
rename "$cf", "$cf.inmulti" or fail "$cf\{,.inmulti}: $!";
}
}
+ maybe_unapply_patches_again();
printdone "build successful, results in $multichanges\n" or die $!;
}