diff options
Diffstat (limited to 'dh')
-rwxr-xr-x | dh | 979 |
1 files changed, 979 insertions, 0 deletions
@@ -0,0 +1,979 @@ +#!/usr/bin/perl -w + +=head1 NAME + +dh - debhelper command sequencer + +=cut + +use strict; +use Debian::Debhelper::Dh_Lib; + +=head1 SYNOPSIS + +B<dh> I<sequence> [B<--with> I<addon>[B<,>I<addon> ...]] [B<--list>] [S<I<debhelper options>>] + +=head1 DESCRIPTION + +B<dh> runs a sequence of debhelper commands. The supported I<sequence>s +correspond to the targets of a F<debian/rules> file: B<build-arch>, +B<build-indep>, B<build>, B<clean>, B<install-indep>, B<install-arch>, +B<install>, B<binary-arch>, B<binary-indep>, and B<binary>. + +=head1 OVERRIDE TARGETS + +A F<debian/rules> file using B<dh> can override the command that is run +at any step in a sequence, by defining an override target. + +To override I<dh_command>, add a target named B<override_>I<dh_command> to +the rules file. When it would normally run I<dh_command>, B<dh> will +instead call that target. The override target can then run the command with +additional options, or run entirely different commands instead. See +examples below. + +Override targets can also be defined to run only when building +architecture dependent or architecture independent packages. +Use targets with names like B<override_>I<dh_command>B<-arch> +and B<override_>I<dh_command>B<-indep>. +(Note that to use this feature, you should Build-Depend on +debhelper 8.9.7 or above.) + +=head1 OPTIONS + +=over 4 + +=item B<--with> I<addon>[B<,>I<addon> ...] + +Add the debhelper commands specified by the given addon to appropriate places +in the sequence of commands that is run. This option can be repeated more +than once, or multiple addons can be listed, separated by commas. +This is used when there is a third-party package that provides +debhelper commands. See the F<PROGRAMMING> file for documentation about +the sequence addon interface. + +=item B<--without> I<addon> + +The inverse of B<--with>, disables using the given addon. This option +can be repeated more than once, or multiple addons to disable can be +listed, separated by commas. + +=item B<--list>, B<-l> + +List all available addons. + +=item B<--no-act> + +Prints commands that would run for a given sequence, but does not run them. + +Note that dh normally skips running commands that it knows will do nothing. +With --no-act, the full list of commands in a sequence is printed. + +=back + +Other options passed to B<dh> are passed on to each command it runs. This +can be used to set an option like B<-v> or B<-X> or B<-N>, as well as for more +specialised options. + +=head1 EXAMPLES + +To see what commands are included in a sequence, without actually doing +anything: + + dh binary-arch --no-act + +This is a very simple rules file, for packages where the default sequences of +commands work with no additional options. + + #!/usr/bin/make -f + %: + dh $@ + +Often you'll want to pass an option to a specific debhelper command. The +easy way to do with is by adding an override target for that command. + + #!/usr/bin/make -f + %: + dh $@ + + override_dh_strip: + dh_strip -Xfoo + + override_dh_auto_configure: + dh_auto_configure -- --with-foo --disable-bar + +Sometimes the automated L<dh_auto_configure(1)> and L<dh_auto_build(1)> +can't guess what to do for a strange package. Here's how to avoid running +either and instead run your own commands. + + #!/usr/bin/make -f + %: + dh $@ + + override_dh_auto_configure: + ./mondoconfig + + override_dh_auto_build: + make universe-explode-in-delight + +Another common case is wanting to do something manually before or +after a particular debhelper command is run. + + #!/usr/bin/make -f + %: + dh $@ + + override_dh_fixperms: + dh_fixperms + chmod 4755 debian/foo/usr/bin/foo + +If your package uses autotools and you want to freshen F<config.sub> and +F<config.guess> with newer versions from the B<autotools-dev> package +at build time, you can use some commands provided in B<autotools-dev> +that automate it, like this. + + #!/usr/bin/make -f + %: + dh $@ --with autotools_dev + +Python tools are not run by dh by default, due to the continual change +in that area. (Before compatibility level v9, dh does run B<dh_pysupport>.) +Here is how to use B<dh_python2>. + + #!/usr/bin/make -f + %: + dh $@ --with python2 + +Here is how to force use of Perl's B<Module::Build> build system, +which can be necessary if debhelper wrongly detects that the package +uses MakeMaker. + + #!/usr/bin/make -f + %: + dh $@ --buildsystem=perl_build + +Here is an example of overriding where the B<dh_auto_>I<*> commands find +the package's source, for a package where the source is located in a +subdirectory. + + #!/usr/bin/make -f + %: + dh $@ --sourcedirectory=src + +And here is an example of how to tell the B<dh_auto_>I<*> commands to build +in a subdirectory, which will be removed on B<clean>. + + #!/usr/bin/make -f + %: + dh $@ --builddirectory=build + +If your package can be built in parallel, you can support parallel building +as follows. Then B<dpkg-buildpackage -j> will work. + + #!/usr/bin/make -f + %: + dh $@ --parallel + +Here is a way to prevent B<dh> from running several commands that you don't +want it to run, by defining empty override targets for each command. + + #!/usr/bin/make -f + %: + dh $@ + + # Commands not to run: + override_dh_auto_test override_dh_compress override_dh_fixperms: + +A long build process for a separate documentation package can +be separated out using architecture independent overrides. +These will be skipped when running build-arch and binary-arch sequences. + + #!/usr/bin/make -f + %: + dh $@ + + override_dh_auto_build-indep: + $(MAKE) -C docs + + # No tests needed for docs + override_dh_auto_test-indep: + + override_dh_auto_install-indep: + $(MAKE) -C docs install + +Adding to the example above, suppose you need to chmod a file, but only +when building the architecture dependent package, as it's not present +when building only documentation. + + override_dh_fixperms-arch: + dh_fixperms + chmod 4755 debian/foo/usr/bin/foo + +=head1 INTERNALS + +If you're curious about B<dh>'s internals, here's how it works under the hood. + +Each debhelper command will record when it's successfully run in +F<debian/package.debhelper.log>. (Which B<dh_clean> deletes.) So B<dh> can tell +which commands have already been run, for which packages, and skip running +those commands again. + +Each time B<dh> is run, it examines the log, and finds the last logged command +that is in the specified sequence. It then continues with the next command +in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining> +options can override this behavior. + +A sequence can also run dependent targets in debian/rules. For +example, the "binary" sequence runs the "install" target. + +B<dh> uses the B<DH_INTERNAL_OPTIONS> environment variable to pass information +through to debhelper commands that are run inside override targets. The +contents (and indeed, existence) of this environment variable, as the name +might suggest, is subject to change at any time. + +Commands in the B<build-indep>, B<install-indep> and B<binary-indep> +sequences are passed the B<-i> option to ensure they only work on +architecture independent packages, and commands in the B<build-arch>, +B<install-arch> and B<binary-arch> sequences are passed the B<-a> +option to ensure they only work on architecture dependent packages. + +=head1 DEPRECATED OPTIONS + +The following options are deprecated. It's much +better to use override targets instead. + +=over 4 + +=item B<--until> I<cmd> + +Run commands in the sequence until and including I<cmd>, then stop. + +=item B<--before> I<cmd> + +Run commands in the sequence before I<cmd>, then stop. + +=item B<--after> I<cmd> + +Run commands in the sequence that come after I<cmd>. + +=item B<--remaining> + +Run all commands in the sequence that have yet to be run. + +=back + +In the above options, I<cmd> can be a full name of a debhelper command, or +a substring. It'll first search for a command in the sequence exactly +matching the name, to avoid any ambiguity. If there are multiple substring +matches, the last one in the sequence will be used. + +=cut + +# Stash this away before init modifies it. +my @ARGV_orig=@ARGV; + +if (compat(8, 1)) { + # python-support was enabled by default before v9. + # (and comes first so python-central loads later and can disable it). + unshift @ARGV, "--with=python-support"; +} + +init(options => { + "until=s" => \$dh{UNTIL}, + "after=s" => \$dh{AFTER}, + "before=s" => \$dh{BEFORE}, + "remaining" => \$dh{REMAINING}, + "with=s" => sub { + my ($option,$value)=@_; + push @{$dh{WITH}},split(",", $value); + }, + "without=s" => sub { + my ($option,$value)=@_; + my %without = map { $_ => 1 } split(",", $value); + @{$dh{WITH}} = grep { ! $without{$_} } @{$dh{WITH}}; + }, + "l" => \&list_addons, + "list" => \&list_addons, + }, + # Disable complaints about unknown options; they are passed on to + # the debhelper commands. + ignore_unknown_options => 1, + # Bundling does not work well since there are unknown options. + bundling => 0, +); +inhibit_log(); +set_buildflags(); +warn_deprecated(); + +# If make is using a jobserver, but it is not available +# to this process, clean out MAKEFLAGS. This avoids +# ugly warnings when calling make. +if (is_make_jobserver_unavailable()) { + clean_jobserver_makeflags(); +} + +# Process the sequence parameter. +my $sequence; +if (! compat(7)) { + # From v8, the sequence is the very first parameter. + $sequence=shift @ARGV_orig; + if (defined $sequence && $sequence=~/^-/) { + error "Unknown sequence $sequence (options should not come before the sequence)"; + } +} +else { + # Before v8, the sequence could be at any position in the parameters, + # so was what was left after parsing. + $sequence=shift; + if (defined $sequence) { + @ARGV_orig=grep { $_ ne $sequence } @ARGV_orig; + } +} +if (! defined $sequence) { + error "specify a sequence to run"; +} +# make -B causes the rules file to be run as a target. +# 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) { + exit 0; +} + + +# Definitions of sequences. +my %sequences; +my @bd_minimal = qw{ + dh_testdir +}; +my @bd = qw{ + dh_testdir + dh_auto_configure + dh_auto_build + dh_auto_test +}; +my @i = qw{ + dh_testroot + dh_prep + dh_installdirs + dh_auto_install + + dh_install + dh_installdocs + dh_installchangelogs + dh_installexamples + dh_installman + + dh_installcatalogs + dh_installcron + dh_installdebconf + dh_installemacsen + dh_installifupdown + dh_installinfo + dh_installinit + dh_installmenu + dh_installmime + dh_installmodules + dh_installlogcheck + dh_installlogrotate + dh_installpam + dh_installppp + dh_installudev + dh_installwm + dh_installgsettings + dh_bugfiles + dh_ucf + dh_lintian + dh_gconf + dh_icons + dh_perl + dh_usrlocal + + dh_link + dh_installxfonts + dh_compress + dh_fixperms +}; +my @ba=qw{ + dh_strip + dh_makeshlibs + dh_shlibdeps +}; +if (! getpackages("arch")) { + @ba=(); +} +my @b=qw{ + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +}; +$sequences{clean} = [qw{ + dh_testdir + dh_auto_clean + dh_clean +}]; +$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")]; +} +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]; +} + +# Additional command options +my %command_opts; + +# sequence addon interface +sub _insert { + my $offset=shift; + my $existing=shift; + my $new=shift; + foreach my $sequence (keys %sequences) { + my @list=@{$sequences{$sequence}}; + next unless grep $existing, @list; + 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; + } +} +sub insert_before { + _insert(-1, @_); +} +sub insert_after { + _insert(1, @_); +} +sub remove_command { + my $command=shift; + foreach my $sequence (keys %sequences) { + $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}]; + } + +} +sub add_command { + my $command=shift; + my $sequence=shift; + unshift @{$sequences{$sequence}}, $command; +} +sub add_command_options { + my $command=shift; + push @{$command_opts{$command}}, @_; +} +sub remove_command_options { + my $command=shift; + if (@_) { + # Remove only specified options + if (my $opts = $command_opts{$command}) { + foreach my $opt (@_) { + $opts = [ grep { $_ ne $opt } @$opts ]; + } + $command_opts{$command} = $opts; + } + } + else { + # Clear all additional options + delete $command_opts{$command}; + } +} + +sub list_addons { + my %addons; + + for my $inc (@INC) { + eval q{use File::Spec}; + my $path = File::Spec->catdir($inc, "Debian/Debhelper/Sequence"); + if (-d $path) { + for my $module_path (glob "$path/*.pm") { + my $name = basename($module_path); + $name =~ s/\.pm$//; + $name =~ s/_/-/g; + $addons{$name} = 1; + } + } + } + + for my $name (sort keys %addons) { + print "$name\n"; + } + + exit 0; +} + +# Load addons, which can modify sequences. +foreach my $addon (@{$dh{WITH}}) { + 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).")"; +} +my @sequence=optimize_sequence(@{$sequences{$sequence}}); + +# The list of all packages that can be acted on. +my @packages=@{$dh{DOPACKAGES}}; + +# Get the options to pass to commands in the sequence. +# Filter out options intended only for this program. +my @options; +my $user_specified_options=0; +if ($sequence eq 'build-arch' || + $sequence eq 'install-arch' || + $sequence eq 'binary-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; +} +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; +} +while (@ARGV_orig) { + my $opt=shift @ARGV_orig; + if ($opt =~ /^--?(after|until|before|with|without)$/) { + shift @ARGV_orig; + next; + } + elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with|without)=)/) { + next; + } + elsif ($opt=~/^-/) { + push @options, "-O".$opt; + $user_specified_options=1 + unless $opt =~ /^--(parallel|buildsystem|sourcedirectory|builddirectory|)/; + } + elsif (@options) { + $user_specified_options=1; + if ($options[$#options]=~/^-O--/) { + $options[$#options].="=".$opt; + } + else { + $options[$#options].=$opt; + } + } +} + +# Figure out at what point in the sequence to start for each package. +my %logged; +my %startpoint; +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}, @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); + } + 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..$#sequence) { + if ($command eq $sequence[$i]) { + $startpoint{$package}=$i+1; + last COMMAND; + } + } + } + } +} + +# Figure out what point in the sequence to go to. +my $stoppoint=$#sequence; +if ($dh{UNTIL}) { + $stoppoint=command_pos($dh{UNTIL}, @sequence); +} +elsif ($dh{BEFORE}) { + $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1; +} + +# Now run the commands in the sequence. +foreach my $i (0..$stoppoint) { + my $command=$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]}) { + push @opts, "-N$package"; + } + else { + push @todo, $package; + } + } + next unless @todo; + + my $rules_target = rules_target($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; + } + + # Check for override targets in debian/rules, and run instead of + # the usual command. (The non-arch-specific override is tried first, + # for simplest semantics; mixing it with arch-specific overrides + # makes little sense.) + my @oldtodo=@todo; + foreach my $override_type (undef, "arch", "indep") { + @todo = run_override($override_type, $command, \@todo, @opts); + } + next unless @todo; + + if (can_skip($command, @todo) && ! $dh{NO_ACT}) { + # This mkdir is to avoid skipping the command causing + # breakage if some later command assumed that the + # command ran, and created the tmpdir, as a side effect. + # No commands in debhelper should make such an assuption, + # but there may be third party commands or other things + # in the rules file that does. + if (! compat(10)) { + foreach my $package (@todo) { + mkdir(tmpdir($package)); + } + } + next; + } + + # No need to run the command for any packages handled by the + # override targets. + my %todo=map { $_ => 1 } @todo; + foreach my $package (@oldtodo) { + if (! $todo{$package}) { + push @opts, "-N$package"; + } + } + + run($command, @opts); +} + +sub run { + my $command=shift; + my @options=@_; + + # Include additional command options if any + unshift @options, @{$command_opts{$command}} + if exists $command_opts{$command}; + + # 3 space indent lines the command being run up under the + # sequence name after "dh ". + print " ".escape_shell($command, @options)."\n"; + + return if $dh{NO_ACT}; + + my $ret=system($command, @options); + if ($ret >> 8 != 0) { + exit $ret >> 8; + } + elsif ($ret) { + exit 1; + } +} + +# Tries to run an override target for a command. Returns the list of +# packages that it was unable to run an override target for. +sub run_override { + my $override_type=shift; # arch, indep, or undef + my $command=shift; + my @packages=@{shift()}; + my @options=@_; + + my $override="override_$command". + (defined $override_type ? "-".$override_type : ""); + + # Check which packages are of the right architecture for the + # override_type. + my (@todo, @rest); + if (defined $override_type) { + foreach my $package (@packages) { + my $isall=package_arch($package) eq 'all'; + if (($override_type eq 'indep' && $isall) || + ($override_type eq 'arch' && !$isall)) { + push @todo, $package; + } + else { + push @rest, $package; + push @options, "-N$package"; + } + } + } + else { + @todo=@packages; + } + + my $has_explicit_target = rules_explicit_target($override); + return @packages unless defined $has_explicit_target; # no such override + return @rest if ! $has_explicit_target; # has empty override + return @rest unless @todo; # has override, but no packages to act on + + if (defined $override_type) { + # Ensure appropriate -a or -i option is passed when running + # an arch-specific override target. + my $opt=$override_type eq "arch" ? "-a" : "-i"; + push @options, $opt unless grep { $_ eq $opt } @options; + } + + # This passes the options through to commands called + # inside the target. + $ENV{DH_INTERNAL_OPTIONS}=join("\x1e", @options); + $ENV{DH_INTERNAL_OVERRIDE}=$command; + run("debian/rules", $override); + delete $ENV{DH_INTERNAL_OPTIONS}; + delete $ENV{DH_INTERNAL_OVERRIDE}; + + # Update log for overridden command now that it has + # finished successfully. + # (But avoid logging for dh_clean since it removes + # the log earlier.) + if (! $dh{NO_ACT} && $command ne 'dh_clean') { + write_log($command, @todo); + commit_override_log(@todo); + } + + return @rest; +} + +sub optimize_sequence { + my @sequence; + my %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 (@_) { + 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=shift; + if ($command =~ /^debian\/rules\s+(.*)/) { + return $1 + } + else { + return undef; + } +} + +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=shift; + + 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 (<MAKE>) { + 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') { + if (defined $dh{uc $deprecated}) { + warning("The --$deprecated option is deprecated. Use override targets instead."); + } + } +} + +sub command_pos { + my $command=shift; + my @sequence=@_; + + foreach my $i (0..$#sequence) { + if ($command eq $sequence[$i]) { + return $i; + } + } + + my @matches; + foreach my $i (0..$#sequence) { + if ($sequence[$i] =~ /\Q$command\E/) { + push @matches, $i; + } + } + if (! @matches) { + error "command specification \"$command\" does not match any command in the sequence" + } + else { + return pop @matches; + } +} + +my %skipinfo; +sub can_skip { + my $command=shift; + my @packages=@_; + + return 0 if $user_specified_options || + (exists $ENV{DH_OPTIONS} && length $ENV{DH_OPTIONS}); + + if (! defined $skipinfo{$command}) { + $skipinfo{$command}=[extract_skipinfo($command)]; + } + my @skipinfo=@{$skipinfo{$command}}; + return 0 unless @skipinfo; + + foreach my $package (@packages) { + foreach my $skipinfo (@skipinfo) { + if ($skipinfo=~/^tmp\((.*)\)$/) { + my $need=$1; + my $tmp=tmpdir($package); + return 0 if -e "$tmp/$need"; + } + elsif (pkgfile($package, $skipinfo) ne '') { + return 0; + } + } + } + return 1; +} + +sub extract_skipinfo { + my $command=shift; + + foreach my $dir (split (':', $ENV{PATH})) { + if (open (my $h, "<", "$dir/$command")) { + while (<$h>) { + if (m/PROMISE: DH NOOP WITHOUT\s+(.*)/) { + close $h; + return split(' ', $1); + } + } + close $h; + return (); + } + } +} + +=head1 SEE ALSO + +L<debhelper(7)> + +This program is a part of debhelper. + +=head1 AUTHOR + +Joey Hess <joeyh@debian.org> + +=cut |