]> git.donarmstrong.com Git - debhelper.git/blobdiff - dh
dh: Disable option bundling to avoid mis-parsing bundled options such as "-Bpython...
[debhelper.git] / dh
diff --git a/dh b/dh
index d0165c9969394d4e2e65d9d9204eb1c00f009fd9..2b60be5d4ffc701a45bb95ca01fff14f5fbffa2f 100755 (executable)
--- a/dh
+++ b/dh
@@ -11,7 +11,7 @@ use Debian::Debhelper::Dh_Lib;
 
 =head1 SYNOPSIS
 
-B<dh> sequence [B<--with> I<addon>] [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [S<I<debhelper options>>]
+B<dh> sequence [B<--with> I<addon>[,I<addon>,...]] [B<--list>] [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [S<I<debhelper options>>]
 
 =head1 DESCRIPTION
 
@@ -35,23 +35,31 @@ in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining>
 options can override this behavior.
 
 If debian/rules contains a target with a name like "override_I<dh_command>",
-then when it gets to that command in the sequence, dh will run that
-target from the rules file, rather than running the actual command. The
-override target can then run the command with additional options, or run
-entirely different commands instead. (Note that to use this feature,
-you should Build-Depend on debhelper 7.2 or above.)
+then when it would normally run I<dh_command>, 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.)
 
 =head1 OPTIONS
 
 =over 4
 
-=item B<--with> I<addon>
+=item B<--with> I<addon>[,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, and is used when there is a third-party package that provides
-debhelper commands. See "SEQUENCE ADDONS" below for documentation about what
-such packages should do to be supported by --with.
+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 PROGRAMMING file for documentation about
+the sequence addon interface.
+
+=item B<--without> I<addon>
+
+The inverse of --with, disables using the given addon.
+
+=item B<--list>, B<-l>
+
+List all available addons.
 
 =item B<--until> I<cmd>
 
@@ -69,40 +77,20 @@ Run commands in the sequence that come after I<cmd>.
 
 Run all commands in the sequence that have yet to be run.
 
+=item B<--no-act>
+
+Prints commands that would run for a given sequence, but does not run them.
+
 =back
 
 All other 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.
 
-=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.
-
-=head1 SEQUENCE ADDONS
-
-When B<--with> I<addon> is used, dh loads the perl module
-Debian::Debhelper::Sequence::I<addon>. Two functions are provided to let
-the module add its commands to sequences:
-
-=over 4
-
-=item Debian::Debhelper::Dh_Lib::insert_before(existing_command, new_command)
-
-Insert I<new_command> in sequences before I<existing_command>.
-
-=item Debian::Debhelper::Dh_Lib::insert_after(existing_command, new_command)
-
-Insert I<new_command> in sequences after I<existing_command>.
-
-=item Debian::Debhelper::Dh_Lib::remove_command(existing_command)
-
-Remove I<existing_command> from the list of commands to 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
 
@@ -182,14 +170,95 @@ after a particular debhelper command is run.
                dh_fixperms
                chmod 4755 debian/foo/usr/bin/foo
 
+If your package is a python package, dh will use dh_pysupport by
+default. This is how to use dh_pycentral instead.
+
+       #!/usr/bin/make -f
+       %:
+               dh $@ --with python-central
+
+Here is how to force use of perl's 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
+
+To patch your package using quilt, you can tell dh to use quilt's dh
+sequence addons like this:
+       
+       #!/usr/bin/make -f
+       %:
+               dh $@ --with quilt
+
+Here is an example of overriding where the dh_auto_* 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 dh_auto_* commands to build
+in a subdirectory, which will be removed on clean.
+
+       #!/usr/bin/make -f
+       %:
+               dh $@ --builddirectory=build
+
+Finally, here is a way to prevent 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:
+
 =cut
 
 # Stash this away before init modifies it.
 my @ARGV_orig=@ARGV;
 
-init();
+# python-support is enabled by default, at least for now
+# (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" => \$dh{LIST},
+               "list" => \$dh{LIST},
+       },
+       # Disable complaints about unknown options; they are passed on the
+       # debhelper commands.
+       ignore_unknown_options => 1,
+       # Bundling does not work well since there are unknown options.
+       bundling => 0,
+);
 inhibit_log();
 
