diff options
-rwxr-xr-x | dh | 154 | ||||
-rw-r--r-- | lib/Debian/Debhelper/Sequence.pm | 127 | ||||
-rw-r--r-- | lib/Debian/Debhelper/SequencerUtil.pm | 143 | ||||
-rwxr-xr-x | t/dh-sequencer.t | 157 |
4 files changed, 456 insertions, 125 deletions
@@ -12,6 +12,7 @@ use constant { 'UNSKIPPABLE_CLI_OPTIONS_BUILD_SYSTEM' => q(-S|--buildsystem|-D|--sourcedir(?:ectory)?|-B|--builddir(?:ectory)?), }; use Debian::Debhelper::Dh_Lib; +use Debian::Debhelper::Sequence; use Debian::Debhelper::SequencerUtil; our $VERSION = DH_BUILTIN_VERSION; @@ -404,13 +405,19 @@ qw{ dh_fixperms dh_missing }); -my @ba=( +my @ba=(map { + { + 'command' => $_, + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + } +} ( (!compat(11) ? qw(dh_dwz) : qw()), qw{ dh_strip dh_makeshlibs dh_shlibdeps -}); +})); if (! getpackages("arch")) { @ba=(); } @@ -420,19 +427,28 @@ my @b=qw{ dh_md5sums dh_builddeb }; -$sequences{clean} = [@bd_minimal, qw{ + +sub _add_sequence { + my @args = @_; + my $seq = Debian::Debhelper::Sequence->new(@args); + my $name = $seq->name; + $sequences{$name} = $seq; + if ($seq->allowed_subsequences eq SEQUENCE_ARCH_INDEP_SUBSEQUENCES) { + for my $subseq ((SEQUENCE_TYPE_ARCH_ONLY, SEQUENCE_TYPE_INDEP_ONLY)) { + my $subname = "${name}-${subseq}"; + $sequences{$subname} = $seq; + } + } + return; +} + +_add_sequence('build', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, @bd); +_add_sequence('install', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("build"), @i); +_add_sequence('binary', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("install"), @ba, @b); +_add_sequence('clean', SEQUENCE_NO_SUBSEQUENCES, @bd_minimal, qw{ dh_auto_clean dh_clean -}]; -$sequences{'build-indep'} = [@bd]; -$sequences{'build-arch'} = [@bd]; -$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; @@ -452,34 +468,18 @@ sub _filter_sequences_for_conditional_add_ons { my @sequences = @_; # If it is unconditional, then there is no issues. return @sequences if $DH_INTERNAL_ADDON_TYPE eq 'both' or not @sequences; - # Typically, if you add a command to a sequence, then you will in fact add it to two. E.g. - # Adding dh_foo after dh_installdocs will affect both install-arch AND install-indep. We want - # this to "just work(tm)" with a conditional add-on to avoid too much hassle (i.e. only affect - # the relevant sequence). At the same time, we must abort if a sequence like "clean" is - # affected. - my (%sequence_stems, @filtered); - - for my $sequence_name (@sequences) { - my $sequence_type = _sequence_type($sequence_name); - my $sequence_stem = $sequence_name; - if ($sequence_type ne 'both') { - $sequence_stem =~ s/-\Q${sequence_type}//; - } - if ($sequence_type eq $DH_INTERNAL_ADDON_TYPE) { - push(@filtered, $sequence_name); - $sequence_stems{$sequence_stem} = 1; - } - elsif (not exists($sequence_stems{$sequence_stem})) { - $sequence_stems{$sequence_stem} = 0; - } - } - for my $sequence_name (@sequences) { - my $sequence_type = _sequence_type($sequence_name); - my $sequence_stem = $sequence_name; - if ($sequence_type ne 'both') { - $sequence_stem =~ s/-\Q${sequence_type}//; - } - if (not $sequence_stems{$sequence_stem}) { + for my $seq (@sequences) { + # Typically, if you add a command to a sequence, then you will in fact add it to two. E.g. + # Adding dh_foo after dh_installdocs will affect both install-arch AND install-indep. We want + # this to "just work(tm)" with a conditional add-on to avoid too much hassle (i.e. only affect + # the relevant sequence). At the same time, we must abort if a sequence like "clean" is + # affected. + # + # We solve the above by checking if the sequence has an -arch + an -indep variant and then + # insert the command only for that sequence variant. + + if ($seq->allowed_subsequences ne SEQUENCE_ARCH_INDEP_SUBSEQUENCES) { + my $sequence_name = $seq->name; warning("The add-on ${DH_INTERNAL_ADDON_NAME} attempted to modify the sequence ${sequence_name} (possibly " . "indirectly) but the add-on is conditional for \"*-${DH_INTERNAL_ADDON_TYPE}\" targets"); warning("Hint: You may have to move the build-dependency for dh-sequence-${DH_INTERNAL_ADDON_NAME} to " @@ -488,7 +488,7 @@ sub _filter_sequences_for_conditional_add_ons { . " targets\n"); } } - return @filtered; + return @sequences; } sub _register_cmd_added_by_addon { @@ -522,9 +522,10 @@ sub _sequences_containing_cmd { my ($cmd) = @_; my @sequences; foreach my $sequence_name (keys %sequences) { - for my $scmd (@{$sequences{$sequence_name}}) { - if ($scmd eq $cmd) { - push(@sequences, $sequence_name); + my $seq = $sequences{$sequence_name}; + for my $scmd (@{$seq->{'_cmds'}}) { + if ($scmd->{'command'} eq $cmd) { + push(@sequences, $seq); last; } } @@ -532,6 +533,15 @@ sub _sequences_containing_cmd { return @sequences; } +sub _seq_cmd { + my ($cmd_name) = @_; + return { + 'command' => $cmd_name, + 'command-options' => [], + 'sequence-limitation' => $DH_INTERNAL_ADDON_TYPE, + }; +} + # sequence addon interface sub _insert { my ($offset, $existing, $new) = @_; @@ -539,20 +549,8 @@ sub _insert { @affected_sequences = _filter_sequences_for_conditional_add_ons(@affected_sequences); return if not @affected_sequences; _register_cmd_added_by_addon($new); - foreach my $sequence (@affected_sequences) { - my @list=@{$sequences{$sequence}}; - my @new; - foreach my $command (@list) { - if ($command eq $existing) { - push @new, $new if $offset < 0; - push @new, $command; - push @new, $new if $offset > 0; - } - else { - push @new, $command; - } - } - $sequences{$sequence}=\@new; + for my $seq (@affected_sequences) { + $seq->_insert($offset, $existing, _seq_cmd($new)); } } sub insert_before { @@ -568,25 +566,38 @@ sub remove_command { my @affected_sequences = _sequences_containing_cmd($command); @affected_sequences = _filter_sequences_for_conditional_add_ons(@affected_sequences); return if not @affected_sequences; - foreach my $sequence (@affected_sequences) { - $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}]; + for my $seq (@affected_sequences) { + $seq->remove_command($command); } return; } sub add_command { my ($command, $sequence) = @_; - _filter_sequences_for_conditional_add_ons($sequence); + _assert_not_conditional_sequence_addon('add_command'); _register_cmd_added_by_addon($command); - unshift @{$sequences{$sequence}}, $command; + if (not exists($sequences{$sequence})) { + _add_sequence($sequence, SEQUENCE_NO_SUBSEQUENCES, _seq_cmd($command)); + } else { + my $seq = $sequences{$sequence}; + _filter_sequences_for_conditional_add_ons($seq); + $seq->add_command_at_start(_seq_cmd($command)) + } return; } sub add_command_at_end { my ($command, $sequence) = @_; - _filter_sequences_for_conditional_add_ons($sequence); + _assert_not_conditional_sequence_addon('add_command'); _register_cmd_added_by_addon($command); - push(@{$sequences{$sequence}}, $command); + if (not exists($sequences{$sequence})) { + _add_sequence($sequence, SEQUENCE_NO_SUBSEQUENCES, _seq_cmd($command)); + } else { + my $seq = $sequences{$sequence}; + _filter_sequences_for_conditional_add_ons($seq); + $seq->add_command_at_end(_seq_cmd($command)) + } return; } + sub add_command_options { my $command=shift; # Implement if actually needed (Complicated as dh_foo becomes dh_foo -a && dh_foo -i <extra_options> @@ -595,6 +606,7 @@ sub add_command_options { push @{$command_opts{$command}}, @_; return; } + sub remove_command_options { my ($command, @cmd_options) = @_; # Implement if actually needed (Complicated as dh_foo <extra_options> becomes @@ -643,7 +655,7 @@ sub _compute_addons { my ($sequence_name, @addon_requests_from_args) = @_; my (@enabled_addons, %disabled_addons, %enabled, $bd_dh_sequences_ref); my @addon_requests; - my $sequence_type = _sequence_type($sequence_name); + my $sequence_type = sequence_type($sequence_name); # Order is important; DH_EXTRA_ADDONS must come before everything # else; then comes built-in and finally argument provided add-ons @@ -1165,16 +1177,6 @@ sub can_skip { return 1; } -sub _sequence_type { - my ($sequence_name) = @_; - if ($sequence_name =~ m/-indep$/) { - return 'indep'; - } elsif ($sequence_name =~ m/-arch/) { - return 'arch'; - } - return 'both'; -} - =head1 SEE ALSO L<debhelper(7)> diff --git a/lib/Debian/Debhelper/Sequence.pm b/lib/Debian/Debhelper/Sequence.pm new file mode 100644 index 00000000..fc857055 --- /dev/null +++ b/lib/Debian/Debhelper/Sequence.pm @@ -0,0 +1,127 @@ +#!/usr/bin/perl +# +# Internal library functions for the dh(1) command + +package Debian::Debhelper::Sequence; +use strict; +use warnings; + +use Exporter qw(import); + +use Debian::Debhelper::SequencerUtil qw(extract_rules_target_name sequence_type SEQUENCE_NO_SUBSEQUENCES + SEQUENCE_ARCH_INDEP_SUBSEQUENCES SEQUENCE_TYPE_ARCH_ONLY SEQUENCE_TYPE_INDEP_ONLY SEQUENCE_TYPE_BOTH); + + +sub _as_command { + my ($input) = @_; + if (ref($input) eq 'HASH') { + return $input; + } + my $rules_target = extract_rules_target_name($input); + if (defined($rules_target)) { + my $sequence_type = sequence_type($rules_target); + return { + 'command' => $input, + 'command-options' => [], + 'sequence-limitation' => $sequence_type, + } + } + return { + 'command' => $input, + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_BOTH, + } +} + +sub new { + my ($class, $name, $sequence_type, @cmds) = @_; + return bless({ + '_name' => $name, + '_subsequences' => $sequence_type, + '_cmds' => [map {_as_command($_)} @cmds], + }, $class); +} + +sub name { + my ($this) = @_; + return $this->{'_name'}; +} + +sub allowed_subsequences { + my ($this) = @_; + return $this->{'_subsequences'}; +} + +sub _insert { + my ($this, $offset, $existing, $new) = @_; + my @list = @{$this->{'_cmds'}}; + my @new; + my $new_cmd = _as_command($new); + foreach my $command (@list) { + if ($command->{'command'} eq $existing) { + push(@new, $new_cmd) if $offset < 0; + push(@new, $command); + push(@new, $new_cmd) if $offset > 0; + } else { + push(@new, $command); + } + } + $this->{'_cmds'} = \@new; + return; +} + +sub remove_command { + my ($this, $command) = @_; + $this->{'_cmds'} = [grep { $_->{'command'} ne $command } @{$this->{'_cmds'}}]; + return; +} + +sub add_command_at_start { + my ($this, $command) = @_; + unshift(@{$this->{'_cmds'}}, _as_command($command)); + return; +} + +sub add_command_at_end { + my ($this, $command) = @_; + push(@{$this->{'_cmds'}}, _as_command($command)); + return; +} + +sub rules_target_name { + my ($this, $sequence_type) = @_; + die("Internal error: Invalid sequence type $sequence_type") if $sequence_type eq SEQUENCE_NO_SUBSEQUENCES; + my $name = $this->{'_name'}; + my $allowed_sequence_type = $this->{'_subsequences'}; + if ($sequence_type ne SEQUENCE_TYPE_BOTH and $allowed_sequence_type eq SEQUENCE_NO_SUBSEQUENCES) { + die("Internal error: Requested subsequence ${sequence_type} of sequence ${name}, but it has no subsequences"); + } + if ($sequence_type ne SEQUENCE_TYPE_BOTH) { + return "${name}-${sequence_type}"; + } + return $name; +} + +sub as_rules_target_command { + my ($this) = shift; + my $rules_name = $this->rules_target_name(@_); + return "debian/rules ${rules_name}"; +} + +sub flatten_sequence { + my ($this, $sequence_type) = @_; + die("Invalid sequence type $sequence_type") if $sequence_type eq SEQUENCE_NO_SUBSEQUENCES; + my @cmds; + for my $cmd_desc (@{$this->{'_cmds'}}) { + my $seq_limitation = $cmd_desc->{'sequence-limitation'}; + if ($seq_limitation eq $sequence_type or $sequence_type eq SEQUENCE_TYPE_BOTH or $seq_limitation eq SEQUENCE_TYPE_BOTH) { + my $cmd = $cmd_desc->{'command'}; + my @cmd_options = $cmd_desc->{'command-options'}; + push(@cmds, [$cmd, @cmd_options]); + next; + } + } + return @cmds; +} + +1; diff --git a/lib/Debian/Debhelper/SequencerUtil.pm b/lib/Debian/Debhelper/SequencerUtil.pm index 9a9ce2bf..a943357d 100644 --- a/lib/Debian/Debhelper/SequencerUtil.pm +++ b/lib/Debian/Debhelper/SequencerUtil.pm @@ -5,17 +5,30 @@ package Debian::Debhelper::SequencerUtil; use strict; use warnings; -use constant DUMMY_TARGET => 'debhelper-fail-me'; +use constant { + 'DUMMY_TARGET' => 'debhelper-fail-me', + 'SEQUENCE_NO_SUBSEQUENCES' => 'none', + 'SEQUENCE_ARCH_INDEP_SUBSEQUENCES' => 'both', + 'SEQUENCE_TYPE_ARCH_ONLY' => 'arch', + 'SEQUENCE_TYPE_INDEP_ONLY' => 'indep', + 'SEQUENCE_TYPE_BOTH' => 'both', +}; use Exporter qw(import); our @EXPORT = qw( extract_rules_target_name to_rules_target + sequence_type unpack_sequence rules_explicit_target extract_skipinfo DUMMY_TARGET + SEQUENCE_NO_SUBSEQUENCES + SEQUENCE_ARCH_INDEP_SUBSEQUENCES + SEQUENCE_TYPE_ARCH_ONLY + SEQUENCE_TYPE_INDEP_ONLY + SEQUENCE_TYPE_BOTH ); our (%EXPLICIT_TARGETS, $RULES_PARSED); @@ -32,39 +45,135 @@ sub to_rules_target { return 'debian/rules '.join(' ', @_); } +sub sequence_type { + my ($sequence_name) = @_; + if ($sequence_name =~ m/-indep$/) { + return 'indep'; + } elsif ($sequence_name =~ m/-arch/) { + return 'arch'; + } + return 'both'; +} + +sub _agg_subseq { + my ($current_subseq, $outer_subseq) = @_; + if ($current_subseq eq $outer_subseq) { + return $current_subseq; + } + if ($current_subseq eq 'both') { + return $outer_subseq; + } + return $current_subseq; +} + sub unpack_sequence { my ($sequences, $sequence_name, $always_inline, $completed_sequences) = @_; my (@sequence, @targets, %seen, %non_inlineable_targets, @stack); + my $sequence_type = sequence_type($sequence_name); # Walk through the sequence effectively doing a DFS of the rules targets # (when we are allowed to inline them). - push(@stack, [@{$sequences->{$sequence_name}}]); + my $seq = $sequences->{$sequence_name}; + push(@stack, [$seq->flatten_sequence($sequence_type)]); while (@stack) { my $current_sequence = pop(@stack); COMMAND: while (@{$current_sequence}) { my $command = shift(@{$current_sequence}); + if (ref($command) eq 'ARRAY') { + $command = $command->[0]; + } my $rules_target=extract_rules_target_name($command); next if (defined($rules_target) and exists($completed_sequences->{$rules_target})); - if (defined($rules_target) && ($always_inline || - ! exists($non_inlineable_targets{$rules_target}) && - ! defined(rules_explicit_target($rules_target)))) { - - # inline the sequence for this implicit target. + if (defined($rules_target) and $always_inline) { + my $subsequence = $sequences->{$rules_target}; + my $subseq_type = _agg_subseq(sequence_type($rules_target), $sequence_type); push(@stack, $current_sequence); - $current_sequence = [@{$sequences->{$rules_target}}]; + $current_sequence = [$subsequence->flatten_sequence($subseq_type)]; + } elsif (defined($rules_target)) { + my $subsequence = $sequences->{$rules_target}; + my $subseq_type = _agg_subseq(sequence_type($rules_target), $sequence_type); + my @subseq_types = ($subseq_type); + my %subtarget_status; + my ($transparent_subseq, $opaque_subseq, $subtarget_decided_both); + if ($subseq_type eq SEQUENCE_TYPE_BOTH) { + push(@subseq_types, SEQUENCE_TYPE_ARCH_ONLY, SEQUENCE_TYPE_INDEP_ONLY); + } + for my $ss_type (@subseq_types) { + my $full_rule_target = ($ss_type eq SEQUENCE_TYPE_BOTH) ? $rules_target : "${rules_target}-${ss_type}"; + if (exists($completed_sequences->{$full_rule_target})) { + $subtarget_status{$ss_type} = 'complete'; + last if $ss_type eq $subseq_type; + } + elsif (defined(rules_explicit_target($full_rule_target))) { + $subtarget_status{$ss_type} = 'opaque'; + last if $ss_type eq $subseq_type; + } + else { + $subtarget_status{$ss_type} = 'transparent'; + } + } + # At this point, %subtarget_status has 1 or 3 kv-pairs. + # - If it has 1, then just check that and be done + # - If it has 3, then "both" must be "transparent". + + if (scalar(keys(%subtarget_status)) == 3) { + if ($subtarget_status{${\SEQUENCE_TYPE_ARCH_ONLY}} eq $subtarget_status{${\SEQUENCE_TYPE_INDEP_ONLY}}) { + # The "both" target is transparent and the subtargets agree. This is the common case + # of "everything is transparent" (or both subtargets are opaque) and we reduce that by + # reducing it to only have one key. + %subtarget_status = ( $subseq_type => $subtarget_status{${\SEQUENCE_TYPE_ARCH_ONLY}} ); + # There is one special-case for this flow if both targets are opaque. + $subtarget_decided_both = 1; + } else { + # The subtargets have different status but we know that the "both" key must be irrelevant + # then. Remove it to simplify matters below. + delete($subtarget_status{${\SEQUENCE_TYPE_BOTH}}); + } + } + + if (scalar(keys(%subtarget_status)) == 1) { + # "Simple" case where we only have to check exactly one result + if ($subtarget_status{$subseq_type} eq 'opaque') { + $opaque_subseq = $subseq_type; + } + elsif ($subtarget_status{$subseq_type} eq 'transparent') { + $transparent_subseq = $subseq_type; + } + } else { + # Either can be transparent, opaque or complete at this point. + if ($subtarget_status{${\SEQUENCE_TYPE_ARCH_ONLY}} eq 'transparent') { + $transparent_subseq = SEQUENCE_TYPE_ARCH_ONLY + } elsif ($subtarget_status{${\SEQUENCE_TYPE_INDEP_ONLY}} eq 'transparent') { + $transparent_subseq = SEQUENCE_TYPE_INDEP_ONLY + } + if ($subtarget_status{${\SEQUENCE_TYPE_ARCH_ONLY}} eq 'opaque') { + $opaque_subseq = SEQUENCE_TYPE_ARCH_ONLY + } elsif ($subtarget_status{${\SEQUENCE_TYPE_INDEP_ONLY}} eq 'opaque') { + $opaque_subseq = SEQUENCE_TYPE_INDEP_ONLY + } + } + if ($opaque_subseq) { + if ($subtarget_decided_both) { + # Final special-case - we are here because the rules file define X-arch AND X-indep but + # not X. In this case, we want two d/rules X-{arch,indep} calls rather than a single + # d/rules X call. + for my $ss_type ((SEQUENCE_TYPE_ARCH_ONLY, SEQUENCE_TYPE_INDEP_ONLY)) { + my $rules_target_cmd = $subsequence->as_rules_target_command($ss_type); + push(@targets, $rules_target_cmd) if not $seen{$rules_target_cmd}++; + } + } else { + my $rules_target_cmd = $subsequence->as_rules_target_command($opaque_subseq); + push(@targets, $rules_target_cmd) if not $seen{$rules_target_cmd}++; + } + } + if ($transparent_subseq) { + push(@stack, $current_sequence); + $current_sequence = [$subsequence->flatten_sequence($transparent_subseq)]; + } 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; diff --git a/t/dh-sequencer.t b/t/dh-sequencer.t index dd5c264a..6c38eae2 100755 --- a/t/dh-sequencer.t +++ b/t/dh-sequencer.t @@ -4,6 +4,7 @@ use strict; use warnings; use Test::More; +use Debian::Debhelper::Sequence; use Debian::Debhelper::SequencerUtil; # Shorten variants of the sequences. @@ -21,46 +22,85 @@ my @i = (qw{ dh_install dh_missing }); -my @ba=qw{ - dh_strip - dh_makeshlibs - dh_shlibdeps -}; +my @ba = ( + { + 'command' => 'dh_strip', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + }, + { + 'command' => 'dh_makeshlibs', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + }, + { + 'command' => 'dh_shlibdeps', + 'command-options' => [], + 'sequence-limitation' => SEQUENCE_TYPE_ARCH_ONLY, + } +); my @b=qw{ dh_installdeb dh_gencontrol dh_builddeb }; +my @c=qw{ + dh_testdir + dh_auto_clean + dh_clean +}; -my %sequences = ( - 'build-indep' => [@bd], - 'build-arch' => [@bd], - 'build' => [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")], +my %sequences; + +sub _add_sequence { + my @args = @_; + my $seq = Debian::Debhelper::Sequence->new(@args); + my $name = $seq->name; + $sequences{$name} = $seq; + if ($seq->allowed_subsequences eq SEQUENCE_ARCH_INDEP_SUBSEQUENCES) { + for my $subseq ((SEQUENCE_TYPE_ARCH_ONLY, SEQUENCE_TYPE_INDEP_ONLY)) { + my $subname = "${name}-${subseq}"; + $sequences{$subname} = $seq; + } + } + return; +} - '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")], -); +_add_sequence('build', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, @bd); +_add_sequence('install', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("build"), @i); +_add_sequence('binary', SEQUENCE_ARCH_INDEP_SUBSEQUENCES, to_rules_target("install"), @ba, @b); +_add_sequence('clean', SEQUENCE_NO_SUBSEQUENCES, @c); + +sub _cmd_names { + my (@input) = @_; + my @cmds; + for my $cmd (@input) { + if (ref($cmd) eq 'HASH') { + push(@cmds, $cmd->{'command'}); + } else { + push(@cmds, $cmd); + } + } + return \@cmds; +} my %sequences_unpacked = ( - 'build-indep' => [@bd], - 'build-arch' => [@bd], - 'build' => [@bd], + 'build-indep' => _cmd_names(@bd), + 'build-arch' => _cmd_names(@bd), + 'build' => _cmd_names(@bd), + + 'install-indep' => _cmd_names(@bd, @i), + 'install-arch' => _cmd_names(@bd, @i), + 'install' => _cmd_names(@bd, @i), - 'install-indep' => [@bd, @i], - 'install-arch' => [@bd, @i], - 'install' => [@bd, @i], + 'binary-indep' => _cmd_names(@bd, @i, @b), + 'binary-arch' => _cmd_names(@bd, @i, @ba, @b), + 'binary' => _cmd_names(@bd, @i, @ba, @b), - 'binary-indep' => [@bd, @i, @b], - 'binary-arch' => [@bd, @i, @ba, @b], - 'binary' => [@bd, @i, @ba, @b], + 'clean' => _cmd_names(@c), ); -plan tests => 11 + 3 * scalar(keys(%sequences)); +plan tests => 18 + 3 * scalar(keys(%sequences)); # 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. @@ -95,20 +135,73 @@ is_deeply( is_deeply( [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], - [[], [@i, @ba, @b]], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + + +is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], 'Inlined binary sequence with build-* done has @i, @ba and @b'); { + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-arch'} = 1; + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-indep'} = 1; + + is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1, 'build-indep' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with build-* done has @i, @ba and @b'); + my $actual = [unpack_sequence(\%sequences, 'binary')]; + # @i should be "-i"-only, @ba + @b should be both. + # Unfortunately, unpack_sequence cannot show that. + my $expected = [[to_rules_target('build-arch'), to_rules_target('build-indep')], _cmd_names(@i, @ba, @b)]; + # Permit some fuzz on the order between build-arch and build-arch + if ($actual->[0][0] eq to_rules_target('build-indep')) { + $expected->[0][0] = to_rules_target('build-indep'); + $expected->[0][1] = to_rules_target('build-arch'); + } + is_deeply( + $actual, + $expected, + 'Inlined binary sequence with explicit build-* has explicit d/rules build-{arch,indep} + @i, @ba, @b'); + + is_deeply( + [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1})], + [[], _cmd_names(@i, @ba, @b)], + 'Inlined binary sequence with explicit build-* but done build has only @i, @ba and @b'); +} + +{ + local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build-indep'} = 1; + is_deeply( + [ unpack_sequence(\%sequences, 'binary', 0, { 'build-arch' => 1 }) ], + [ [to_rules_target('build-indep')], _cmd_names(@i, @ba, @b) ], + 'Inlined binary sequence with build-arch done and build-indep explicit has d/rules build-indep + @i, @ba and @b'); + + is_deeply( + [ unpack_sequence(\%sequences, 'binary-arch', 0, { 'build-arch' => 1 }) ], + [ [], _cmd_names(@i, @ba, @b) ], + 'Inlined binary-arch sequence with build-arch done and build-indep explicit has @i, @ba and @b'); + + + is_deeply( + [ unpack_sequence(\%sequences, 'binary-indep', 0, { 'build-arch' => 1 }) ], + [ [to_rules_target('build-indep')], _cmd_names(@i, @b) ], + 'Inlined binary-indep sequence with build-arch done and build-indep explicit has d/rules build-indep + @i and @b'); +} + +{ local $Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS{'build'} = 1; is_deeply( [unpack_sequence(\%sequences, 'binary')], - [[to_rules_target('build')], [@i, @ba, @b]], + [[to_rules_target('build')], _cmd_names(@i, @ba, @b)], 'Inlined binary sequence has all the commands but build target is opaque'); is_deeply( [unpack_sequence(\%sequences, 'binary', 0, { 'build' => 1, 'build-arch' => 1, 'build-indep' => 1})], - [[], [@i, @ba, @b]], + [[], _cmd_names(@i, @ba, @b)], 'Inlined binary sequence has all the commands with build-* done and not build-target'); is_deeply( @@ -133,7 +226,7 @@ is_deeply( [unpack_sequence(\%sequences, 'binary')], # @bd_minimal, @bd and @i should be "-i"-only, @ba + @b should be both. # Unfortunately, unpack_sequence cannot show that. - [[to_rules_target('install-arch')], [@bd, @i, @ba, @b]], + [[to_rules_target('install-arch')], _cmd_names(@bd, @i, @ba, @b)], 'Inlined binary sequence has all the commands'); # Compat <= 8 ignores explicit targets! @@ -152,7 +245,7 @@ is_deeply( my $actual = [unpack_sequence(\%sequences, 'binary')]; # @i should be "-i"-only, @ba + @b should be both. # Unfortunately, unpack_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')], _cmd_names(@i, @ba, @b)]; # Permit some fuzz on the order between build and install-arch if ($actual->[0][0] eq to_rules_target('install-arch')) { $expected->[0][0] = to_rules_target('install-arch'); |