+# Figure out at what point in the sequence to start for each package.
+my %logged;
+my %startpoint;
+foreach my $package (@{$dh{DOPACKAGES}}) {
+ if ($dh{AFTER}) {
+ # Run commands in the sequence that come after the
+ # specified command.
+ $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1;
+ }
+ 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..
+ my @log=loadlog($package);
+ $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) {
+ # Figure out which packages need to run this command.
+ my @exclude;
+ foreach my $package (@{$dh{DOPACKAGES}}) {
+ if ($startpoint{$package} > $i ||
+ $logged{$package}{$sequence[$i]}) {
+ push @exclude, $package;
+ }
+ }
+
+ if (@exclude eq @{$dh{DOPACKAGES}}) {
+ # Command already done for all packages.
+ 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);
+ }
+}
+
+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";
+ }
+
+ # The 4 spaces is a kind of half indent.
+ print " ".escape_shell($command, @options)."\n";