+
+# 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();
+}
+
 # Definitions of sequences.
 my %sequences;
 $sequences{build} = [qw{
@@ -218,7 +287,6 @@ $sequences{install} = [@{$sequences{build}}, qw{
        dh_installcatalogs
        dh_installcron
        dh_installdebconf
-       dh_installcatalogs
        dh_installemacsen
        dh_installifupdown
        dh_installinfo
@@ -233,12 +301,11 @@ $sequences{install} = [@{$sequences{build}}, qw{
        dh_installudev
        dh_installwm
        dh_installxfonts
+       dh_bugfiles
        dh_lintian
-       dh_desktop
        dh_gconf
        dh_icons
        dh_perl
-       dh_scrollkeeper
        dh_usrlocal
 
        dh_link
@@ -259,8 +326,8 @@ $sequences{binary} = [@{$sequences{install}}, qw{
 }, @b];
 $sequences{'binary-arch'} = [@{$sequences{binary}}];
 
-# --with python-support is enabled by default, at least for now
-unshift @{$dh{WITH}}, "python-support";
+# Additional command options
+my %command_opts;
 
 # sequence addon interface
 sub _insert {
@@ -297,12 +364,61 @@ sub remove_command {
        }
        
 }
+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};
+       }
+}
+
+if ($dh{LIST}) {
+       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;
+}
+
 foreach my $addon (@{$dh{WITH}}) {
        my $mod="Debian::Debhelper::Sequence::$addon";
        $mod=~s/-/_/g;
        eval "use $mod";
        if ($@) {
-               error("--with $addon not supported or failed to load module $mod");
+               error("unable to load addon $addon: $@");
        }
 }
 
@@ -311,8 +427,14 @@ if (! @ARGV) {
        error "specify a sequence to run";
 }
 my $sequence=shift;
-if (! exists $sequences{$sequence}) {
-       error "Unknown sequence $sequence (chose from: ".
+if ($sequence eq 'debian/rules' ||
+    $sequence =~ /^override_dh_/) {
+       # make -B causes the rules file to be run as a target
+       # and support completly empty override targets
+       exit 0
+}      
+elsif (! exists $sequences{$sequence}) {
+       error "Unknown sequence $sequence (choose from: ".
                join(" ", sort keys %sequences).")";
 }
 my @sequence=@{$sequences{$sequence}};
@@ -339,21 +461,31 @@ elsif ($sequence eq 'binary-indep') {
 while (@ARGV_orig) {
        my $opt=shift @ARGV_orig;
        next if $opt eq $sequence;
-       if ($opt =~ /^--?(after|until|before|with)$/) {
+       if ($opt =~ /^--?(after|until|before|with|without)$/) {
                shift @ARGV_orig;
                next;
        }
-       elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with)=)/) {
+       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 (@packages) {
-       my @log=loadlog($package);
+       my @log=load_log($package, \%logged);
        if ($dh{AFTER}) {
                # Run commands in the sequence that come after the
                # specified command.
@@ -363,7 +495,7 @@ foreach my $package (@packages) {
                # 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]);
+               write_log($sequence[$startpoint{$package}-1], $package);
        }
        elsif ($dh{REMAINING}) {
                # Start at the beginning so all remaining commands will get
@@ -420,34 +552,51 @@ sub run {
        my @exclude=@{shift()};
        my @options=@_;
        
+       # If some packages are excluded, add flags
+       # to prevent them from being acted on.
+       push @options, map { "-N$_" } @exclude;
+
        # Check for override targets in debian/rules and
        # run them instead of running the command directly.
        my $override_command;
-       if (rules_explicit_target("override_".$command)) {
+       my $has_explicit_target = rules_explicit_target("override_".$command);
+       if (defined $has_explicit_target) {
                $override_command=$command;
-               # This passes the options through to commands called
-               # inside the target.
-               $ENV{DH_INTERNAL_OPTIONS}=join(" ", @options);
-               $command="debian/rules";
-               @options="override_".$override_command;
+               # Check if target isn't noop
+               if ($has_explicit_target) {
+                       # This passes the options through to commands called
+                       # inside the target.
+                       $ENV{DH_INTERNAL_OPTIONS}=join("\x1e", @options);
+                       $command="debian/rules";
+                       @options="override_".$override_command;
+               }
+               else {
+                       $command = undef;
+               }
        }
        else {
-               # If some packages are excluded, add flags
-               # to prevent them from being acted on.
-               push @options, map { "-N$_" } @exclude;
+               # Pass 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";
+       if (defined $command) {
+               # 3 space indent lines the command being run up under the
+               # sequence name after "dh ".
+               print "   ".escape_shell($command, @options)."\n";
+       }
+       else {
+               print "   ", "# Skipping ", $override_command, " - empty override", "\n";
+       }
 
        if (! $dh{NO_ACT}) {
-               my $ret=system($command, @options);
-               if ($ret >> 8 != 0) {
-                       exit $ret >> 8;
-               }
-               elsif ($ret) {
-                       exit 1;
+               if (defined $command) {
+                       my $ret=system($command, @options);
+                       if ($ret >> 8 != 0) {
+                               exit $ret >> 8;
+                       }
+                       elsif ($ret) {
+                               exit 1;
+                       }
                }
 
                if (defined $override_command) {
@@ -455,59 +604,75 @@ sub run {
                        # Need to handle logging for overriden commands here,
                        # because the actual debhelper command may not have
                        # been run by the rules file target.
-                       my %packages=map { $_ => 1 } @packages;
-                       map { delete $packages{$_} } @exclude;
-                       Debian::Debhelper::Dh_Lib::write_log($override_command, keys %packages);
+                       # (But avoid logging for dh_clean since it removes
+                       # the log earlier.)
+                       if ($override_command ne 'dh_clean') {
+                               my %packages=map { $_ => 1 } @packages;
+                               map { delete $packages{$_} } @exclude;
+                               write_log($override_command, keys %packages);
+                       }
                }
        }
 }
 
-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;
-}
-
 {
 my %targets;
 my $rules_parsed;
 
 sub rules_explicit_target {
        # Checks if a specified target exists as an explicit target
-       # in debian/rules. 
-       # Currently this is accomplished via a stupid makefile parser.
+       # 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) {  
-               open(IN, "<debian/rules") || warning("dh cannot read debian/rules: $!");
-               while (<IN>) {
-                       if (/^([a-zA-Z_]+):/) {
-                               $targets{$1}=1;
+
+       if (! $rules_parsed) {
+               my $processing_targets = 0;
+               my $not_a_target = 0;
+               my $current_target;
+               open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules debhelper-fail-me 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 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 IN;
+               close MAKE;
+               $rules_parsed = 1;
        }
 
-       return exists $targets{$target};
+       return $targets{$target};
 }
 
 }