From 6bd40b18f8fbe69e2f5b0f3f2dd2795f78b2f042 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Tue, 12 Dec 2017 23:35:39 -0500 Subject: Add DH_EXTRA_ADDONS env variable to specify local addons. This is intended to be used by downstreams or specific local configurations that require a debhelper addon to be run during multiple builds without having to patch a large number of rules file. If at all possible, this should be avoided in favor of a --with flag in the rules file. Signed-off-by: Niels Thykier --- dh | 1 + 1 file changed, 1 insertion(+) (limited to 'dh') diff --git a/dh b/dh index 3d268268..344d4e93 100755 --- a/dh +++ b/dh @@ -303,6 +303,7 @@ if (not compat(9, 1)) { unshift(@ARGV, "--with=build-stamp"); } +push @{$dh{WITH}},split(",", $ENV{DH_EXTRA_ADDONS}); inhibit_log(); -- cgit v1.2.3 From fb1060cdcf6575fd9aed711e470e194892874375 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sat, 30 Dec 2017 20:34:48 +0000 Subject: dh: Fix a warning about an uninitialized variable Signed-off-by: Niels Thykier --- dh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dh') diff --git a/dh b/dh index 344d4e93..0403d0ca 100755 --- a/dh +++ b/dh @@ -303,7 +303,7 @@ if (not compat(9, 1)) { unshift(@ARGV, "--with=build-stamp"); } -push @{$dh{WITH}},split(",", $ENV{DH_EXTRA_ADDONS}); +push(@{$dh{WITH}},split(",", $ENV{DH_EXTRA_ADDONS})) if $ENV{DH_EXTRA_ADDONS}; inhibit_log(); -- cgit v1.2.3 From cb2caa7f67837294b0681d881f52dd23df487f33 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Tue, 2 Jan 2018 09:55:17 +0000 Subject: dh: Rewrite sequence handling Rewrite the way we compute the sequences to ensure that: 1) Rules target remain opaque (particularly "subtargets" are now also opaque). 2) Opaque targets are run first, so they can run their subtargets before dh runs a command that depends on it. This is the first half of fixing Debian#880840. Signed-off-by: Niels Thykier --- dh | 128 ++++------------------------------ lib/Debian/Debhelper/SequencerUtil.pm | 128 ++++++++++++++++++++++++++++++++++ t/dh-sequencer.t | 127 +++++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+), 113 deletions(-) create mode 100644 lib/Debian/Debhelper/SequencerUtil.pm create mode 100755 t/dh-sequencer.t (limited to 'dh') diff --git a/dh b/dh index 0403d0ca..201baa77 100755 --- a/dh +++ b/dh @@ -9,6 +9,7 @@ dh - debhelper command sequencer use strict; use warnings; use Debian::Debhelper::Dh_Lib; +use Debian::Debhelper::SequencerUtil; our $VERSION = DH_BUILTIN_VERSION; @@ -364,10 +365,9 @@ if (! defined $sequence) { # Also support completely empty override targets. # Note: it's not safe to use rules_explicit_target before this check, # since it causes dh to be run. -my $dummy_target="debhelper-fail-me"; if ($sequence eq 'debian/rules' || $sequence =~ /^override_dh_/ || - $sequence eq $dummy_target) { + $sequence eq DUMMY_TARGET) { exit 0; } @@ -454,13 +454,13 @@ $sequences{'build-indep'} = [@bd]; $sequences{'build-arch'} = [@bd]; if (! compat(8)) { # From v9, sequences take standard rules targets into account. - $sequences{build} = [@bd_minimal, rules("build-arch"), rules("build-indep")]; - $sequences{'install-indep'} = [rules("build-indep"), @i]; - $sequences{'install-arch'} = [rules("build-arch"), @i]; - $sequences{'install'} = [rules("build"), rules("install-arch"), rules("install-indep")]; - $sequences{'binary-indep'} = [rules("install-indep"), @b]; - $sequences{'binary-arch'} = [rules("install-arch"), @ba, @b]; - $sequences{binary} = [rules("install"), rules("binary-arch"), rules("binary-indep")]; + $sequences{build} = [@bd_minimal, to_rules_target("build-arch"), to_rules_target("build-indep")]; + $sequences{'install-indep'} = [to_rules_target("build-indep"), @i]; + $sequences{'install-arch'} = [to_rules_target("build-arch"), @i]; + $sequences{'install'} = [to_rules_target("build"), to_rules_target("install-arch"), to_rules_target("install-indep")]; + $sequences{'binary-indep'} = [to_rules_target("install-indep"), @b]; + $sequences{'binary-arch'} = [to_rules_target("install-arch"), @ba, @b]; + $sequences{binary} = [to_rules_target("install"), to_rules_target("binary-arch"), to_rules_target("binary-indep")]; } else { $sequences{build} = [@bd]; @@ -574,7 +574,10 @@ if (! exists $sequences{$sequence}) { error "Unknown sequence $sequence (choose from: ". join(" ", sort keys %sequences).")"; } -my @sequence=optimize_sequence(@{$sequences{$sequence}}); +# In compat <= 9, the sequences are always inlined (those versions do not +# recurse into debian/rules anyway). In compat 10+, we never inline an +# existing rules target. +my @sequence = optimize_sequence(\%sequences, $sequence, (!compat(9) ? 0 : 1)); # The list of all packages that can be acted on. my @packages=@{$dh{DOPACKAGES}}; @@ -670,7 +673,7 @@ foreach my $package (@packages) { # everything (admittedly, it is bit of an over # approximation) # Related bug: #851071 - my @seq = optimize_sequence(@{$sequences{'build'}}); + my @seq = optimize_sequence(\%sequences, 'build', 1); $optimized_build_seq = \@seq; } @log = @{$optimized_build_seq}; @@ -735,7 +738,7 @@ foreach my $i (0..$stoppoint) { } next unless @todo; - my $rules_target = rules_target($command); + my $rules_target = extract_rules_target_name($command); if (defined $rules_target) { # Don't pass DH_ environment variables, since this is # a fresh invocation of debian/rules and any sub-dh commands. @@ -895,42 +898,6 @@ sub run_override { return @rest; } -sub optimize_sequence { - my (@commands) = @_; - my (@sequence, %seen); - my $add=sub { - # commands can appear multiple times when sequences are - # inlined together; only the first should be needed - my $command=shift; - if (! $seen{$command}) { - $seen{$command}=1; - push @sequence, $command; - } - }; - foreach my $command (@commands) { - my $rules_target=rules_target($command); - if (defined $rules_target && - ! defined rules_explicit_target($rules_target)) { - # inline the sequence for this implicit target - $add->($_) foreach optimize_sequence(@{$sequences{$rules_target}}); - } - else { - $add->($command); - } - } - return @sequence; -} - -sub rules_target { - my ($command) = @_; - if ($command =~ /^debian\/rules\s+(.*)/) { - return $1 - } - else { - return undef; - } -} - sub stamp_target { my ($command) = @_; if ($command =~ s/^create-stamp\s+//) { @@ -939,71 +906,6 @@ sub stamp_target { return; } -sub rules { - return "debian/rules ".join(" ", @_); -} - -{ -my %targets; -my $rules_parsed; - -sub rules_explicit_target { - # Checks if a specified target exists as an explicit target - # in debian/rules. - # undef is returned if target does not exist, 0 if target is noop - # and 1 if target has dependencies or executes commands. - my ($target) = @_; - - if (! $rules_parsed) { - my $processing_targets = 0; - my $not_a_target = 0; - my $current_target; - open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules $dummy_target 2>/dev/null |"); - while () { - if ($processing_targets) { - if (/^# Not a target:/) { - $not_a_target = 1; - } - else { - if (!$not_a_target && /^([^#:]+)::?\s*(.*)$/) { - # Target is defined. NOTE: if it is a dependency of - # .PHONY it will be defined too but that's ok. - # $2 contains target dependencies if any. - $current_target = $1; - $targets{$current_target} = ($2) ? 1 : 0; - } - else { - if (defined $current_target) { - if (/^#/) { - # Check if target has commands to execute - if (/^#\s*(commands|recipe) to execute/) { - $targets{$current_target} = 1; - } - } - else { - # Target parsed. - $current_target = undef; - } - } - } - # "Not a target:" is always followed by - # a target name, so resetting this one - # here is safe. - $not_a_target = 0; - } - } - elsif (/^# Files$/) { - $processing_targets = 1; - } - } - close MAKE; - $rules_parsed = 1; - } - - return $targets{$target}; -} - -} sub warn_deprecated { foreach my $deprecated ('until', 'after', 'before', 'remaining') { diff --git a/lib/Debian/Debhelper/SequencerUtil.pm b/lib/Debian/Debhelper/SequencerUtil.pm new file mode 100644 index 00000000..d78aa032 --- /dev/null +++ b/lib/Debian/Debhelper/SequencerUtil.pm @@ -0,0 +1,128 @@ +#!/usr/bin/perl +# +# Internal library functions for the dh(1) command + +package Debian::Debhelper::SequencerUtil; +use strict; +use warnings; +use constant DUMMY_TARGET => 'debhelper-fail-me'; + +use Exporter qw(import); + +our @EXPORT = qw( + extract_rules_target_name + to_rules_target + optimize_sequence + rules_explicit_target + DUMMY_TARGET +); + +our (%EXPLICIT_TARGETS, $RULES_PARSED); + +sub extract_rules_target_name { + my ($command) = @_; + if ($command =~ m{^debian/rules\s++(.++)}) { + return $1 + } + return; +} + +sub to_rules_target { + return 'debian/rules '.join(' ', @_); +} + +sub optimize_sequence { + my ($sequences, $sequence_name, $always_inline) = @_; + my (@sequence, @targets, %seen, %non_inlineable_targets, @stack); + push(@stack, [@{$sequences->{$sequence_name}}]); + while (@stack) { + my $current_sequence = pop(@stack); + COMMAND: + while (@{$current_sequence}) { + my $command = shift(@{$current_sequence}); + my $rules_target=extract_rules_target_name($command); + if (defined($rules_target) && + ! exists($non_inlineable_targets{$rules_target}) && + ! defined(rules_explicit_target($rules_target))) { + + # inline the sequence for this implicit target. + push(@stack, $current_sequence); + $current_sequence = [@{$sequences->{$rules_target}}]; + next COMMAND; + } else { + if (defined($rules_target) and not $always_inline) { + next COMMAND if exists($non_inlineable_targets{$rules_target}); + my @opaque_targets = ($rules_target); + while (my $opaque_target = pop(@opaque_targets)) { + for my $c (@{$sequences->{$opaque_target}}) { + my $subtarget = extract_rules_target_name($c); + next if not defined($subtarget); + next if exists($non_inlineable_targets{$subtarget}); + $non_inlineable_targets{$subtarget} = $rules_target; + } + } + push(@targets, $command) if not $seen{$command}++; + } elsif (! $seen{$command}) { + $seen{$command} = 1; + push(@sequence, $command); + } + } + } + } + return (@targets, @sequence); +} + + +sub rules_explicit_target { + # Checks if a specified target exists as an explicit target + # in debian/rules. + # undef is returned if target does not exist, 0 if target is noop + # and 1 if target has dependencies or executes commands. + my ($target) = @_; + + if (! $RULES_PARSED) { + my $processing_targets = 0; + my $not_a_target = 0; + my $current_target; + open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules ${\DUMMY_TARGET} 2>/dev/null |"); + while () { + if ($processing_targets) { + if (/^# Not a target:/) { + $not_a_target = 1; + } else { + if (!$not_a_target && m/^([^#:]+)::?\s*(.*)$/) { + # Target is defined. NOTE: if it is a dependency of + # .PHONY it will be defined too but that's ok. + # $2 contains target dependencies if any. + $current_target = $1; + $EXPLICIT_TARGETS{$current_target} = ($2) ? 1 : 0; + } else { + if (defined($current_target)) { + if (m/^#/) { + # Check if target has commands to execute + if (m/^#\s*(commands|recipe) to execute/) { + $EXPLICIT_TARGETS{$current_target} = 1; + } + } else { + # Target parsed. + $current_target = undef; + } + } + } + # "Not a target:" is always followed by + # a target name, so resetting this one + # here is safe. + $not_a_target = 0; + } + } elsif (m/^# Files$/) { + $processing_targets = 1; + } + } + close MAKE; + $RULES_PARSED = 1; + } + + return $EXPLICIT_TARGETS{$target}; +} + +1; diff --git a/t/dh-sequencer.t b/t/dh-sequencer.t new file mode 100755 index 00000000..8f554594 --- /dev/null +++ b/t/dh-sequencer.t @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; + +use Debian::Debhelper::SequencerUtil; + +# Shorten variants of the sequences. +my @bd_minimal = qw{ + dh_testdir +}; +my @bd = (qw{ + dh_auto_configure + dh_auto_build + dh_auto_test +}); +my @i = (qw{ + dh_testroot + dh_prep + dh_auto_install + + dh_install + dh_missing +}); +my @ba=qw{ + dh_strip + dh_makeshlibs + dh_shlibdeps +}; +my @b=qw{ + dh_installdeb + dh_gencontrol + dh_builddeb +}; + +my %sequences = ( + 'build-indep' => [@bd_minimal, @bd], + 'build-arch' => [@bd_minimal, @bd], + 'build' => [@bd_minimal, to_rules_target("build-arch"), to_rules_target("build-indep")], + + 'install-indep' => [to_rules_target("build-indep"), @i], + 'install-arch' => [to_rules_target("build-arch"), @i], + 'install' => [to_rules_target("build"), to_rules_target("install-arch"), to_rules_target("install-indep")], + + 'binary-indep' => [to_rules_target("install-indep"), @b], + 'binary-arch' => [to_rules_target("install-arch"), @ba, @b], + 'binary' => [to_rules_target("install"), to_rules_target("binary-arch"), to_rules_target("binary-indep")], +); + + +plan tests => 9; + +# We will horse around with %EXPLICIT_TARGETS in this test; it should +# definitely not attempt to read d/rules or the test will be break. +$Debian::Debhelper::SequencerUtil::RULES_PARSED = 1; + + +is_deeply( + [optimize_sequence(\%sequences, 'build')], + [@bd_minimal, @bd], + 'Inlined build sequence matches build-indep/build-arch'); + +is_deeply( + [optimize_sequence(\%sequences, 'install')], + [@bd_minimal, @bd, @i], + 'Inlined install sequence matches build-indep/build-arch + install commands'); + +is_deeply( + [optimize_sequence(\%sequences, 'binary-arch')], + [@bd_minimal, @bd, @i, @ba, @b], + 'Inlined binary-arch sequence has all the commands'); + +is_deeply( + [optimize_sequence(\%sequences, 'binary-indep')], + [@bd_minimal, @bd, @i, @b], + 'Inlined binary-indep sequence has all the commands except @bd'); + +is_deeply( + [optimize_sequence(\%sequences, 'binary')], + [@bd_minimal, @bd, @i, @ba, @b], + 'Inlined binary sequence has all the commands'); + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; + + is_deeply( + [optimize_sequence(\%sequences, 'binary')], + [to_rules_target('build'), @i, @ba, @b], + 'Inlined binary sequence has all the commands but build target is opaque'); + + is_deeply( + [optimize_sequence(\%sequences, 'build')], + [@bd_minimal, @bd], + 'build sequence is inlineable'); + +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; + + is_deeply( + [optimize_sequence(\%sequences, 'binary')], + # @bd_minimal, @bd and @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, optimize_sequence cannot show that. + [to_rules_target('install-arch'), @bd_minimal, @bd, @i, @ba, @b], + 'Inlined binary sequence has all the commands'); +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; + + my $actual = [optimize_sequence(\%sequences, 'binary')]; + # @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, optimize_sequence cannot show that. + my $expected = [to_rules_target('build'), to_rules_target('install-arch'), @i, @ba, @b]; + # Permit some fuzz on the order between build and install-arch + if ($actual->[0] eq to_rules_target('install-arch')) { + $expected->[0] = to_rules_target('install-arch'); + $expected->[1] = to_rules_target('build'); + } + is_deeply( + $actual, + $expected, + 'Inlined binary sequence has all the commands'); +} -- cgit v1.2.3 From 33788cb6ce471f5ee4b02444414a20163e428a25 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Tue, 2 Jan 2018 14:01:01 +0000 Subject: dh: Do not re-run completed targets This is part of 2 of the dh sequence rewrite. Part 1 is cb2caa7f67837294b0681d881f52dd23df487f33. This change ensures that dh no longer attempts to run a target that is already marked as complete (e.g. via the stamp file). Signed-off-by: Niels Thykier --- debian/changelog | 3 + dh | 117 ++++++++++++++++++++++++---------- lib/Debian/Debhelper/SequencerUtil.pm | 5 +- t/dh-sequencer.t | 37 +++++++---- 4 files changed, 115 insertions(+), 47 deletions(-) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index b0448c27..9db0168c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -53,6 +53,9 @@ debhelper (11.1) UNRELEASED; urgency=medium * dh_gencontrol: Deduplicate debug-ids before inserting them into the control file. Thanks to Mattia Rizzolo for reporting the bug. (Closes: #886038) + * dh: Rewrite sequence handling to ensure that dh does not "inline" + a subtarget of a target it recurses into. Thanks to James + Cowgill for reporting the bug. (Closes: #880840) -- Niels Thykier Sun, 17 Dec 2017 07:59:18 +0000 diff --git a/dh b/dh index 201baa77..537d5e72 100755 --- a/dh +++ b/dh @@ -454,7 +454,7 @@ $sequences{'build-indep'} = [@bd]; $sequences{'build-arch'} = [@bd]; if (! compat(8)) { # From v9, sequences take standard rules targets into account. - $sequences{build} = [@bd_minimal, to_rules_target("build-arch"), to_rules_target("build-indep")]; + $sequences{build} = [to_rules_target("build-arch"), to_rules_target("build-indep")]; $sequences{'install-indep'} = [to_rules_target("build-indep"), @i]; $sequences{'install-arch'} = [to_rules_target("build-arch"), @i]; $sequences{'install'} = [to_rules_target("build"), to_rules_target("install-arch"), to_rules_target("install-indep")]; @@ -574,13 +574,27 @@ if (! exists $sequences{$sequence}) { error "Unknown sequence $sequence (choose from: ". join(" ", sort keys %sequences).")"; } -# In compat <= 9, the sequences are always inlined (those versions do not -# recurse into debian/rules anyway). In compat 10+, we never inline an -# existing rules target. -my @sequence = optimize_sequence(\%sequences, $sequence, (!compat(9) ? 0 : 1)); # The list of all packages that can be acted on. my @packages=@{$dh{DOPACKAGES}}; +my @arch_packages = getpackages("arch"); +my @indep_packages = getpackages("indep"); +my %sequence2packages = ( + 'build-arch' => \@arch_packages, + 'install-arch' => \@arch_packages, + 'binary-arch' => \@arch_packages, + + 'build-indep' => \@indep_packages, + 'install-indep' => \@indep_packages, + 'binary-indep' => \@indep_packages, + + 'clean' => \@packages, + 'build' => \@packages, + 'install' => \@packages, + 'binary' => \@packages, +); + +my %completed_sequences; # Get the options to pass to commands in the sequence. # Filter out options intended only for this program. @@ -593,16 +607,14 @@ if ($sequence eq 'build-arch' || push @options, "-a"; # as an optimisation, remove from the list any packages # that are not arch dependent - my %arch_packages = map { $_ => 1 } getpackages("arch"); - @packages = grep { $arch_packages{$_} } @packages; + @packages = @{$sequence2packages{$sequence}}; } elsif ($sequence eq 'build-indep' || $sequence eq 'install-indep' || $sequence eq 'binary-indep') { push @options, "-i"; # ditto optimisation for arch indep - my %indep_packages = map { $_ => 1 } getpackages("indep"); - @packages = grep { $indep_packages{$_} } @packages; + @packages = @{$sequence2packages{$sequence}}; } while (@ARGV_orig) { my $opt=shift @ARGV_orig; @@ -647,19 +659,44 @@ while (@ARGV_orig) { } # Figure out at what point in the sequence to start for each package. -my %logged; -my %startpoint; -my %stamp_file; +my (%logged, %startpoint, %stamp_file); -if ( -f $build_stamp_file) { +if ( -f $build_stamp_file and not compat(9)) { open(my $fd, '<', $build_stamp_file) or error("open($build_stamp_file, ro) failed: $!"); while (my $line = <$fd>) { chomp($line); $stamp_file{$line} = 1; } close($fd); + my $build_indep_target_done = 1; + my $build_arch_target_done = 1; + for my $pkg (@{$sequence2packages{'build-arch'}}) { + if (not $stamp_file{$pkg}) { + $build_arch_target_done = 0; + last; + } + } + for my $pkg (@{$sequence2packages{'build-indep'}}) { + if (not $stamp_file{$pkg}) { + $build_indep_target_done = 0; + last; + } + } + $completed_sequences{'build-arch'} = 1 if $build_arch_target_done; + $completed_sequences{'build-indep'} = 1 if $build_indep_target_done; + $completed_sequences{'build'} = 1 if $build_indep_target_done and $build_arch_target_done; } +# In compat <= 9, the sequences are always inlined (those versions do not +# recurse into debian/rules anyway). In compat 10+, we never inline an +# existing rules target. +my ($rules_targets, $full_sequence) = optimize_sequence(\%sequences, + $sequence, + (!compat(9) ? 0 : 1), + \%completed_sequences + ); + + # Lazy cache of the result of optimize_sequence on the "build" # sequence my $optimized_build_seq; @@ -673,8 +710,8 @@ foreach my $package (@packages) { # everything (admittedly, it is bit of an over # approximation) # Related bug: #851071 - my @seq = optimize_sequence(\%sequences, 'build', 1); - $optimized_build_seq = \@seq; + my (undef, $seq) = optimize_sequence(\%sequences, 'build', 1); + $optimized_build_seq = $seq; } @log = @{$optimized_build_seq}; # We do not need %logged in compat 10 @@ -682,13 +719,13 @@ foreach my $package (@packages) { if ($dh{AFTER}) { # Run commands in the sequence that come after the # specified command. - $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1; + $startpoint{$package} = command_pos($dh{AFTER}, @{$full_sequence}) + 1; # Write a dummy log entry indicating that the specified # command was, in fact, run. This handles the case where # no commands remain to run after it, communicating to # future dh instances that the specified command should not # be run again. - write_log($sequence[$startpoint{$package}-1], $package); + write_log($full_sequence->[$startpoint{$package}-1], $package); } elsif ($dh{REMAINING}) { # Start at the beginning so all remaining commands will get @@ -701,8 +738,8 @@ foreach my $package (@packages) { # command is in the sequence, we're starting at the beginning.. $startpoint{$package}=0; COMMAND: foreach my $command (reverse @log) { - foreach my $i (0..$#sequence) { - if ($command eq $sequence[$i]) { + foreach my $i (0..$#{$full_sequence}) { + if ($command eq $full_sequence->[$i]) { $startpoint{$package}=$i+1; last COMMAND; } @@ -712,24 +749,46 @@ COMMAND: foreach my $command (reverse @log) { } # Figure out what point in the sequence to go to. -my $stoppoint=$#sequence; +my $stoppoint=$#{$full_sequence}; if ($dh{UNTIL}) { - $stoppoint=command_pos($dh{UNTIL}, @sequence); + $stoppoint = command_pos($dh{UNTIL}, @{$full_sequence}); } elsif ($dh{BEFORE}) { - $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1; + $stoppoint = command_pos($dh{BEFORE}, @{$full_sequence}) - 1; +} + +for my $rules_command (@{$rules_targets}) { + my $rules_target = extract_rules_target_name($rules_command) + // error("Internal error: $rules_command was not a rules target!?"); + # Don't pass DH_ environment variables, since this is + # a fresh invocation of debian/rules and any sub-dh commands. + delete($ENV{DH_INTERNAL_OPTIONS}); + delete($ENV{DH_INTERNAL_OVERRIDE}); + run("debian/rules", $rules_target); + my $override_packages = $sequence2packages{$rules_target} // \@packages; + for my $package (@{$override_packages}) { + my (undef, $seq) = optimize_sequence(\%sequences, $rules_target, 1); + COMMAND: for my $c (reverse(@{$seq})) { + for my $j (0 .. $#{$full_sequence}) { + if ($c eq $full_sequence->[$j]) { + $startpoint{$package} = $j + 1; + last COMMAND; + } + } + } + } } # Now run the commands in the sequence. foreach my $i (0..$stoppoint) { - my $command=$sequence[$i]; + my $command = $full_sequence->[$i]; # Figure out which packages need to run this command. my @todo; my @opts=@options; foreach my $package (@packages) { if ($startpoint{$package} > $i || - $logged{$package}{$sequence[$i]}) { + $logged{$package}{$full_sequence->[$i]}) { push @opts, "-N$package"; } else { @@ -739,14 +798,8 @@ foreach my $i (0..$stoppoint) { next unless @todo; my $rules_target = extract_rules_target_name($command); - if (defined $rules_target) { - # Don't pass DH_ environment variables, since this is - # a fresh invocation of debian/rules and any sub-dh commands. - delete $ENV{DH_INTERNAL_OPTIONS}; - delete $ENV{DH_INTERNAL_OVERRIDE}; - run("debian/rules", $rules_target); - next; - } + error("Internal error: $command is a rules target, but it is not supported to be!?") if defined($rules_target); + if (my $stamp_file = stamp_target($command)) { my %seen; print " create-stamp ".escape_shell($stamp_file)."\n"; diff --git a/lib/Debian/Debhelper/SequencerUtil.pm b/lib/Debian/Debhelper/SequencerUtil.pm index d78aa032..1aba9964 100644 --- a/lib/Debian/Debhelper/SequencerUtil.pm +++ b/lib/Debian/Debhelper/SequencerUtil.pm @@ -32,7 +32,7 @@ sub to_rules_target { } sub optimize_sequence { - my ($sequences, $sequence_name, $always_inline) = @_; + my ($sequences, $sequence_name, $always_inline, $completed_sequences) = @_; my (@sequence, @targets, %seen, %non_inlineable_targets, @stack); push(@stack, [@{$sequences->{$sequence_name}}]); while (@stack) { @@ -41,6 +41,7 @@ sub optimize_sequence { while (@{$current_sequence}) { my $command = shift(@{$current_sequence}); my $rules_target=extract_rules_target_name($command); + next if (defined($rules_target) and exists($completed_sequences->{$rules_target})); if (defined($rules_target) && ! exists($non_inlineable_targets{$rules_target}) && ! defined(rules_explicit_target($rules_target))) { @@ -69,7 +70,7 @@ sub optimize_sequence { } } } - return (@targets, @sequence); + return (\@targets, \@sequence); } diff --git a/t/dh-sequencer.t b/t/dh-sequencer.t index 8f554594..6509a9bf 100755 --- a/t/dh-sequencer.t +++ b/t/dh-sequencer.t @@ -49,7 +49,7 @@ my %sequences = ( ); -plan tests => 9; +plan tests => 11; # We will horse around with %EXPLICIT_TARGETS in this test; it should # definitely not attempt to read d/rules or the test will be break. @@ -58,40 +58,51 @@ $Debian::Debhelper::SequencerUtil::RULES_PARSED = 1; is_deeply( [optimize_sequence(\%sequences, 'build')], - [@bd_minimal, @bd], + [[], [@bd_minimal, @bd]], 'Inlined build sequence matches build-indep/build-arch'); is_deeply( [optimize_sequence(\%sequences, 'install')], - [@bd_minimal, @bd, @i], + [[], [@bd_minimal, @bd, @i]], 'Inlined install sequence matches build-indep/build-arch + install commands'); is_deeply( [optimize_sequence(\%sequences, 'binary-arch')], - [@bd_minimal, @bd, @i, @ba, @b], + [[], [@bd_minimal, @bd, @i, @ba, @b]], 'Inlined binary-arch sequence has all the commands'); is_deeply( [optimize_sequence(\%sequences, 'binary-indep')], - [@bd_minimal, @bd, @i, @b], + [[], [@bd_minimal, @bd, @i, @b]], 'Inlined binary-indep sequence has all the commands except @bd'); is_deeply( [optimize_sequence(\%sequences, 'binary')], - [@bd_minimal, @bd, @i, @ba, @b], + [[], [@bd_minimal, @bd, @i, @ba, @b]], 'Inlined binary sequence has all the commands'); + +is_deeply( + [optimize_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [[], [@i, @ba, @b]], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + { local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; is_deeply( [optimize_sequence(\%sequences, 'binary')], - [to_rules_target('build'), @i, @ba, @b], + [[to_rules_target('build')], [@i, @ba, @b]], 'Inlined binary sequence has all the commands but build target is opaque'); + is_deeply( + [optimize_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [[], [@i, @ba, @b]], + 'Inlined binary sequence has all the commands with build-* done and not build-target'); + is_deeply( [optimize_sequence(\%sequences, 'build')], - [@bd_minimal, @bd], + [[], [@bd_minimal, @bd]], 'build sequence is inlineable'); } @@ -103,7 +114,7 @@ is_deeply( [optimize_sequence(\%sequences, 'binary')], # @bd_minimal, @bd and @i should be "-i"-only, @ba + @b should be both. # Unfortunately, optimize_sequence cannot show that. - [to_rules_target('install-arch'), @bd_minimal, @bd, @i, @ba, @b], + [[to_rules_target('install-arch')], [@bd_minimal, @bd, @i, @ba, @b]], 'Inlined binary sequence has all the commands'); } @@ -114,11 +125,11 @@ is_deeply( my $actual = [optimize_sequence(\%sequences, 'binary')]; # @i should be "-i"-only, @ba + @b should be both. # Unfortunately, optimize_sequence cannot show that. - my $expected = [to_rules_target('build'), to_rules_target('install-arch'), @i, @ba, @b]; + my $expected = [[to_rules_target('build'), to_rules_target('install-arch')], [@i, @ba, @b]]; # Permit some fuzz on the order between build and install-arch - if ($actual->[0] eq to_rules_target('install-arch')) { - $expected->[0] = to_rules_target('install-arch'); - $expected->[1] = to_rules_target('build'); + if ($actual->[0][0] eq to_rules_target('install-arch')) { + $expected->[0][0] = to_rules_target('install-arch'); + $expected->[0][1] = to_rules_target('build'); } is_deeply( $actual, -- cgit v1.2.3 From 486dc1195346ed6aa35dae7e3ef35b4c4d37b7ee Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Tue, 2 Jan 2018 14:08:08 +0000 Subject: dh: Isolate some (now) "compat 9"-only code Signed-off-by: Niels Thykier --- dh | 75 ++++++++++++++++++++++++++++------------------------------------------ 1 file changed, 30 insertions(+), 45 deletions(-) (limited to 'dh') diff --git a/dh b/dh index 537d5e72..0945d175 100755 --- a/dh +++ b/dh @@ -696,52 +696,37 @@ my ($rules_targets, $full_sequence) = optimize_sequence(\%sequences, \%completed_sequences ); - -# Lazy cache of the result of optimize_sequence on the "build" -# sequence -my $optimized_build_seq; -foreach my $package (@packages) { - my @log; - if (compat(9)) { - @log = load_log($package, \%logged); - } elsif (exists($stamp_file{$package})) { - if (not defined($optimized_build_seq)) { - # Expand "build" so we can accurately filter out - # everything (admittedly, it is bit of an over - # approximation) - # Related bug: #851071 - my (undef, $seq) = optimize_sequence(\%sequences, 'build', 1); - $optimized_build_seq = $seq; +if (compat(9)) { + foreach my $package (@packages) { + my @log = load_log($package, \%logged); + if ($dh{AFTER}) { + # Run commands in the sequence that come after the + # specified command. + $startpoint{$package} = command_pos($dh{AFTER}, @{$full_sequence}) + 1; + # Write a dummy log entry indicating that the specified + # command was, in fact, run. This handles the case where + # no commands remain to run after it, communicating to + # future dh instances that the specified command should not + # be run again. + write_log($full_sequence->[$startpoint{$package} - 1], $package); } - @log = @{$optimized_build_seq}; - # We do not need %logged in compat 10 - } - if ($dh{AFTER}) { - # Run commands in the sequence that come after the - # specified command. - $startpoint{$package} = command_pos($dh{AFTER}, @{$full_sequence}) + 1; - # Write a dummy log entry indicating that the specified - # command was, in fact, run. This handles the case where - # no commands remain to run after it, communicating to - # future dh instances that the specified command should not - # be run again. - write_log($full_sequence->[$startpoint{$package}-1], $package); - } - elsif ($dh{REMAINING}) { - # Start at the beginning so all remaining commands will get - # run. - $startpoint{$package}=0; - } - else { - # Find the last logged command that is in the sequence, and - # continue with the next command after it. If no logged - # command is in the sequence, we're starting at the beginning.. - $startpoint{$package}=0; -COMMAND: foreach my $command (reverse @log) { - foreach my $i (0..$#{$full_sequence}) { - if ($command eq $full_sequence->[$i]) { - $startpoint{$package}=$i+1; - last COMMAND; + elsif ($dh{REMAINING}) { + # Start at the beginning so all remaining commands will get + # run. + $startpoint{$package} = 0; + } + else { + # Find the last logged command that is in the sequence, and + # continue with the next command after it. If no logged + # command is in the sequence, we're starting at the beginning.. + $startpoint{$package} = 0; + COMMAND: + foreach my $command (reverse @log) { + foreach my $i (0 .. $#{$full_sequence}) { + if ($command eq $full_sequence->[$i]) { + $startpoint{$package} = $i + 1; + last COMMAND; + } } } } -- cgit v1.2.3 From eb1bdee3ff729551267578c2716afcebd88b4365 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Tue, 2 Jan 2018 14:41:04 +0000 Subject: dh: Ensure that $startpoint{$package} is defined Thanks to James Cowgill for finding this bug. --- dh | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'dh') diff --git a/dh b/dh index 0945d175..4e69bb2e 100755 --- a/dh +++ b/dh @@ -731,6 +731,10 @@ if (compat(9)) { } } } +} else { + foreach my $package (@packages) { + $startpoint{$package} = 0; + } } # Figure out what point in the sequence to go to. -- cgit v1.2.3 From 76a900d24ba46df3e8868f778a6a0d7ab84c52ed Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 4 Jan 2018 19:09:59 +0000 Subject: dh: Move some "compat 9"-only code inside an if-guard This will make it easier to see that the code is dead once compat 9 is removed. Signed-off-by: Niels Thykier --- dh | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'dh') diff --git a/dh b/dh index 4e69bb2e..d6ba0c4f 100755 --- a/dh +++ b/dh @@ -695,6 +695,7 @@ my ($rules_targets, $full_sequence) = optimize_sequence(\%sequences, (!compat(9) ? 0 : 1), \%completed_sequences ); +my $stoppoint = $#{$full_sequence}; if (compat(9)) { foreach my $package (@packages) { @@ -731,21 +732,18 @@ if (compat(9)) { } } } + # Figure out what point in the sequence to go to. + if ($dh{UNTIL}) { + $stoppoint = command_pos($dh{UNTIL}, @{$full_sequence}); + } elsif ($dh{BEFORE}) { + $stoppoint = command_pos($dh{BEFORE}, @{$full_sequence}) - 1; + } } else { foreach my $package (@packages) { $startpoint{$package} = 0; } } -# Figure out what point in the sequence to go to. -my $stoppoint=$#{$full_sequence}; -if ($dh{UNTIL}) { - $stoppoint = command_pos($dh{UNTIL}, @{$full_sequence}); -} -elsif ($dh{BEFORE}) { - $stoppoint = command_pos($dh{BEFORE}, @{$full_sequence}) - 1; -} - for my $rules_command (@{$rules_targets}) { my $rules_target = extract_rules_target_name($rules_command) // error("Internal error: $rules_command was not a rules target!?"); -- cgit v1.2.3 From d0cd645924fd6834d049dd3d4d156c93a2e29a0c Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 4 Jan 2018 19:14:28 +0000 Subject: dh: Avoid reset of starting point with multiple opaque targets Signed-off-by: Niels Thykier --- dh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'dh') diff --git a/dh b/dh index d6ba0c4f..e123ed03 100755 --- a/dh +++ b/dh @@ -758,7 +758,16 @@ for my $rules_command (@{$rules_targets}) { COMMAND: for my $c (reverse(@{$seq})) { for my $j (0 .. $#{$full_sequence}) { if ($c eq $full_sequence->[$j]) { - $startpoint{$package} = $j + 1; + # Unfortunately, we do not guarantee any order + # between the run targets. Assuming e.g. + # "install-arch" and "build" are opague targets + # then we could process "install-arch" first and + # then "build". In this case, it is important + # that we do not "reset" the starting point for + # "arch" packages. Otherwise, we might repeat + # part of the "install-arch" sequence when we + # should not. + $startpoint{$package} = $j + 1 if $j + 1 > startpoint{$package}; last COMMAND; } } -- cgit v1.2.3 From 62a4c177571afb07202219312d0c79389971d980 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sun, 7 Jan 2018 09:48:03 +0000 Subject: dh: Fix off-by-one in a compat check Signed-off-by: Niels Thykier --- debian/changelog | 9 +++++++++ dh | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index 49afe012..fed3e6b5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +debhelper (11.1.1) UNRELEASED; urgency=medium + + * dh: Fix an off-by-one in a compat check. This fixes an + internal error for compat 9 packages that requires dh to + recurse into the debian/rules file. Thanks to Helmut + Grohne for reporting the bug. (Closes: #886518) + + -- Niels Thykier Sun, 07 Jan 2018 09:17:16 +0000 + debhelper (11.1) unstable; urgency=medium [ Paul Tagliamonte ] diff --git a/dh b/dh index e123ed03..7e5322e0 100755 --- a/dh +++ b/dh @@ -687,12 +687,12 @@ if ( -f $build_stamp_file and not compat(9)) { $completed_sequences{'build'} = 1 if $build_indep_target_done and $build_arch_target_done; } -# In compat <= 9, the sequences are always inlined (those versions do not -# recurse into debian/rules anyway). In compat 10+, we never inline an +# In compat <= 8, the sequences are always inlined (those versions do not +# recurse into debian/rules anyway). In compat 9+, we never inline an # existing rules target. my ($rules_targets, $full_sequence) = optimize_sequence(\%sequences, $sequence, - (!compat(9) ? 0 : 1), + (!compat(8) ? 0 : 1), \%completed_sequences ); my $stoppoint = $#{$full_sequence}; -- cgit v1.2.3 From 084c26e70d4b43e6be187acde850a371f60ff005 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sun, 7 Jan 2018 21:31:24 +0000 Subject: dh: Fix missing $ in $startpoint Signed-off-by: Niels Thykier --- debian/changelog | 7 +++++++ dh | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index f9d9a5a9..b96c9182 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +debhelper (11.1.2) UNRELEASED; urgency=medium + + * dh: Fix non-sense error about a missing "startpoint object + method". + + -- Niels Thykier Sun, 07 Jan 2018 21:30:13 +0000 + debhelper (11.1.1) unstable; urgency=medium * dh: Fix an off-by-one in a compat check. This fixes an diff --git a/dh b/dh index 7e5322e0..47160317 100755 --- a/dh +++ b/dh @@ -767,7 +767,7 @@ for my $rules_command (@{$rules_targets}) { # "arch" packages. Otherwise, we might repeat # part of the "install-arch" sequence when we # should not. - $startpoint{$package} = $j + 1 if $j + 1 > startpoint{$package}; + $startpoint{$package} = $j + 1 if $j + 1 > $startpoint{$package}; last COMMAND; } } -- cgit v1.2.3 From 2a8d9efcca626d2027c093f11cd10c6909c81338 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sat, 20 Jan 2018 09:38:35 +0000 Subject: dh: Always run commands with sequence defined options Signed-off-by: Niels Thykier --- debian/changelog | 3 +++ dh | 3 +++ 2 files changed, 6 insertions(+) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index 4ef12475..36da02a1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -12,6 +12,9 @@ debhelper (11.1.3) UNRELEASED; urgency=medium * ninja.pm: Set LC_ALL=C.UTF-8 when calling ninja to avoid meson choking on UTF-8 characters when it embeds itself into e.g. the build or install. (Closes: #873831) + * dh: Remove the assumption that sequences will supply only + "safe no-op" parameters to commands. Thanks to Axel Beckert + and Sascha Steinbiss for the report. (Closes: #887727) -- Niels Thykier Sun, 14 Jan 2018 09:54:57 +0000 diff --git a/dh b/dh index 47160317..787462aa 100755 --- a/dh +++ b/dh @@ -998,6 +998,9 @@ sub can_skip { return 0 if $user_specified_options || (exists $ENV{DH_OPTIONS} && length $ENV{DH_OPTIONS}); + return 0 if exists($command_opts{$command}) + and @{$command_opts{$command}}; + if (! defined $skipinfo{$command}) { $skipinfo{$command}=[extract_skipinfo($command)]; } -- cgit v1.2.3 From 4d8d691b722075dc5a1a35ab900a6f059bb6d8f4 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sun, 28 Jan 2018 12:31:00 +0000 Subject: dh: Rename optimize_sequence to unpack_sequence It is not a super name, but "optimize" implies that dh will work if you skip the call. By renaming it to unpack we avoid that implication. Signed-off-by: Niels Thykier --- dh | 4 ++-- lib/Debian/Debhelper/SequencerUtil.pm | 6 ++++-- t/dh-sequencer.t | 26 +++++++++++++------------- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'dh') diff --git a/dh b/dh index 787462aa..566432ff 100755 --- a/dh +++ b/dh @@ -690,7 +690,7 @@ if ( -f $build_stamp_file and not compat(9)) { # In compat <= 8, the sequences are always inlined (those versions do not # recurse into debian/rules anyway). In compat 9+, we never inline an # existing rules target. -my ($rules_targets, $full_sequence) = optimize_sequence(\%sequences, +my ($rules_targets, $full_sequence) = unpack_sequence(\%sequences, $sequence, (!compat(8) ? 0 : 1), \%completed_sequences @@ -754,7 +754,7 @@ for my $rules_command (@{$rules_targets}) { run("debian/rules", $rules_target); my $override_packages = $sequence2packages{$rules_target} // \@packages; for my $package (@{$override_packages}) { - my (undef, $seq) = optimize_sequence(\%sequences, $rules_target, 1); + my (undef, $seq) = unpack_sequence(\%sequences, $rules_target, 1); COMMAND: for my $c (reverse(@{$seq})) { for my $j (0 .. $#{$full_sequence}) { if ($c eq $full_sequence->[$j]) { diff --git a/lib/Debian/Debhelper/SequencerUtil.pm b/lib/Debian/Debhelper/SequencerUtil.pm index 1aba9964..859ee145 100644 --- a/lib/Debian/Debhelper/SequencerUtil.pm +++ b/lib/Debian/Debhelper/SequencerUtil.pm @@ -12,7 +12,7 @@ use Exporter qw(import); our @EXPORT = qw( extract_rules_target_name to_rules_target - optimize_sequence + unpack_sequence rules_explicit_target DUMMY_TARGET ); @@ -31,9 +31,11 @@ sub to_rules_target { return 'debian/rules '.join(' ', @_); } -sub optimize_sequence { +sub unpack_sequence { my ($sequences, $sequence_name, $always_inline, $completed_sequences) = @_; my (@sequence, @targets, %seen, %non_inlineable_targets, @stack); + # Walk through the sequence effectively doing a DFS of the rules targets + # (when we are allowed to inline them). push(@stack, [@{$sequences->{$sequence_name}}]); while (@stack) { my $current_sequence = pop(@stack); diff --git a/t/dh-sequencer.t b/t/dh-sequencer.t index 47b9c05f..4d283aba 100755 --- a/t/dh-sequencer.t +++ b/t/dh-sequencer.t @@ -55,33 +55,33 @@ $Debian::Debhelper::SequencerUtil::RULES_PARSED = 1; is_deeply( - [optimize_sequence(\%sequences, 'build')], + [unpack_sequence(\%sequences, 'build')], [[], [@bd]], 'Inlined build sequence matches build-indep/build-arch'); is_deeply( - [optimize_sequence(\%sequences, 'install')], + [unpack_sequence(\%sequences, 'install')], [[], [@bd, @i]], 'Inlined install sequence matches build-indep/build-arch + install commands'); is_deeply( - [optimize_sequence(\%sequences, 'binary-arch')], + [unpack_sequence(\%sequences, 'binary-arch')], [[], [@bd, @i, @ba, @b]], 'Inlined binary-arch sequence has all the commands'); is_deeply( - [optimize_sequence(\%sequences, 'binary-indep')], + [unpack_sequence(\%sequences, 'binary-indep')], [[], [@bd, @i, @b]], 'Inlined binary-indep sequence has all the commands except @bd'); is_deeply( - [optimize_sequence(\%sequences, 'binary')], + [unpack_sequence(\%sequences, 'binary')], [[], [@bd, @i, @ba, @b]], 'Inlined binary sequence has all the commands'); is_deeply( - [optimize_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], [[], [@i, @ba, @b]], 'Inlined binary sequence with build-* done has @i, @ba and @b'); @@ -89,17 +89,17 @@ is_deeply( local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; is_deeply( - [optimize_sequence(\%sequences, 'binary')], + [unpack_sequence(\%sequences, 'binary')], [[to_rules_target('build')], [@i, @ba, @b]], 'Inlined binary sequence has all the commands but build target is opaque'); is_deeply( - [optimize_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], [[], [@i, @ba, @b]], 'Inlined binary sequence has all the commands with build-* done and not build-target'); is_deeply( - [optimize_sequence(\%sequences, 'build')], + [unpack_sequence(\%sequences, 'build')], [[], [@bd]], 'build sequence is inlineable'); @@ -109,9 +109,9 @@ is_deeply( local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; is_deeply( - [optimize_sequence(\%sequences, 'binary')], + [unpack_sequence(\%sequences, 'binary')], # @bd_minimal, @bd and @i should be "-i"-only, @ba + @b should be both. - # Unfortunately, optimize_sequence cannot show that. + # Unfortunately, unpack_sequence cannot show that. [[to_rules_target('install-arch')], [@bd, @i, @ba, @b]], 'Inlined binary sequence has all the commands'); } @@ -120,9 +120,9 @@ is_deeply( local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'install-arch'} = 1; local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; - my $actual = [optimize_sequence(\%sequences, 'binary')]; + my $actual = [unpack_sequence(\%sequences, 'binary')]; # @i should be "-i"-only, @ba + @b should be both. - # Unfortunately, optimize_sequence cannot show that. + # Unfortunately, unpack_sequence cannot show that. my $expected = [[to_rules_target('build'), to_rules_target('install-arch')], [@i, @ba, @b]]; # Permit some fuzz on the order between build and install-arch if ($actual->[0][0] eq to_rules_target('install-arch')) { -- cgit v1.2.3 From 30ea2c148eb780c3bdbc2269348794c2ef27b80a Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Wed, 7 Mar 2018 19:44:57 +0000 Subject: Move sub from dh to D::DH::SequencerUtil Signed-off-by: Niels Thykier --- dh | 17 ----------------- lib/Debian/Debhelper/SequencerUtil.pm | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 17 deletions(-) (limited to 'dh') diff --git a/dh b/dh index 566432ff..6afa234c 100755 --- a/dh +++ b/dh @@ -1047,23 +1047,6 @@ sub can_skip { return 1; } -sub extract_skipinfo { - my ($command) = @_; - - foreach my $dir (split (':', $ENV{PATH})) { - if (open (my $h, "<", "$dir/$command")) { - while (<$h>) { - if (m/PROMISE: DH NOOP( WITHOUT\s+(.*))?\s*$/) { - close $h; - return split(' ', $2) if defined($2); - return ('always-skip'); - } - } - close $h; - return (); - } - } -} =head1 SEE ALSO diff --git a/lib/Debian/Debhelper/SequencerUtil.pm b/lib/Debian/Debhelper/SequencerUtil.pm index 859ee145..c0d047db 100644 --- a/lib/Debian/Debhelper/SequencerUtil.pm +++ b/lib/Debian/Debhelper/SequencerUtil.pm @@ -14,6 +14,7 @@ our @EXPORT = qw( to_rules_target unpack_sequence rules_explicit_target + extract_skipinfo DUMMY_TARGET ); @@ -128,4 +129,24 @@ sub rules_explicit_target { return $EXPLICIT_TARGETS{$target}; } +sub extract_skipinfo { + my ($command) = @_; + + foreach my $dir (split(':', $ENV{PATH})) { + if (open (my $h, "<", "$dir/$command")) { + while (<$h>) { + if (m/PROMISE: DH NOOP( WITHOUT\s+(.*))?\s*$/) { + close $h; + return split(' ', $2) if defined($2); + return ('always-skip'); + } + } + close $h; + return; + } + } + return; +} + + 1; -- cgit v1.2.3 From 0e8a8e4ef4980405ba66cd42fa0c67e8b366143c Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Wed, 7 Mar 2018 20:39:47 +0000 Subject: dh: Simplify sequence definitions As of commit d68d6751a86052246433bf4381a5f8daac45f90d, the SequencerUtil function "unpack_sequence" should correctly transform the "compat 9"-style sequences into "compat 8"-style sequences. Exploit this to avoid the duplicated definitions. Signed-off-by: Niels Thykier --- debian/changelog | 1 + dh | 26 +++++++------------------- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index 79fb5520..5d3e85a3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ debhelper (11.1.6) UNRELEASED; urgency=medium attempt to make pkgfile() use "DEB_TARGET_ARCH{,_OS}" (see 11.1.5~alpha1). Thanks to Andreas Beckmann for reporting the issue. (Closes: #891546) + * dh: Refactor handling of sequences to simplify some code paths. -- Niels Thykier Mon, 26 Feb 2018 19:32:52 +0000 diff --git a/dh b/dh index 6afa234c..fb3b7776 100755 --- a/dh +++ b/dh @@ -452,25 +452,13 @@ $sequences{clean} = [@bd_minimal, qw{ }]; $sequences{'build-indep'} = [@bd]; $sequences{'build-arch'} = [@bd]; -if (! compat(8)) { - # From v9, sequences take standard rules targets into account. - $sequences{build} = [to_rules_target("build-arch"), to_rules_target("build-indep")]; - $sequences{'install-indep'} = [to_rules_target("build-indep"), @i]; - $sequences{'install-arch'} = [to_rules_target("build-arch"), @i]; - $sequences{'install'} = [to_rules_target("build"), to_rules_target("install-arch"), to_rules_target("install-indep")]; - $sequences{'binary-indep'} = [to_rules_target("install-indep"), @b]; - $sequences{'binary-arch'} = [to_rules_target("install-arch"), @ba, @b]; - $sequences{binary} = [to_rules_target("install"), to_rules_target("binary-arch"), to_rules_target("binary-indep")]; -} -else { - $sequences{build} = [@bd]; - $sequences{'install'} = [@{$sequences{build}}, @i]; - $sequences{'install-indep'} = [@{$sequences{'build-indep'}}, @i]; - $sequences{'install-arch'} = [@{$sequences{'build-arch'}}, @i]; - $sequences{binary} = [@{$sequences{install}}, @ba, @b]; - $sequences{'binary-indep'} = [@{$sequences{'install-indep'}}, @b]; - $sequences{'binary-arch'} = [@{$sequences{'install-arch'}}, @ba, @b]; -} +$sequences{build} = [to_rules_target("build-arch"), to_rules_target("build-indep")]; +$sequences{'install-indep'} = [to_rules_target("build-indep"), @i]; +$sequences{'install-arch'} = [to_rules_target("build-arch"), @i]; +$sequences{'install'} = [to_rules_target("build"), to_rules_target("install-arch"), to_rules_target("install-indep")]; +$sequences{'binary-indep'} = [to_rules_target("install-indep"), @b]; +$sequences{'binary-arch'} = [to_rules_target("install-arch"), @ba, @b]; +$sequences{binary} = [to_rules_target("install"), to_rules_target("binary-arch"), to_rules_target("binary-indep")]; # Additional command options my %command_opts; -- cgit v1.2.3 From 41fc7af0111ffd354b9c09fc81f3d922341acb07 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 10 May 2018 18:30:26 +0000 Subject: Enable dwz in c12 by default Closes: nthykier/debhelper#3 Signed-off-by: Niels Thykier --- debian/changelog | 5 +++++ dh | 6 ++++-- dh_dwz | 2 -- lib/Debian/Debhelper/Sequence/dwz.pm | 6 ++++-- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'dh') diff --git a/debian/changelog b/debian/changelog index 5aa2c0d3..0d2310e8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,11 @@ debhelper (11.3) UNRELEASED; urgency=medium had a valid symlink to it. Thanks to Andreas Hasenack for reporting the bug. (Closes: LP: #1765851) * debian/control: Depend on dwz for dh_dwz. + * dh_dwz: Generate a per-package multifile by default. This + feature can be disabled by --no-multifile. + * dh: Run dh_dwz by default in compat 12. + * dh_dwz/dwz.pm: Remove warning about the dwz feature being + experimental. [ Dmitry Shachnev ] * qmake.pm: Use ${DEB_HOST_GNU_TYPE}-qmake wrapper for diff --git a/dh b/dh index fb3b7776..10b018bb 100755 --- a/dh +++ b/dh @@ -432,11 +432,13 @@ qw{ dh_fixperms dh_missing }); -my @ba=qw{ +my @ba=( + (!compat(11) ? qw(dh_dwz) : qw()), +qw{ dh_strip dh_makeshlibs dh_shlibdeps -}; +}); if (! getpackages("arch")) { @ba=(); } diff --git a/dh_dwz b/dh_dwz index 66a33e5d..b90121f1 100755 --- a/dh_dwz +++ b/dh_dwz @@ -80,8 +80,6 @@ init(options => { # This variable can be used to turn off stripping (see Policy). exit 0 if get_buildoption('nostrip'); -warning('This tool is experimental and may change (or be retired) without any notice'); - my @elf_files; sub testfile { diff --git a/lib/Debian/Debhelper/Sequence/dwz.pm b/lib/Debian/Debhelper/Sequence/dwz.pm index 3db77561..eb8ef13e 100644 --- a/lib/Debian/Debhelper/Sequence/dwz.pm +++ b/lib/Debian/Debhelper/Sequence/dwz.pm @@ -3,9 +3,11 @@ use strict; use warnings; -use Debian::Debhelper::Dh_Lib qw(warning); +use Debian::Debhelper::Dh_Lib; -warning('The "dwz"-sequence is experimental and may change (or be retired) without any notice'); +if (not compat(11)) { + error("In compat 12, dh_dwz is run by default and the dwz-sequence is no longer required."); +} insert_before('dh_strip', 'dh_dwz'); -- cgit v1.2.3 From 41f1ca9ed464300f5a84c9aebbf699e8b0e77928 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Fri, 18 May 2018 18:35:28 +0000 Subject: dh_installinitramfs: New helper tool --- autoscripts/postinst-initramfs-hook | 5 +++ autoscripts/postrm-initramfs-hook | 5 +++ debhelper.pod | 8 ++++ debian/changelog | 3 ++ dh | 1 + dh_installinitramfs | 88 +++++++++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 autoscripts/postinst-initramfs-hook create mode 100644 autoscripts/postrm-initramfs-hook create mode 100755 dh_installinitramfs (limited to 'dh') diff --git a/autoscripts/postinst-initramfs-hook b/autoscripts/postinst-initramfs-hook new file mode 100644 index 00000000..7785c643 --- /dev/null +++ b/autoscripts/postinst-initramfs-hook @@ -0,0 +1,5 @@ +if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then + if [ -x /usr/sbin/update-initramfs ] && [ -e /etc/initramfs-tools/initramfs.conf ]; then + update-initramfs -u + fi +fi diff --git a/autoscripts/postrm-initramfs-hook b/autoscripts/postrm-initramfs-hook new file mode 100644 index 00000000..9f688943 --- /dev/null +++ b/autoscripts/postrm-initramfs-hook @@ -0,0 +1,5 @@ +if [ "$1" = "remove" ]; then + if [ -x /usr/sbin/update-initramfs ] && [ -e /etc/initramfs-tools/initramfs.conf ]; then + update-initramfs -u + fi +fi diff --git a/debhelper.pod b/debhelper.pod index 0635951c..16e9aea2 100644 --- a/debhelper.pod +++ b/debhelper.pod @@ -798,6 +798,14 @@ the B sequence obsolete and it will now fail with an error. If you want to skip B, then please insert an empty I target in F. +=item - + +The B tool automatically generates the maintainer +script snippets when it detects an initramfs hook script in the package. + +Previously, it would only generate these snippets when it installed +the hook itself. + =back =back diff --git a/debian/changelog b/debian/changelog index 81a1927e..fb602ab2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -53,6 +53,9 @@ debhelper (11.3) UNRELEASED; urgency=medium * Dh_Lib.pm: Re-organise exports. * Dh_Lib.pm: Retract "print_and_complex_doit"; the only potential consumer went with a different code snippet. + * dh_installinitramfs: New tool to install initramfs hook scripts and + handle related maintscripts. Thanks to Evgeni Golov for the + suggestion. (Closes: #491027) [ Dmitry Shachnev ] * qmake.pm: Use ${DEB_HOST_GNU_TYPE}-qmake wrapper for diff --git a/dh b/dh index 10b018bb..71d078c4 100755 --- a/dh +++ b/dh @@ -416,6 +416,7 @@ qw{ dh_installppp dh_installudev dh_installgsettings + dh_installinitramfs dh_bugfiles dh_ucf dh_lintian diff --git a/dh_installinitramfs b/dh_installinitramfs new file mode 100755 index 00000000..7b832031 --- /dev/null +++ b/dh_installinitramfs @@ -0,0 +1,88 @@ +#!/usr/bin/perl + +=head1 NAME + +dh_installinitramfs - install initramfs hooks and setup maintscripts + +=cut + +use strict; +use warnings; +use Debian::Debhelper::Dh_Lib; + +our $VERSION = DH_BUILTIN_VERSION; + +=head1 SYNOPSIS + +B [S>] [B<-n>] + +=head1 DESCRIPTION + +B is a debhelper program that is responsible for +installing Debian package provided initramfs hooks. + +If B installs or (in compat 12 or later) detects +one or more initramfs hooks in the package, then it also automatically +generates the F and F commands needed to interface +with the Debian initramfs system. These commands are inserted into +the maintainer scripts by L. + +=head1 FILES + +=over 4 + +=item debian/I.initramfs-hook + +Assumed to be an initramfs hook that will be installed into F<< +usr/share/initramfs-tools/hooks/I >> in the package build +directory. See B in L for more +information about initramfs hooks. + +=back + +=head1 OPTIONS + +=over 4 + +=item B<-n>, B<--no-scripts> + +Do not modify F/F scripts. + +=back + +=cut + +init(); + +# PROMISE: DH NOOP WITHOUT initramfs-hook tmp(usr/share/initramfs-tools/hooks) + +foreach my $package (@{$dh{DOPACKAGES}}) { + my $tmp = tmpdir($package); + my $hook_script = pkgfile($package, 'initramfs-hook'); + my $has_hooks; + my $hook_dir = "${tmp}/usr/share/initramfs-tools/hooks"; + + if ($hook_script ne '') { + install_dir($hook_dir); + install_file($hook_script, "${hook_dir}/${package}"); + $has_hooks = 1; + } elsif (-d $hook_dir and not is_empty_dir($hook_dir) and not compat(11)) { + $has_hooks = 1; + + } + + if ($has_hooks && ! $dh{NOSCRIPTS}) { + autoscript($package, 'postinst', 'postinst-initramfs-hook'); + autoscript($package, 'postrm', 'postrm-initramfs-hook') + } +} + +=head1 SEE ALSO + +L +L +L + +This program is a part of debhelper. + +=cut -- cgit v1.2.3 From 3cc5e6aea41f1b3d890712e622b5a4d732211936 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sat, 19 May 2018 08:13:05 +0000 Subject: Use a new sequence to toggle dh_installinitramfs in c11 and older Then we can make dh_installinitramfs do the same in all compat levels and people can simply opt-in with a "--with installinitramfs" in older compat levels. Signed-off-by: Niels Thykier --- debhelper.pod | 10 ++++++---- debian/changelog | 2 ++ dh | 4 +++- dh_installinitramfs | 2 +- lib/Debian/Debhelper/Sequence/installinitramfs.pm | 14 ++++++++++++++ 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 lib/Debian/Debhelper/Sequence/installinitramfs.pm (limited to 'dh') diff --git a/debhelper.pod b/debhelper.pod index 16e9aea2..924d4c4d 100644 --- a/debhelper.pod +++ b/debhelper.pod @@ -793,10 +793,12 @@ in F</examples>>.) =item - -The standard sequence in B now includes B by default. This makes -the B sequence obsolete and it will now fail with an error. If you want -to skip B, then please insert an empty I target in -F. +The standard sequence in B now includes B and +B by default. This makes the B and +B sequences obsolete and they will now fail with an +error. If you want to skip these commands, then please insert an +empty override target for them in F +(e.g. I) =item - diff --git a/debian/changelog b/debian/changelog index fb602ab2..b4adcf9b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -56,6 +56,8 @@ debhelper (11.3) UNRELEASED; urgency=medium * dh_installinitramfs: New tool to install initramfs hook scripts and handle related maintscripts. Thanks to Evgeni Golov for the suggestion. (Closes: #491027) + * installinitramfs.pm: New sequence to enable dh_installinitramfs in + compat 11 and earlier. [ Dmitry Shachnev ] * qmake.pm: Use ${DEB_HOST_GNU_TYPE}-qmake wrapper for diff --git a/dh b/dh index 71d078c4..2dc635bd 100755 --- a/dh +++ b/dh @@ -416,7 +416,9 @@ qw{ dh_installppp dh_installudev dh_installgsettings - dh_installinitramfs +}, + (!compat(11) ? qw(dh_installinitramfs) : qw()), +qw{ dh_bugfiles dh_ucf dh_lintian diff --git a/dh_installinitramfs b/dh_installinitramfs index 7b832031..e6980af3 100755 --- a/dh_installinitramfs +++ b/dh_installinitramfs @@ -66,7 +66,7 @@ foreach my $package (@{$dh{DOPACKAGES}}) { install_dir($hook_dir); install_file($hook_script, "${hook_dir}/${package}"); $has_hooks = 1; - } elsif (-d $hook_dir and not is_empty_dir($hook_dir) and not compat(11)) { + } elsif (-d $hook_dir and not is_empty_dir($hook_dir)) { $has_hooks = 1; } diff --git a/lib/Debian/Debhelper/Sequence/installinitramfs.pm b/lib/Debian/Debhelper/Sequence/installinitramfs.pm new file mode 100644 index 00000000..3c7b2b81 --- /dev/null +++ b/lib/Debian/Debhelper/Sequence/installinitramfs.pm @@ -0,0 +1,14 @@ +#!/usr/bin/perl +# Enable dh_installinitramfs + +use strict; +use warnings; +use Debian::Debhelper::Dh_Lib; + +if (not compat(11)) { + error("In compat 12, dh_installinitramfs is run by default and the installinitramfs-sequence is no longer required."); +} + +insert_after('dh_installgsettings', 'dh_installinitramfs'); + +1; -- cgit v1.2.3 From 7baf4b986eb04a5c949bfe1588e0dd2181bcf737 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sat, 4 Aug 2018 11:18:23 +0000 Subject: dh: Refactor --with/--without handling of add-ons Signed-off-by: Niels Thykier --- dh | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 19 deletions(-) (limited to 'dh') diff --git a/dh b/dh index 2dc635bd..a98d05cc 100755 --- a/dh +++ b/dh @@ -292,19 +292,7 @@ matches, the last one in the sequence will be used. # Stash this away before init modifies it. my @ARGV_orig=@ARGV; - -if (not compat(9, 1)) { - # Enable autoreconf'ing by default in compat 10 or later. Use the - # sequence add-on so existing --without=autoreconf - unshift(@ARGV, "--with=autoreconf"); - # Enable systemd support by default in compat 10 or later. - # - compat 11 injects the dh_installsystemd tool directly in the - # sequence instead of using a --with sequence. - unshift(@ARGV, "--with=systemd") if compat(10, 1); - unshift(@ARGV, "--with=build-stamp"); -} - -push(@{$dh{WITH}},split(",", $ENV{DH_EXTRA_ADDONS})) if $ENV{DH_EXTRA_ADDONS}; +my (@addons, @addon_requests); inhibit_log(); @@ -314,13 +302,12 @@ init(options => { "before=s" => \$dh{BEFORE}, "remaining" => \$dh{REMAINING}, "with=s" => sub { - my ($option,$value)=@_; - push @{$dh{WITH}},split(",", $value); + my ($option, $value) = @_; + push(@addon_requests, map { "+${_}" } split(",", $value)); }, "without=s" => sub { - my ($option,$value)=@_; - my %without = map { $_ => 1 } split(",", $value); - @{$dh{WITH}} = grep { ! $without{$_} } @{$dh{WITH}}; + my ($option, $value) = @_; + push(@addon_requests, map { "-${_}" } split(",", $value)); }, "l" => \&list_addons, "list" => \&list_addons, @@ -553,8 +540,59 @@ sub list_addons { exit 0; } +sub _compute_addons { + my (@addon_requests_from_args) = @_; + my (@enabled_addons, %disabled_addons, %enabled); + my @addon_requests; + + # Order is important; DH_EXTRA_ADDONS must come before everything + # else; then comes built-in and finally argument provided add-ons + # requests. + push(@addon_requests, map { "+${_}" } split(",", $ENV{DH_EXTRA_ADDONS})) + if $ENV{DH_EXTRA_ADDONS}; + if (not compat(9, 1)) { + # Enable autoreconf'ing by default in compat 10 or later. + push(@addon_requests, '+autoreconf'); + + # Enable systemd support by default in compat 10 or later. + # - compat 11 injects the dh_installsystemd tool directly in the + # sequence instead of using a --with sequence. + push(@addon_requests, '+systemd') if compat(10, 1); + push(@addon_requests, '+build-stamp'); + } + push(@addon_requests, @addon_requests_from_args); + + # Removing disabled add-ons are expensive (O(N) per time), so we + # attempt to make removals in bulk. Note that we have to be order + # preserving (due to #885580), so there is a limit to how "smart" + # we can be. + my $flush_disable_cache = sub { + @enabled_addons = grep { not exists($disabled_addons{$_}) } @enabled_addons; + for my $addon (keys(%disabled_addons)) { + delete($enabled{$addon}); + } + %disabled_addons = (); + }; + + for my $request (@addon_requests) { + if ($request =~ s/^[+]//) { + $flush_disable_cache->() if %disabled_addons; + push(@enabled_addons, $request) if not $enabled{$request}++; + } elsif ($request =~ s/^-//) { + $disabled_addons{$request} = 1; + } else { + error("Internal error: Invalid add-on request: $request (Missing +/- prefix)"); + } + } + + $flush_disable_cache->() if %disabled_addons; + return @enabled_addons; +} + +@addons = _compute_addons(@addon_requests); + # Load addons, which can modify sequences. -foreach my $addon (@{$dh{WITH}}) { +foreach my $addon (@addons) { my $mod="Debian::Debhelper::Sequence::$addon"; $mod=~s/-/_/g; eval "use $mod"; -- cgit v1.2.3 From 48b9bb654d19df85f913eb644e9748f128e05be6 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Sat, 4 Aug 2018 17:01:35 +0000 Subject: dh: Support autoloading sequences via Build-Depends Signed-off-by: Niels Thykier --- dh | 11 +++++++++++ lib/Debian/Debhelper/Dh_Lib.pm | 21 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'dh') diff --git a/dh b/dh index a98d05cc..52931ee2 100755 --- a/dh +++ b/dh @@ -55,6 +55,16 @@ This is used when there is a third-party package that provides debhelper commands. See the F file for documentation about the sequence addon interface. +A B relation on the package BI +implies a B<--with> I. This avoids the need for an explicit +B<--with> in F that only duplicates what is already +declared via the build dependencies in F. Note that +only relations in the B field are considered +(i.e. B and B are +deliberately unsupported). Please keep in mind that B insists on +"simple" relations (e.g. a relation like "BI | +B" will I imply B<--with> I). + =item B<--without> I The inverse of B<--with>, disables using the given addon. This option @@ -560,6 +570,7 @@ sub _compute_addons { push(@addon_requests, '+systemd') if compat(10, 1); push(@addon_requests, '+build-stamp'); } + push(@addon_requests, map { "+${_}" } Debian::Debhelper::Dh_Lib::bd_dh_sequences()); push(@addon_requests, @addon_requests_from_args); # Removing disabled add-ons are expensive (O(N) per time), so we diff --git a/lib/Debian/Debhelper/Dh_Lib.pm b/lib/Debian/Debhelper/Dh_Lib.pm index b07358d1..8d9f3476 100644 --- a/lib/Debian/Debhelper/Dh_Lib.pm +++ b/lib/Debian/Debhelper/Dh_Lib.pm @@ -1524,13 +1524,14 @@ sub is_cross_compiling { # As a side effect, populates %package_arches and %package_types # with the types of all packages (not only those returned). my (%package_types, %package_arches, %package_multiarches, %packages_by_type, - %package_sections, $sourcepackage, %package_cross_type); + %package_sections, $sourcepackage, %package_cross_type, %dh_bd_sequences); # Resets the arrays; used mostly for testing sub resetpackages { undef $sourcepackage; %package_types = %package_arches = %package_multiarches = %packages_by_type = %package_sections = %package_cross_type = (); + %dh_bd_sequences = (); } # Returns source package name @@ -1656,6 +1657,16 @@ sub getpackages { warning(" compat level into the file debian/compat. (E.g. \"echo ${clevel} > debian/compat\")"); error("Could not parse desired debhelper compat level from relation: $dep"); } + # Build-Depends on dh-sequence- OR dh-sequence- ( ) + if ($dep =~ m/^dh-sequence-(${PKGNAME_REGEX})\s*(?:[(]\s*(?:[<>]?=|<<|>>)\s*(${PKGVERSION_REGEX})\s*[)])?$/) { + my $sequence = $1; + if ($field ne 'build-depends') { + warning("Ignoring dh sequence add-on request for sequenece ${sequence} via ${field}: Please move it to the Build-Depends field"); + warning("The relation that triggered this warning was: ${dep} (from the ${field} field)"); + next; + } + $dh_bd_sequences{$sequence} = 1; + } } } $compat_from_bd = $final_level // -1; @@ -1942,6 +1953,14 @@ sub is_udeb { } } +# Only useful for dh(1) +sub bd_dh_sequences { + # Use $sourcepackage as check because %dh_bd_sequence can be empty + # after running getpackages(). + getpackages() if not defined($sourcepackage); + return sort(keys(%dh_bd_sequences)); +} + sub _concat_slurp_script_files { my (@files) = @_; my $res = ''; -- cgit v1.2.3