=head1 SYNOPSIS
-B<dh> sequence [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining> [S<I<debhelper options>>]
+B<dh> I<sequence> [B<--with> I<addon>[B<,>I<addon> ...]] [B<--list>] [S<I<debhelper options>>]
=head1 DESCRIPTION
-dh runs a sequence of debhelper commands. The supported sequences
-correspond to the targets of a debian/rules file: "build", "clean",
-"install", "binary-arch", "binary-indep", and "binary".
+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>.
-Commands in the binary-indep sequence are passed the "-i" option to ensure
-they only work on binary independent packages, and commands in the
-binary-arch sequences are passed the "-a" option to ensure they only work
-on architecture dependent packages.
+=head1 OVERRIDE TARGETS
-Options passed to dh are passed on to each command it runs. This can be
-used to set an option like "-v" or "-X" or "-N", as well as for more
-specialised options.
+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.
-Each debhelper command will record when it's successfully run in
-debian/package.log.debhelper. (Which dh_clean deletes.) So dh can tell
-which commands have already been run, for which packages, and skip running
-those commands again.
+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.
+(Note that to use this feature, you should Build-Depend on
+debhelper 7.0.50 or above.)
-Each time 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.
+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<--until> I<cmd>
-
-Run commands in the sequence until and including I<cmd>, then stop.
+=item B<--with> I<addon>[B<,>I<addon> ...]
-=item B<--before> I<cmd>
+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.
-Run commands in the sequence before I<cmd>, then stop.
+=item B<--without> I<addon>
-=item B<--after> I<cmd>
+The inverse of B<--with>, disables using the given addon.
-Run commands in the sequence that come after I<cmd>.
+=item B<--list>, B<-l>
-=item B<--remaining>
-
-Run all commands in the sequence that have yet to be run.
+List all available addons.
-=head1 COMMAND SPECIFICATION
+=item B<--no-act>
-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.
+Prints commands that would run for a given sequence, but does not run them.
-=cut
+=back
-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;
- }
-}
+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
dh binary-arch --no-act
-This is a very simple rules file, for packages where the default seqences of
+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 %@
+ 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 $@
-This is a simple rules file that is a good starting place for customisation.
-(It's also available in F</usr/share/doc/debhelper/examples/rules.simple>
+ 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 $@
- build:
- dh build
+ override_dh_fixperms:
+ dh_fixperms
+ chmod 4755 debian/foo/usr/bin/foo
- clean:
- dh clean
+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.
- install: build
- dh install
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with autotools_dev
- binary-arch: install
- dh binary-arch
+Python tools are not run by dh by default, due to the continual change
+in that area. (Before compatability level v9, dh does run B<dh_pysupport>.)
+Here is how to use B<dh_python2>.
- binary-indep: install
- dh binary-indep
+ #!/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.
- binary: binary-arch binary-indep
+ #!/usr/bin/make -f
+ %:
+ dh $@ --buildsystem=perl_build
-Often you'll want to pass an option to ./configure. This uses dh to run all
-commands before L<dh_auto_configure(1)>, then runs that command by hand,
-and then finished up by running the rest of the sequence. You could also
-run ./configure by hand, instead of bothering with using dh_auto_configure.
-And if necessary, you can add commands to run automake, etc here too.
+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.
- build:
- dh build --before configure
- dh_auto_configure --kitchen-sink=yes
- dh build --after configure
+ #!/usr/bin/make -f
+ %:
+ dh $@ --sourcedirectory=src
-Here's how to skip two automated in a row (configure and build), and
-instead run the commands by hand.
+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>.
- build:
- dh build --before configure
- ./mondoconfig
- make universe-explode-in-delight
- dh build --after build
+ #!/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
-Another common case is wanting to run some code manually after a particular
-debhelper command is run.
+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.
- binary-arch: install
- dh binary-arch --until dh_fixperms
- # dh_fixperms has run, now override it for one program
+ override_dh_fixperms-arch:
+ dh_fixperms
chmod 4755 debian/foo/usr/bin/foo
- # and continue
- dh binary-arch --after dh_fixperms
-It's also fine to run debhelper commands before starting the dh sequence.
-Just be sure to use the B<--remaining> option to ensure that commands
-that normally come before those in the sequence are still run.
+=head1 INTERNALS
- binary-arch: install
- dh_strip -X foo
- dh_fixperms -X bar
- dh binary-arch --remaining
+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;
-init();
+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)=@_;
+ @{$dh{WITH}} = grep { $_ ne $value } @{$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 completly 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;
-$sequences{build} = [qw{
+my @bd_minimal = qw{
+ dh_testdir
+};
+my @bd = qw{
dh_testdir
dh_auto_configure
dh_auto_build
dh_auto_test
-}],
-$sequences{clean} = [qw{
- dh_testdir
- dh_auto_clean
- dh_clean
-}];
-$sequences{install} = [@{$sequences{build}}, qw{
+};
+my @i = qw{
dh_testroot
- dh_clean
+ dh_prep
dh_installdirs
dh_auto_install
dh_installcatalogs
dh_installcron
dh_installdebconf
- dh_installcatalogs
dh_installemacsen
dh_installifupdown
dh_installinfo
dh_installudev
dh_installwm
dh_installxfonts
+ dh_installgsettings
+ dh_bugfiles
+ dh_ucf
dh_lintian
- dh_desktop
dh_gconf
dh_icons
dh_perl
- dh_python
- dh_scrollkeeper
dh_usrlocal
dh_link
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{'binary-indep'} = [@{$sequences{install}}, @b];
-$sequences{binary} = [@{$sequences{install}}, qw{
- dh_strip
- dh_makeshlibs
- dh_shlibdeps
-}, @b];
-$sequences{'binary-arch'} = [@{$sequences{binary}}];
+$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];
+}
-# Get the sequence of commands to run.
-if (! @ARGV) {
- error "specify a sequence to run";
+# 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}}, @_;
}
-my $sequence=shift;
+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 (chose from: ".
+ error "Unknown sequence $sequence (choose from: ".
join(" ", sort keys %sequences).")";
}
-my @sequence=@{$sequences{$sequence}};
+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;
-if ($sequence eq 'binary-arch') {
+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 'binary-indep') {
+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;
- next if $opt eq $sequence;
- if ($opt =~ /^--?(after|until|before)$/) {
+ if ($opt =~ /^--?(after|until|before|with|without)$/) {
shift @ARGV_orig;
next;
}
- elsif ($opt =~ /^--?(remaining|(after|until|before)=)/) {
+ elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with|without)=)/) {
next;
}
- push @options, $opt;
+ elsif ($opt=~/^-/) {
+ push @options, "-O".$opt;
+ }
+ elsif (@options) {
+ 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 (@{$dh{DOPACKAGES}}) {
+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
# 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..
- my @log=loadlog($package);
$startpoint{$package}=0;
COMMAND: foreach my $command (reverse @log) {
foreach my $i (0..$#sequence) {
# 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 @exclude;
- foreach my $package (@{$dh{DOPACKAGES}}) {
+ my @todo;
+ my @opts=@options;
+ foreach my $package (@packages) {
if ($startpoint{$package} > $i ||
$logged{$package}{$sequence[$i]}) {
- push @exclude, $package;
+ push @opts, "-N$package";
+ }
+ else {
+ push @todo, $package;
}
}
-
- if (@exclude eq @{$dh{DOPACKAGES}}) {
- # Command already done for all packages.
+ 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;
}
- elsif (! @exclude) {
- # Run command for all packages.
- run($sequence[$i], @options);
- }
- else {
- # Run command for only a subset of packages.
- run($sequence[$i], @options,
- map { "-N$_" } @exclude);
+
+ # 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.)
+ foreach my $override_type (undef, "arch", "indep") {
+ @todo = run_override($override_type, $command, \@todo, @opts);
}
+ next unless @todo;
+
+ run($command, @opts);
}
sub run {
my $command=shift;
my @options=@_;
-
- # dh_clean -k is a special case
- if ($command eq 'dh_clean' && $sequence ne 'clean') {
- unshift @options, "-k";
+
+ # 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;
}
+}
- # The 4 spaces is a kind of half indent.
- print " ".escape_shell($command, @options)."\n";
+# 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=@_;
- if (! $dh{NO_ACT}) {
- my $ret=system($command, @options);
- exit($ret) if $ret != 0;
+ 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 loadlog {
- my $package=shift;
- my $ext=pkgext($package);
-
- my @log;
- open(LOG, "<", "debian/${ext}log.debhelper");
- while (<LOG>) {
- chomp;
- push @log, $_;
- $logged{$package}{$_}=1;
- }
- close LOG;
- return @log;
+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 depenency 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;
+ }
}
=head1 SEE ALSO