summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Thykier <niels@thykier.net>2022-10-08 07:54:48 +0000
committerNiels Thykier <niels@thykier.net>2022-10-08 08:13:47 +0000
commit26d7d3926aaa6803511673fd110e2afe03195760 (patch)
tree746bf34a615f71c752596d0f95580d89636fa268
parent5b13b4c3c1b31ea6004c66ac876fec3ed1bc7b87 (diff)
dh_assistant: Support new detect-hook-targets command
Signed-off-by: Niels Thykier <niels@thykier.net>
-rw-r--r--debian/changelog3
-rwxr-xr-xdh49
-rwxr-xr-xdh_assistant131
3 files changed, 179 insertions, 4 deletions
diff --git a/debian/changelog b/debian/changelog
index 3a6583e1..c79d773a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -35,6 +35,9 @@ debhelper (13.10) UNRELEASED; urgency=medium
from `is_udeb`).
* Dh_Getopt.pm: Fix duplicated `warning` in output for a
particular warning.
+ * dh_assistant: Provide a new `detect-hook-targets` command.
+ * dh: Recommend using `dh_assistant detect-hook-targets` for
+ checking whether hook targets are correct.
[ Translations ]
* Update Portuguese translation (Américo Monteiro)
diff --git a/dh b/dh
index 8f0062fe..8e233821 100755
--- a/dh
+++ b/dh
@@ -72,8 +72,9 @@ and 12.8 (for hook targets).
=head2 Completely empty targets
-As a special optimization, B<dh> will skip a target if it is completely empty.
-This is mostly useful for override targets, where the command will simply be
+As a special optimization, B<dh> will skip a target if it is
+completely empty and does not depend on any other target. This is
+mostly useful for override targets, where the command will simply be
skipped without the overhead of invoking a dummy target.
Note that the target has to be completely empty for this to work:
@@ -90,8 +91,48 @@ Note that the target has to be completely empty for this to work:
=head2 Verifying targets are picked up by dh
-If you want to confirm that B<dh> has seen an override or a hook target, you
-can use the following command as an example:
+As of debhelper 13.10, you can use L<dh_assistant(1)> to see which override
+and hook targets will be seen by B<dh>. Here is an example run of L<dh_assistant(1)>
+along with its output:
+
+ $ dh_assistant detect-hook-targets
+ {
+ "commands-not-in-path": [
+ "dh_foo"
+ ],
+ "hook-targets": [
+ {
+ "command": "dh_strip_nondeterminism",
+ "is-empty": true,
+ "package-section-param": null,
+ "target-name": "override_dh_strip_nondeterminism"
+ },
+ {
+ "command": "dh_foo",
+ "is-empty": false,
+ "package-section-param": "-a",
+ "target-name": "override_dh_foo-arch"
+ }
+ ]
+ }
+
+The B<commands-not-in-path> is useful for spotting mistakes in the hook target
+names. A non-empty value implies one of more hook targets are related to a command
+that is either not installed or no command with that name exists at all. It is
+generally worth double checking these.
+
+Additionally, the B<is-empty> attribute for each hook target can be used for seeing
+whether a hook target triggers the L</Completely empty targets> optimization.
+
+If you are interested in the other attributes, please read the L<dh_assistant(1)>
+for the details.
+
+=head3 Verifying targets are picked up by dh (when debhelper is older than 13.10)
+
+
+
+On older versions of debhelper, you have to use B<dh> with B<--no-act>.
+You can use the following command as an example:
$ dh binary --no-act | grep dh_install | head -n5
dh_installdirs
diff --git a/dh_assistant b/dh_assistant
index fbd3986a..f65be8b8 100755
--- a/dh_assistant
+++ b/dh_assistant
@@ -156,6 +156,93 @@ is a build system if the build system does not use/set/define that variable.
=back
+=head2 detect-hook-targets (JSON)
+
+B<Synopsis>: B<dh_assistant> B<detect-hook-targets>
+
+Detects possible override targets and hook targets that L<dh(1)> might use (provided that the
+relevant command is in the sequence).
+
+The detection is based on scanning the rules file for any target that I<might look> like a hook
+target and can therefore list targets that are in fact not hook targets (or are but will never
+be triggered for other reasons).
+
+The detection uses a similar logic for scanning the rules file and is therefore subject to
+makefile conditionals (i.e., the truth value of makefile conditionals can change whether a hook
+target is visible in the output of this command). In theory, you would have to setup up the
+environment to look like it would during a build for getting the most accurate output. Though,
+a lot of packages will not have conditional hook targets, so the "out of the box" behaviour
+will work well in most cases.
+
+The output looks something like this:
+
+ {
+ "commands-not-in-path": [
+ "dh_foo"
+ ],
+ "hook-targets": [
+ {
+ "command": "dh_strip_nondeterminism",
+ "is-empty": true,
+ "package-section-param": null,
+ "target-name": "override_dh_strip_nondeterminism"
+ },
+ {
+ "command": "dh_foo",
+ "is-empty": false,
+ "package-section-param": "-a",
+ "target-name": "override_dh_foo-arch"
+ }
+ ]
+ }
+
+In more details:
+
+=over 4
+
+=item commands-not-in-path
+
+This attribute lists all the commands related to hook targets, which B<dh_assistant> could B<not>
+find in PATH. These are usually caused by either the command not being installed on the system
+where B<dh_assistant> is run or by the command not existing at all.
+
+If you are using this command to verify an hook target is present, please double check that the
+command is spelled correctly.
+
+=item hook-targets
+
+List over hook targets found along with additional information about them.
+
+=over 4
+
+=item command
+
+Attribute that lists which command this hook target is related too.
+
+=item target-name
+
+The actual target name detected in the F<debian/rules> file.
+
+=item is-empty
+
+A boolean that determines whether L<dh(1)> will optimize the hook out at runtime (see "Completely empty targets" in
+L<dh(1)>). Note that empty override targets will still cause L<dh(1)> to skip the original command.
+
+=item package-section-param
+
+This attribute defines what package selection parameter should be passed to B<dh_*> commands used
+in the hook target. It can either be B<-a>, B<-i> or (if no parameter should be used) C<null>.
+
+=back
+
+=back
+
+In the output, each hook target is associated with a B<is-empty> boolean. This boolean determines
+whether L<dh(1)> will optimize the hook out at runtime. Note that empty override targets will
+still cause L<dh(1)> to skip the original command.
+
+This command accepts no options or arguments.
+
=head2 COMMAND TAGS
Most commands have one or more of the following "tags" associated with them. Their
@@ -220,6 +307,7 @@ my %COMMANDS = (
'active-compat-level' => \&active_compat_level,
'supported-compat-levels' => \&supported_compat_levels,
'which-build-system' => \&which_build_system,
+ 'detect-hook-targets' => \&detect_hook_targets,
);
my ($COMMAND) = shift(@ARGV);
@@ -243,6 +331,7 @@ The following commands are available:
active-compat-level Output information about which compat level is declared/active (JSON)
supported-compat-levels Output information about supported compat levels (JSON, CRFA)
which-build-system Determine which build system will be used (JSON)
+ detect-hook-targets Detect and output possible override and hook targets (JSON)
Command tags:
@@ -355,6 +444,48 @@ sub which_build_system {
return;
}
+sub _in_path {
+ my ($cmd) = @_;
+ for my $dir (split(':', $ENV{PATH})) {
+ return 1 if -x "${dir}/${cmd}";
+ }
+ return 0;
+}
+
+sub detect_hook_targets {
+ if (@ARGV) {
+ error("$COMMAND: No arguments supported (please remove everything after the command)");
+ }
+ _assert_debian_control_exists();
+ require Debian::Debhelper::SequencerUtil;
+ Debian::Debhelper::SequencerUtil::rules_explicit_target('does-not-matter');
+ my ($explicit_targets, %result, @targets, @unverifiable_commands, %seen_cmds);
+ {
+ no warnings qw(once);
+ $explicit_targets = \%Debian::Debhelper::SequencerUtil::EXPLICIT_TARGETS;
+ }
+ while (my ($target, $non_empty) = each(%{$explicit_targets})) {
+ next if $target !~ m{^(?:execute_before_|execute_after_|override_)(\S+?)(-indep|-arch)?$};
+ my ($command, $archness) = ($1, $2);
+ my $param;
+ if ($archness) {
+ $param = ($archness eq '-arch') ? '-a' : '-i' ;
+ }
+ my $target_info = {
+ 'target-name' => $target,
+ 'command' => $command,
+ 'package-section-param' => $param,
+ 'is-empty' => $non_empty ? JSON::PP::false : JSON::PP::true,
+ };
+ push(@targets, $target_info);
+ push(@unverifiable_commands, $command) if not exists($seen_cmds{$command}) and not _in_path($command);
+ $seen_cmds{$command} = 1;
+ }
+ $result{'hook-targets'} = \@targets;
+ $result{'commands-not-in-path'} = \@unverifiable_commands;
+ _output(\%result);
+}
+
if (not defined($COMMAND)) {
error('Usage: ' . basename($0) . ' <command>');
}