+# 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.)
+ 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=@_;
+
+ # 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;
+}