summaryrefslogtreecommitdiffstats
path: root/dh_assistant
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-17 16:37:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-17 16:37:30 +0000
commitdbf14b11a1c911e6832e5518ae9c3e406245edaa (patch)
treef2b58ca7d37f97bf2c49862a31951aa103c06b12 /dh_assistant
parentReleasing progress-linux version 13.15.3-0.0~progress7.99u1. (diff)
downloaddebhelper-dbf14b11a1c911e6832e5518ae9c3e406245edaa.tar.xz
debhelper-dbf14b11a1c911e6832e5518ae9c3e406245edaa.zip
Merging upstream version 13.16.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dh_assistant')
-rwxr-xr-xdh_assistant232
1 files changed, 202 insertions, 30 deletions
diff --git a/dh_assistant b/dh_assistant
index 3d3337f..6a9297a 100755
--- a/dh_assistant
+++ b/dh_assistant
@@ -165,13 +165,17 @@ is a build system if the build system does not use/set/define that variable.
=back
-=head2 detect-hook-targets (AJSON)
+=head2 detect-hook-targets (EXEC, AJSON)
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).
+**UNSAFE**: This command relies on the output of L<make>. Even it its dry-run mode, B<make> may
+execute commands from F<debian/rules>. Avoid using on packages from untrusted sources, where you
+have not reviewed the packaging for backdoors.
+
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).
@@ -264,13 +268,17 @@ following command:
This command accepts no options or arguments.
-=head2 detect-unknown-hook-targets (AJSON, LINT)
+=head2 detect-unknown-hook-targets (EXEC, AJSON, LINT)
B<Synopsis>: B<dh_assistant> B<detect-unknown-hook-targets> [--output-format=json] [command-options]
Detects unknown and possibly misspelled override targets and hook targets in F<debian/rules> that
will most likely not be used by L<dh(1)>.
+**UNSAFE**: This command relies on the output of L<make>. Even it its dry-run mode, B<make> may
+execute commands from F<debian/rules>. Avoid using on packages from untrusted sources, where you
+have not reviewed the packaging for backdoors.
+
This command differs from B<detect-hook-targets> subtly in the scope. The B<detect-hook-targets>
will list all targets that looks like hook targets whether they are applicable or not. This
command show all hook targets, for which a command cannot be found in any sequence. Accordingly,
@@ -298,7 +306,15 @@ not stable, it will not be documented. The JSON output looks something like this
"execute_before_dh_install"
]
}
- ]
+ ],
+ "hook-targets-for-disabled-commands": [
+ {
+ "filename": "debian/rules",
+ "target-name": "override_dh_builddeb",
+ "removed-by": "zz-debputy"
+ }
+ ],
+
}
In more details:
@@ -333,8 +349,43 @@ following command:
When not null and not empty, each element in this list are names for likely candidates for the
"correct" name of this target.
+=back
+
+=item hook-targets-for-disabled-commands
+
+List of known hook targets found related to disabled commands along with additional information about them.
+
+=over 4
+
+=item target-name
+
+The actual target name detected in the file (usually F<debian/rules>).
+
=item filename
+This attribute reports which file the target was found it. In most cases, this will always be "debian/rules"
+though in case of include files, the target could appear in an include file. Note this attribute is not
+super reliable as L<make(1)> only reports it for targets with a "recipe" (targets with commands inside
+them). When B<make> does not provide the filename, B<dh_assistant> blindly assumes the filename is
+"debian/rules" (as overrides via includes is not a commonly used feature).
+
+Note this accuracy of this attribute is limited about what data B<dh_assistant> can read out from the
+following command:
+
+ LC_ALL=C make -Rrnpsf debian/rules debhelper-fail-me 2>/dev/null
+
+=item removed-by
+
+If present, this denotes the B<dh> add-on that removed the command from the sequence (thereby disabling
+this command for that package).
+
+Note this field is not present in all cases. As an example, as obsolete commands (such as B<dh_gconf>) are
+not part of any sequence by the time they are marked as obsolete.
+
+If you (as a consumer) need to know whether a command is obsolete or the particular reason why a command
+was disabled, please file a feature request to get that data. The absence of B<removed-by> is not
+guaranteed to imply the command is obsolete.
+
=back
=item issues
@@ -406,6 +457,11 @@ not stable, it will not be documented. The JSON output looks something like this
},
[... more commands listed here... ]
],
+ "removed-commands": [
+ {
+ "command": "dh_gconf"
+ },
+ ]
"issues": [
{
"issue": "load-addon",
@@ -432,6 +488,34 @@ While most commands are resolved via PATH, a sequence add-on could register a co
=back
+=item disabled-commands
+
+The top level key containing the list of all known commands that have been disabled. Each element in
+the list are an object and can have the following keys:
+
+=over 4
+
+=item command
+
+The name of the command.
+
+While most commands are resolved via PATH, a sequence add-on could register a command via a full path
+(by passing the path search). If so, the command provided in this output will also use the full path.
+
+=item removed-by
+
+If present, this denotes the B<dh> add-on that removed the command from the sequence (thereby disabling
+this command for that package).
+
+Note this field is not present in all cases. As an example, as obsolete commands (such as B<dh_gconf>) are
+not part of any sequence by the time they are marked as obsolete.
+
+If you (as a consumer) need to know whether a command is obsolete or the particular reason why a command
+was disabled, please file a feature request to get that data. The absence of B<removed-by> is not
+guaranteed to imply the command is obsolete.
+
+=back
+
=item issues
If present, then it is a list of one or more reasons why this output is definitely incomplete. Each element
@@ -476,9 +560,12 @@ These options behave the same as the L<dh(1)> options with the same name.
B<Synopsis>: B<dh_assistant> B<list-guessed-dh-config-files> [command-options]
-Load all B<dh> sequence add-ons, determine the full list of commands could be used by this
-source package and for each command used, then attempt to I<guess> which "config files"
-these commands are interested in.
+Load all B<dh> sequence add-ons declaratively depended on, determine the full list of
+commands could be relevant for this source package and for each command used, then
+attempt to I<guess> which "config files" these commands are interested in.
+
+The command will include config files for commands that are not active with current add-ons,
+since the commands might be run manually from hook targets.
Note this command only guesses "per command config files". Standard global config files
such as F<debian/control>, F<debian/rules>, and F<debian/compat> are not included in this
@@ -489,7 +576,8 @@ The B<dh_assistant> tool have to derive this from optional metadata that command
choose to provide and B<dh_assistant> has no means to validate that this metadata is up
to date.
-As the command will attempt to load all plugins, they must be installed.
+As the command will attempt to load all plugins referenced by the package, they must
+be installed.
The text output is intended for human consumption and should be self-explanatory. Since it is
not stable, it will not be documented. The JSON output looks something like this:
@@ -500,6 +588,7 @@ not stable, it will not be documented. The JSON output looks something like this
"commands": [
{
"command": "dh_autoreconf_clean"
+ "is-active": true
}
],
"file-type": "pkgfile",
@@ -509,6 +598,7 @@ not stable, it will not be documented. The JSON output looks something like this
"commands": [
{
"command": "dh_installgsettings"
+ "is-active": true
}
],
"file-type": "pkgfile",
@@ -577,6 +667,29 @@ which all reacts to (the now) deprecated B<tmpfile> pkgfile. In the particular c
to the file for a given compat level (but that information is not available to B<dh_assistant> and therefore
is not available in this output either).
+=item is-active
+
+A boolean that determines whether the command is active with the loaded sequences. When false, the command
+is known to debhelper, but it is not run automatically via B<dh>. The command might be explicitly removed
+by a sequence, marked as obsolete or possibly known to debhelper a command that would activate in a different
+command level (than the one currently active).
+
+Note that commands that are not "active" can often still be invoked manually from F<debian/rules> via hook
+targets. Therefore, this reflects whether B<dh> would call the command directly or provide its standard
+hook targets for the command.
+
+=item removed-by
+
+If present, this denotes the B<dh> add-on that removed the command from the sequence (thereby disabling
+this command for that package).
+
+Note this field is not present in all cases even when B<is-active> is true. As an example, as obsolete
+commands (such as B<dh_gconf>) are not part of any sequence by the time they are marked as obsolete.
+
+If you (as a consumer) need to know whether a command is obsolete or the particular reason why a command
+was disabled, please file a feature request to get that data. The absence of B<removed-by> plus
+B<is-active> being false is not guaranteed to imply the command is obsolete.
+
=back
=back
@@ -722,6 +835,15 @@ meaning is defined here.
=over 4
+=item EXEC
+
+This command will or may execute content from the package. Do not run on untrusted packages.
+
+Note: This tag only applies if the command will I<out of the box> be unsafe. As an example, commands that
+parse the output of B<make> is inherently unsafe, because it is trivial B<make> to have B<make> run
+code even in B<--dry-run> mode. As a counter example, commands that only loads B<dh> add-ons will be
+considered safe, because B<PERL5LIB> is assumed to be curated to only include trusted plugins.
+
=item AJSON
The command always provides JSON output. See L</JSON OUTPUT> for details.
@@ -734,7 +856,8 @@ do so by default. See L</JSON OUTPUT> for details when using B<--output-format=j
=item LINT
The command is or can be used for linting purposes. This command will exit with code 2 when an important
-issue is found.
+issue is found. B<Be careful> if the command is also tagged with B<EXEC>. When this happens, the
+command should only be used on trusted content (see the B<EXEC> tag for details).
Note that commands may have options that redefine what is considered an "important" issue.
@@ -789,6 +912,9 @@ $JSON_ENCODER = $JSON_ENCODER->pretty->space_before(0)->canonical if -t STDOUT;
# We never use the log file for this tool
inhibit_log();
$Debian::Debhelper::Dh_Lib::PARSE_DH_SEQUENCE_INFO = 1;
+# Force commands to opt-in
+$Debian::Debhelper::Dh_Lib::ALLOW_UNSAFE_EXECUTION = 0;
+
my %COMMANDS = (
'help' => \&_do_help,
@@ -827,9 +953,9 @@ The following commands are available:
active-compat-level Output information about which compat level is declared/active (AJSON)
supported-compat-levels Output information about supported compat levels (AJSON, CRFA)
which-build-system Determine which build system will be used (AJSON)
- detect-hook-targets Detect and output possible override and hook targets (AJSON)
+ detect-hook-targets Detect and output possible override and hook targets (EXEC, AJSON)
detect-unknown-hook-targets
- Detect unknown / typos of known hook targets (RJSON)
+ Detect unknown / typos of known hook targets (EXEC, LINT, RJSON)
list-commands List all commands across all sequences (RJSON)
list-guessed-dh-config-files
List guessed "config files" for debhelper commands (AJSON)
@@ -839,10 +965,11 @@ The following commands are available:
Command tags:
+ * EXEC *UNSAFE*: The command may execute code from the package. Do not use on unsafe content.
* AJSON The command always provides JSON output.
* RJSON The command *can* provide JSON output via --output-format=json.
* LINT The command is or can be used for linting purposes. This command will exit with code 2
- when an important issue is found.
+ when an important issue is found. Be careful when using commands also tagged EXEC!
* CRFA Command does not need to be run from a package source directory
(Mnemonic "Can be Run From Anywhere")
* BLD The command is intended to be used as a part of a package build.
@@ -875,6 +1002,10 @@ sub _output {
return;
}
+sub _allow_unsafe_execution() {
+ $Debian::Debhelper::Dh_Lib::ALLOW_UNSAFE_EXECUTION = 1;
+}
+
sub active_compat_level {
if (@ARGV) {
error("$COMMAND: No arguments supported (please remove everything after the command)");
@@ -1011,7 +1142,7 @@ sub _load_levenshtein {
sub _all_sequence_commands {
my ($forgive_errors, @addon_requests) = @_;
- my ($sequences, @all_commands, @unloadable);
+ my ($sequences, @all_commands, @unloadable, $commands_removed_by_sequence);
Debian::Debhelper::SequencerUtil::load_sequence_addon('root-sequence', 'both');
my @addons = Debian::Debhelper::SequencerUtil::compute_selected_addons('binary', @addon_requests);
# Load addons, which can modify sequences.
@@ -1029,8 +1160,10 @@ sub _all_sequence_commands {
{
no warnings qw(once);
$sequences = \%Debian::Debhelper::DH::SequenceState::sequences;
+ $commands_removed_by_sequence = \%Debian::Debhelper::DH::SequenceState::commands_removed_by_sequence;
}
my %seen;
+ my %disabled_commands = %{$commands_removed_by_sequence}; # Copy
for my $sequence(values(%{$sequences})) {
my @commands = map {$_->[0]} $sequence->flatten_sequence('both', 0);
for my $command (@commands) {
@@ -1038,9 +1171,10 @@ sub _all_sequence_commands {
next if exists($seen{$command});
$seen{$command} = 1;
push(@all_commands, $command);
+ delete($disabled_commands{$command});
}
}
- return \@all_commands, \@unloadable;
+ return \@all_commands, \%disabled_commands, \@unloadable;
}
sub list_commands {
@@ -1068,18 +1202,32 @@ sub list_commands {
my $value = $ARGV[0];
error("$COMMAND: No non-options supported - please remove ${value}");
}
-
- my ($all_commands, $unloadables) = _all_sequence_commands(1, @addon_requests);
+ my ($all_commands, $disabled_commands, $unloadables) = _all_sequence_commands(1, @addon_requests);
if ($output_format eq 'json') {
- my @commands_json;
+ my (@commands_json, %known_commands);
for my $command (sort(@{$all_commands})) {
push(@commands_json, {
'command' => $command,
});
+ $known_commands{$command} = 1;
}
my %result = (
"commands" => \@commands_json,
);
+ if (%{$disabled_commands}) {
+ my @remove_commands;
+ while (my ($command, $addon) = each(%{$disabled_commands})) {
+ next if $known_commands{$command};
+ my $data = {
+ 'command' => $command,
+ };
+ $data->{'removed-by'} = $addon if $addon;
+ push(@remove_commands, $data);
+ }
+ if (@remove_commands) {
+ $result{'disabled-commands'} = \@remove_commands;
+ }
+ }
if (@{$unloadables}) {
my @issues;
for my $addon (@{$unloadables}) {
@@ -1155,10 +1303,11 @@ sub list_guessed_dh_config_files {
error("$COMMAND: No non-options supported - please remove ${value}");
}
- my ($all_commands, $unloadables) = _all_sequence_commands(1, @addon_requests);
+ my ($active_commands, $disabled_cmds, $unloadables) = _all_sequence_commands(1, @addon_requests);
my $pkg_files = {};
my $bug_950723;
- for my $command (@{$all_commands}) {
+ my @all_commands = (@{$active_commands}, keys(%{$disabled_cmds}));
+ for my $command (@all_commands) {
my @annotations = _extract_annotations($command);
next if not @annotations or $annotations[0] eq 'always-skip';
for my $annotation (@annotations) {
@@ -1173,17 +1322,22 @@ sub list_guessed_dh_config_files {
next if $type ne 'pkgfile' and $type ne 'pkgfile-logged';
my $key = "pkgfile/${need}";
my $existing = $pkg_files->{$key};
+ my $is_active = not exists($disabled_cmds->{$command});
+ my $command_data = {
+ 'command' => $command,
+ 'is-active' => $is_active,
+ };
+ if (not $is_active) {
+ my $removed_by = $disabled_cmds->{$command};
+ $command_data->{'removed-by'} = $removed_by if $removed_by;
+ }
if (defined($existing)) {
- push(@{$existing->{'commands'}}, {
- 'command' => $command,
- });
+ push(@{$existing->{'commands'}}, $command_data);
} else {
$existing = {
'file-type' => 'pkgfile',
'pkgfile' => $need,
- 'commands' => [{
- 'command' => $command,
- }],
+ 'commands' => [$command_data],
};
$pkg_files->{$key} = $existing;
}
@@ -1213,6 +1367,7 @@ sub list_guessed_dh_config_files {
sub detect_unknown_hook_targets {
_assert_debian_control_exists();
+ _allow_unsafe_execution();
my $distance_func = _load_levenshtein();
require Getopt::Long;
Getopt::Long::config('no_ignore_case');
@@ -1221,8 +1376,8 @@ sub detect_unknown_hook_targets {
my (@addon_requests, %all_overrides, %unknown_hooks);
my $lint_exit = 1;
my %options=(
- "output-format=s" => \$output_format,
- "linter-exit-code!" => \$lint_exit,
+ "output-format=s" => \$output_format,
+ "linter-exit-code!" => \$lint_exit,
"with=s" => sub {
my ($option, $value) = @_;
push(@addon_requests, map { "+${_}" } split(",", $value));
@@ -1249,10 +1404,15 @@ sub detect_unknown_hook_targets {
$_ ne 'debhelper-fail-me' and !m{^(?:debian/rules|create-stamp)}
} keys(%{$explicit_targets});
- my ($all_commands, $unloadables) = _all_sequence_commands(1, @addon_requests);
- for my $command (@{$all_commands}) {
+ my ($activate_commands, $disabled_commands, $unloadables) = _all_sequence_commands(1, @addon_requests);
+ my @hook_targets_for_disabled_commands;
+ my @all_commands = (@{$activate_commands}, keys(%{$disabled_commands}));
+ for my $command (@all_commands) {
for my $variant (_hook_target_variants($command)) {
$all_overrides{$variant} = 1;
+ if (exists($missing_targets{$variant}) and exists($disabled_commands->{$command})) {
+ push(@hook_targets_for_disabled_commands, [$variant, $disabled_commands->{$command}]);
+ }
delete($missing_targets{$variant});
}
}
@@ -1276,7 +1436,7 @@ sub detect_unknown_hook_targets {
}
if ($output_format eq 'json') {
- my @hook_target_data;
+ my (@hook_target_data, @disabled_targets_data);
for my $target (sort(keys(%unknown_hooks))) {
my $options = $unknown_hooks{$target};
my (undef, $filename) = @{$explicit_targets->{$target}};
@@ -1286,8 +1446,19 @@ sub detect_unknown_hook_targets {
'candidates' => $options,
});
}
+ for my $rm_data (@hook_targets_for_disabled_commands) {
+ my ($target, $removed_by_sequence) = @{$rm_data};
+ my (undef, $filename) = @{$explicit_targets->{$target}};
+ my $data = {
+ 'target-name' => $target,
+ 'filename' => $filename,
+ };
+ $data->{'removed-by'} = $removed_by_sequence if $removed_by_sequence;
+ push(@disabled_targets_data, $data);
+ }
my %result = (
- "unknown-hook-targets" => \@hook_target_data,
+ "unknown-hook-targets" => \@hook_target_data,
+ "hook-targets-for-disabled-commands" => \@disabled_targets_data,
);
if (@{$unloadables}) {
my @issues;
@@ -1335,6 +1506,7 @@ sub detect_hook_targets {
error("$COMMAND: No arguments supported (please remove everything after the command)");
}
_assert_debian_control_exists();
+ _allow_unsafe_execution();
my $explicit_targets = _load_hook_targets();
my (%result, @targets, @unverifiable_commands, %seen_cmds);
while (my ($target, $rule_details) = each(%{$explicit_targets})) {