]> git.donarmstrong.com Git - debhelper.git/blobdiff - dh
I lied, one more v7 change slipped in..
[debhelper.git] / dh
diff --git a/dh b/dh
index e5a43a9ad926ca63a80790a1510a3dc8cc7f4281..2c36c95563e842d15762fdb6334937c740e93a49 100755 (executable)
--- a/dh
+++ b/dh
@@ -29,7 +29,7 @@ used to set an option like "-v" or "-X" or "-N", as well as for more
 specialised options.
 
 Each debhelper command will record when it's successfully run in
-debian/package.log.debhelper. (Which dh_clean deletes.) So dh can tell
+debian/package.debhelper.log. (Which dh_clean deletes.) So dh can tell
 which commands have already been run, for which packages, and skip running
 those commands again.
 
@@ -58,19 +58,45 @@ Run commands in the sequence that come after I<cmd>.
 
 Run all commands in the sequence that have yet to be run.
 
-=head1 COMMAND SPECIFICATON
+=head1 COMMAND SPECIFICATION
 
 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
+
+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 EXAMPLES
 
 To see what commands are included in a sequence, without actually doing
 anything:
 
-       dh binary-arch -n
+       dh binary-arch --no-act
 
 This is a very simple rules file, for packages where the default seqences of
 commands work with no additional options.
@@ -124,20 +150,24 @@ instead run the commands by hand.
 Another common case is wanting to run some code manually after a particular
 debhelper command is run.
 
-       binary-arch: install
-               dh binary-arch --until dh_fixperms
+       install: build
+               dh install --until dh_fixperms
                # dh_fixperms has run, now override it for one program
                chmod 4755 debian/foo/usr/bin/foo
                # and continue
-               dh binary-arch --after dh_fixperms
+               dh install --after dh_fixperms
 
-It's also fine to run debhelper commands before starting the dh sequence.
+It's also fine to run debhelper commands before starting a 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.
 
+       install:
+               dh_installdocs README TODO
+               dh_installchangelogs Changes
+               dh install --remaining
+
         binary-arch: install
                 dh_strip -X foo
-                dh_fixperms -X bar
                 dh binary-arch --remaining
 
 =cut
@@ -146,6 +176,7 @@ that normally come before those in the sequence are still run.
 my @ARGV_orig=@ARGV;
 
 init();
+inhibit_log();
 
 # Definitions of sequences.
 my %sequences;
@@ -160,7 +191,9 @@ $sequences{clean} = [qw{
        dh_auto_clean
        dh_clean
 }];
-$sequences{install} = [@{$sequences{build}}, "dh_testroot", "dh_clean -k", qw{
+$sequences{install} = [@{$sequences{build}}, qw{
+       dh_testroot
+       dh_prep
        dh_installdirs
        dh_auto_install
 
@@ -181,6 +214,8 @@ $sequences{install} = [@{$sequences{build}}, "dh_testroot", "dh_clean -k", qw{
        dh_installmenu
        dh_installmime
        dh_installmodules
+       dh_installlogcheck
+       dh_installlogrotate
        dh_installpam
        dh_installppp
        dh_installudev
@@ -190,18 +225,17 @@ $sequences{install} = [@{$sequences{build}}, "dh_testroot", "dh_clean -k", qw{
        dh_desktop
        dh_gconf
        dh_icons
-       dh_logcheck
-       dh_logrotate
        dh_perl
-       dh_python
+       dh_pysupport
        dh_scrollkeeper
-       dh_uselocal
+       dh_usrlocal
 
        dh_link
        dh_compress
        dh_fixperms
 }];
 my @b=qw{
+       dh_installdeb
        dh_gencontrol
        dh_md5sums
        dh_builddeb
@@ -214,7 +248,14 @@ $sequences{binary} = [@{$sequences{install}}, qw{
 }, @b];
 $sequences{'binary-arch'} = [@{$sequences{binary}}];
 
-# Sequence parameter.
+# Third-party commands can be listed in the sequences, but should be
+# listed here as well. They will not be run if not present.
+my %thirdparty=(
+       dh_pycompat => 1,
+       dh_pysupport => 1,
+);
+
+# Get the sequence of commands to run.
 if (! @ARGV) {
        error "specify a sequence to run";
 }
@@ -223,6 +264,7 @@ if (! exists $sequences{$sequence}) {
        error "Unknown sequence $sequence (chose from: ".
                join(" ", sort keys %sequences).")";
 }
+my @sequence=@{$sequences{$sequence}};
 
 # Get the options to pass to commands in the sequence.
 # Filter out options intended only for this program.
@@ -246,17 +288,125 @@ while (@ARGV_orig) {
        push @options, $opt;
 }
 
-@options=grep {
-       $_ ne $sequence && !/^--?(before|after|remaining)$/
-} @options;
+# Figure out at what point in the sequence to start for each package.
+my %logged;
+my %startpoint;
+foreach my $package (@{$dh{DOPACKAGES}}) {
+       my @log=loadlog($package);
+       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.
+               writelog($package, $sequence[$startpoint{$package}-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..                         
+               $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=@_;
+       
+       # If a third party command is not in /usr/bin, don't try to run it.
+       if ($thirdparty{$command} && ! -x "/usr/bin/$command") {
+               return;
+       }
 
-foreach my $cmd (@{$sequences{$sequence}}) {
-       print "$cmd @options\n";
+       # 3 space indent lines the command being run up under the 
+       # sequence name after "dh ".
+       print "   ".escape_shell($command, @options)."\n";
+
+       if (! $dh{NO_ACT}) {
+               my $ret=system($command, @options);
+               if ($ret >> 8 != 0) {
+                       exit $ret >> 8;
+               }
+               elsif ($ret) {
+                       exit 1;
+               }
+       }
 }
 
-foreach my $package (@{$dh{DOPACKAGES}}) {
-       my $tmp=tmpdir($package);
+sub loadlog {
+       my $package=shift;
+       my $ext=pkgext($package);
+       
+       my @log;
+       open(LOG, "<", "debian/${ext}debhelper.log") || return;
+       while (<LOG>) {
+               chomp;
+               push @log, $_;
+               $logged{$package}{$_}=1;
+       }
+       close LOG;
+       return @log;
+}
+               
+sub writelog {
+       my $package=shift;
+       my $cmd=shift;
        my $ext=pkgext($package);
+       
+       open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
+       print LOG $cmd."\n";
+       close LOG;
 }
 
 =head1 SEE ALSO