diff options
Diffstat (limited to 'dh')
-rwxr-xr-x | dh | 206 |
1 files changed, 181 insertions, 25 deletions
@@ -273,6 +273,7 @@ option to ensure they only work on architecture dependent packages. # Stash this away before init modifies it. my @ARGV_orig=@ARGV; my (@addons, @addon_requests); +our ($DH_INTERNAL_ADDON_TYPE, $DH_INTERNAL_ADDON_NAME); inhibit_log(); @@ -435,13 +436,111 @@ $sequences{binary} = [to_rules_target("install"), to_rules_target("binary-arch") # Additional command options my %command_opts; +my %commands_added_by_addon; + +sub _assert_not_conditional_sequence_addon { + my ($feature) = @_; + return if $DH_INTERNAL_ADDON_TYPE eq 'both'; + warning("The add-on ${DH_INTERNAL_ADDON_NAME} relies on a feature (${feature}) (possibly indirectly), which is " + . 'not supported for conditional debhelper sequence add-ons.'); + warning("Hint: You may have to move the build-dependency for dh-sequence-${DH_INTERNAL_ADDON_NAME} to " + . 'Build-Depends to avoid this error assuming it is possible to use the sequence unconditionally.'); + die("${feature} is not supported for conditional dh sequence add-ons.\n"); +} + +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}) { + 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 " + . 'Build-Depends to avoid this error assuming it is possible to use the sequence unconditionally.'); + die("The add-on ${DH_INTERNAL_ADDON_NAME} cannot be use conditionally for \"*-${DH_INTERNAL_ADDON_TYPE}\"" + . " targets\n"); + } + } + return @filtered; +} + +sub _register_cmd_added_by_addon { + my ($cmd) = @_; + my $existing = $commands_added_by_addon{$cmd}; + if ($existing) { + if ($existing->{'addon-type'} ne $DH_INTERNAL_ADDON_TYPE) { + my $old_addon_name = $existing->{'addon-name'}; + my $old_addon_type = $existing->{'addon-type'}; + # Technically, "both" could be made compatible with "indep" OR "arch" (but not both at the same time). + # Implement if it turns out to be relevant. + warning("Both dh sequence add-ons ${DH_INTERNAL_ADDON_NAME} and ${old_addon_name} have attempted to add " + . "the command $cmd (possibly indirectly)."); + warning("However, the two add-ons do not have compatible constraints (${DH_INTERNAL_ADDON_TYPE} vs. " + . "${old_addon_type})."); + warning("Hint: You may have to move the build-dependency for dh-sequence-<X> to " + . ' the same build-dependency field to avoid this error assuming it is possible.'); + die("Multiple sequences have conflicting requests for $cmd.\n"); + } + return; + } + + $commands_added_by_addon{$cmd} = { + 'addon-name' => $DH_INTERNAL_ADDON_NAME, + 'addon-type' => $DH_INTERNAL_ADDON_TYPE, + }; + return; +} + +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); + last; + } + } + } + return @sequences; +} # sequence addon interface sub _insert { my ($offset, $existing, $new) = @_; - foreach my $sequence (keys %sequences) { + my @affected_sequences = _sequences_containing_cmd($existing); + @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}}; - next unless grep $existing, @list; my @new; foreach my $command (@list) { if ($command eq $existing) { @@ -464,25 +563,43 @@ sub insert_after { } sub remove_command { my ($command) = @_; - foreach my $sequence (keys %sequences) { + # Implement if actually needed (I *think* it basically means to transform dh_foo to dh_foo -a/-i) + _assert_not_conditional_sequence_addon('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}}]; } - + return; } sub add_command { my ($command, $sequence) = @_; + _filter_sequences_for_conditional_add_ons($sequence); + _register_cmd_added_by_addon($command); unshift @{$sequences{$sequence}}, $command; + return; } sub add_command_at_end { my ($command, $sequence) = @_; + _filter_sequences_for_conditional_add_ons($sequence); + _register_cmd_added_by_addon($command); push(@{$sequences{$sequence}}, $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> + # and that implies smarter deduplication logic) + _assert_not_conditional_sequence_addon('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 + # dh_foo -a <extra_options> && dh_foo -i and that implies smarter deduplication logic) + _assert_not_conditional_sequence_addon('remove_command_options'); if (@cmd_options) { # Remove only specified options if (my $opts = $command_opts{$command}) { @@ -496,6 +613,7 @@ sub remove_command_options { # Clear all additional options delete $command_opts{$command}; } + return; } sub list_addons { @@ -522,9 +640,10 @@ sub list_addons { } sub _compute_addons { - my (@addon_requests_from_args) = @_; - my (@enabled_addons, %disabled_addons, %enabled); + 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); # Order is important; DH_EXTRA_ADDONS must come before everything # else; then comes built-in and finally argument provided add-ons @@ -541,7 +660,14 @@ 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()); + $bd_dh_sequences_ref = Debian::Debhelper::Dh_Lib::bd_dh_sequences(); + for my $addon_name (sort(keys(%{$bd_dh_sequences_ref}))) { + my $addon_type = $bd_dh_sequences_ref->{$addon_name}; + if ($addon_type eq 'both' or $sequence_type eq 'both' or $addon_type eq $sequence_type) { + push(@addon_requests, "+${addon_name}"); + } + } + push(@addon_requests, @addon_requests_from_args); # Removing disabled add-ons are expensive (O(N) per time), so we @@ -568,24 +694,12 @@ sub _compute_addons { } $flush_disable_cache->() if %disabled_addons; - return @enabled_addons; -} - -@addons = _compute_addons(@addon_requests); - -# Load addons, which can modify sequences. -foreach my $addon (@addons) { - my $mod="Debian::Debhelper::Sequence::$addon"; - $mod=~s/-/_/g; - eval "use $mod"; - if ($@) { - error("unable to load addon $addon: $@"); - } -} - -if (! exists $sequences{$sequence}) { - error "Unknown sequence $sequence (choose from: ". - join(" ", sort keys %sequences).")"; + return map { + { + 'name' => $_, + 'addon-type' => $bd_dh_sequences_ref->{$_} // 'both', + } + } @enabled_addons; } # The list of all packages that can be acted on. @@ -629,6 +743,39 @@ elsif ($sequence eq 'build-indep' || # ditto optimisation for arch indep @packages = @{$sequence2packages{$sequence}}; } + +@addons = _compute_addons($sequence, @addon_requests); + +# Load addons, which can modify sequences. +foreach my $addon (@addons) { + my $addon_name = $addon->{'name'}; + my $addon_type = $addon->{'addon-type'}; + my $mod="Debian::Debhelper::Sequence::${addon_name}"; + $mod=~s/-/_/g; + local $DH_INTERNAL_ADDON_NAME = $addon_name; + local $DH_INTERNAL_ADDON_TYPE = $addon_type; + eval "use $mod"; + if ($@) { + error("unable to load addon ${addon_name}: $@"); + } +} +if (%commands_added_by_addon) { + while (my ($cmd, $addon) = each(%commands_added_by_addon)) { + my $addon_type = $addon->{'addon-type'}; + if ($addon_type eq 'indep') { + unshift(@{$command_opts{$cmd}}, '-i'); + } elsif ($addon_type eq 'arch') { + unshift(@{$command_opts{$cmd}}, '-a'); + } + } +} + + +if (! exists $sequences{$sequence}) { + error "Unknown sequence $sequence (choose from: ". + join(" ", sort keys %sequences).")"; +} + while (@ARGV_orig) { my $opt=shift @ARGV_orig; if ($opt =~ /^--?(after|until|before|with|without)$/) { @@ -1018,6 +1165,15 @@ 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 |