X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=dh;h=c90cf0e286752c72288edc86863bf58fa0c8da2d;hb=4901f607e6f1485f8d1b5e44bd4d2ab4518a28f4;hp=289e7fc253fc9b3e3f37a484c4127f18c53f97b1;hpb=5a4f5a4379f537f7a7a3efca3e251ad16f217e8e;p=debhelper.git diff --git a/dh b/dh index 289e7fc..c90cf0e 100755 --- a/dh +++ b/dh @@ -11,7 +11,7 @@ use Debian::Debhelper::Dh_Lib; =head1 SYNOPSIS -B sequence [B<--until> I] [B<--before> I] [B<--after> I] [B<--remaining>] [B<--with> I] [S>] +B sequence [B<--with> I[,I,...]] [B<--list>] [B<--until> I] [B<--before> I] [B<--after> I] [B<--remaining>] [S>] =head1 DESCRIPTION @@ -34,10 +34,33 @@ 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. +If debian/rules contains a target with a name like "override_I", +then when it would notmally run I, 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[,I,...] + +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 PROGRAMMING file for documentation about +the sequence addon interface. + +=item B<--without> I + +The inverse of --with, disables using the given addon. + +=item B<--list>, B<-l> + +List all available addons. + =item B<--until> I Run commands in the sequence until and including I, then stop. @@ -54,13 +77,9 @@ Run commands in the sequence that come after I. Run all commands in the sequence that have yet to be run. -=item B<--with> I +=item B<--no-act> -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. +Prints commands that would run for a given sequence, but does not run them. =back @@ -68,34 +87,10 @@ 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 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 is used, dh loads the perl module -Debian::Debhelper::Sequence::I. 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 in sequences before I. - -=item Debian::Debhelper::Dh_Lib::insert_after(existing_command, new_command) - -Insert I in sequences after I. - -=item Debian::Debhelper::Dh_Lib::remove_command(existing_command) - -Remove I from the list of commands to run. - -=back +In the above options, I 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 @@ -137,92 +132,124 @@ commands work with no additional options. %: dh $@ -This is a simple rules file that is a good starting place for customisation. -(It's also available in F +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_installdocs: + dh_installdocs README TODO + +Sometimes the automated dh_auto_configure and dh_auto_build 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 $@ - build: build-stamp - dh build - touch build-stamp + override_dh_auto_configure: + ./mondoconfig - clean: - dh clean + override_dh_auto_build: + make universe-explode-in-delight - install: build install-stamp - install-stamp: - dh install - touch install-stamp +Another common case is wanting to do something manually before or +after a particular debhelper command is run. - binary-arch: install - dh binary-arch + #!/usr/bin/make -f + %: + dh $@ - binary-indep: install - dh binary-indep + override_dh_fixperms: + dh_fixperms + chmod 4755 debian/foo/usr/bin/foo - binary: binary-arch binary-indep +If your package is a python package, dh will use dh_pysupport by +default. This is how to use dh_pycentral instead. -Often you'll want to pass an option to ./configure. This uses dh to run all -commands before L, 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. + #!/usr/bin/make -f + %: + dh --with python-central $@ - build: build-stamp - build-stamp: - dh build --before configure - dh_auto_configure -- --kitchen-sink=yes - dh build --after configure - touch build-stamp +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. -Here's how to skip two automated in a row (configure and build), and -instead run the commands by hand. + #!/usr/bin/make -f + %: + dh --buildsystem=perl_build $@ - build: build-stamp - build-stamp: - dh build --before configure - ./mondoconfig - make universe-explode-in-delight - dh build --after build - touch build-stamp +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 $@ -Another common case is wanting to run some code manually after a particular -debhelper command is run. +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. - install: build install-stamp - install-stamp: - 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 install --after dh_fixperms - touch install-stamp - -It's also fine to run debhelper commands early. Just make sure that at -least dh_prep is run from the sequence first, and be sure to use the -B<--remaining> option to ensure that commands that normally come before -those in the sequence are still run. - - install: build install-stamp - install-stamp: - dh install --until dh_prep - dh_installdocs README TODO - dh_installchangelogs Changes - dh install --remaining - touch install-stamp + #!/usr/bin/make -f + %: + dh --sourcedirectory=src $@ - binary-arch: install - dh_strip -X foo - dh binary-arch --remaining +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"; + +# Disable complaints about unknown options for both dh and the commands +# it runs. This is done because dh accepts and passes on options that may +# be specific to only some debhelper commands. +$ENV{DH_IGNORE_UNKNOWN_OPTIONS}=1; + +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}, +}); 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{ @@ -251,7 +278,6 @@ $sequences{install} = [@{$sequences{build}}, qw{ dh_installcatalogs dh_installcron dh_installdebconf - dh_installcatalogs dh_installemacsen dh_installifupdown dh_installinfo @@ -266,12 +292,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 @@ -292,8 +317,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 { @@ -330,12 +355,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: $@"); } } @@ -344,8 +418,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}}; @@ -372,11 +452,11 @@ 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; @@ -386,7 +466,7 @@ while (@ARGV_orig) { 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. @@ -396,7 +476,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 @@ -443,59 +523,139 @@ foreach my $i (0..$stoppoint) { # 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); - } + + run($sequence[$i], \@packages, \@exclude, @options); } sub run { my $command=shift; + my @packages=@{shift()}; + my @exclude=@{shift()}; my @options=@_; - # 3 space indent lines the command being run up under the - # sequence name after "dh ". - print " ".escape_shell($command, @options)."\n"; + # 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; + my $has_explicit_target = rules_explicit_target("override_".$command); + if (defined $has_explicit_target) { + $override_command=$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 { + # Pass additional command options if any + unshift @options, @{$command_opts{$command}} if exists $command_opts{$command}; + } + + 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; + if (defined $command) { + my $ret=system($command, @options); + if ($ret >> 8 != 0) { + exit $ret >> 8; + } + elsif ($ret) { + exit 1; + } } - elsif ($ret) { - exit 1; + + if (defined $override_command) { + delete $ENV{DH_INTERNAL_OPTIONS}; + # Need to handle logging for overriden commands here, + # because the actual debhelper command may not have + # been run by the rules file target. + # (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 () { - chomp; - push @log, $_; - $logged{$package}{$_}=1; +{ +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 debhelper-fail-me 2>/dev/null |"); + while () { + 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 MAKE; + $rules_parsed = 1; } - close LOG; - return @log; + + return $targets{$target}; } - -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