X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=dh;h=bcd5b02dae530fbf3055cbacab5b013c84fb0a7d;hb=fdf8b4a8b4b4f50c39b6e4266773539bc13d6e56;hp=cf6d1d2d64fd3c941efbc7e4f3f5a276416cebdb;hpb=7bce3f50a494bec6c023a9156175f463ba11d9c6;p=debhelper.git diff --git a/dh b/dh index cf6d1d2..bcd5b02 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> [S>] +B sequence [B<--with> I[,I,...]] [B<--until> I] [B<--before> I] [B<--after> I] [B<--remaining>] [S>] =head1 DESCRIPTION @@ -34,10 +34,30 @@ 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 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.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<--until> I Run commands in the sequence until and including I, then stop. @@ -100,84 +120,98 @@ anything: dh binary-arch --no-act -This is a very simple rules file, for packages where the default seqences of +This is a very simple rules file, for packages where the default sequences of commands work with no additional options. #!/usr/bin/make -f %: - dh %@ - -This is a simple rules file that is a good starting place for customisation. -(It's also available in F + dh $@ +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 $@ - build: - dh build - - clean: - dh clean - - install: build - dh install + override_dh_strip: + dh_strip -Xfoo + + override_dh_installdocs: + dh_installdocs README TODO - binary-arch: install - dh binary-arch +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. - binary-indep: install - dh binary-indep + #!/usr/bin/make -f + %: + dh $@ - binary: binary-arch binary-indep + override_dh_auto_configure: + ./mondoconfig -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. + override_dh_auto_build: + make universe-explode-in-delight - build: - dh build --before configure - dh_auto_configure --kitchen-sink=yes - dh build --after configure +Another common case is wanting to do something manually before or +after a particular debhelper command is run. -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 $@ - build: - dh build --before configure - ./mondoconfig - make universe-explode-in-delight - dh build --after build + override_dh_fixperms: + dh_fixperms + chmod 4755 debian/foo/usr/bin/foo -Another common case is wanting to run some code manually after a particular -debhelper command is run. +If your package is a python package, dh will use dh_pysupport by +default. This is how to use dh_pycentral instead. - 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 install --after dh_fixperms + #!/usr/bin/make -f + %: + dh --with python-central $@ -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. +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 $@ - install: - dh_installdocs README TODO - dh_installchangelogs Changes - dh install --remaining +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. It also forces use of perl's Module::Build build system, +which can be necessary if debhelper wrongly detects that the package +uses MakeMaker. - binary-arch: install - dh_strip -X foo - dh binary-arch --remaining + #!/usr/bin/make -f + %: + dh --sourcedirectory=src --buildsystem=perl_build $@ =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}}; + }, +}); inhibit_log(); # Definitions of sequences. @@ -223,13 +257,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_pysupport - dh_scrollkeeper dh_usrlocal dh_link @@ -250,41 +282,94 @@ $sequences{binary} = [@{$sequences{install}}, qw{ }, @b]; $sequences{'binary-arch'} = [@{$sequences{binary}}]; -# 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, -); +# sequence addon interface +sub _insert { + my $offset=shift; + my $existing=shift; + my $new=shift; + foreach my $sequence (keys %sequences) { + my @list=@{$sequences{$sequence}}; + next unless grep $existing, @list; + my @new; + foreach my $command (@list) { + if ($command eq $existing) { + push @new, $new if $offset < 0; + push @new, $command; + push @new, $new if $offset > 0; + } + else { + push @new, $command; + } + } + $sequences{$sequence}=\@new; + } +} +sub insert_before { + _insert(-1, @_); +} +sub insert_after { + _insert(1, @_); +} +sub remove_command { + my $command=shift; + foreach my $sequence (keys %sequences) { + $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}]; + } + +} +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"); + } +} # Get the sequence of commands to run. 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}}; +# The list of all packages that can be acted on. +my @packages=@{$dh{DOPACKAGES}}; + # Get the options to pass to commands in the sequence. # Filter out options intended only for this program. my @options; if ($sequence eq 'binary-arch') { push @options, "-a"; + # as an optimisation, remove from the list any packages + # that are not arch dependent + my %arch_packages = map { $_ => 1 } getpackages("arch"); + @packages = grep { $arch_packages{$_} } @packages; } elsif ($sequence eq 'binary-indep') { push @options, "-i"; + # ditto optimisation for arch indep + my %indep_packages = map { $_ => 1 } getpackages("indep"); + @packages = grep { $indep_packages{$_} } @packages; } while (@ARGV_orig) { my $opt=shift @ARGV_orig; next if $opt eq $sequence; - if ($opt =~ /^--?(after|until|before)$/) { + if ($opt =~ /^--?(after|until|before|with|without)$/) { shift @ARGV_orig; next; } - elsif ($opt =~ /^--?(no-act|remaining|(after|until|before)=)/) { + elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with|without)=)/) { next; } push @options, $opt; @@ -293,8 +378,8 @@ while (@ARGV_orig) { # 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); +foreach my $package (@packages) { + my @log=load_log($package, \%logged); if ($dh{AFTER}) { # Run commands in the sequence that come after the # specified command. @@ -304,7 +389,7 @@ foreach my $package (@{$dh{DOPACKAGES}}) { # 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 @@ -340,35 +425,41 @@ elsif ($dh{BEFORE}) { foreach my $i (0..$stoppoint) { # Figure out which packages need to run this command. my @exclude; - foreach my $package (@{$dh{DOPACKAGES}}) { + foreach my $package (@packages) { if ($startpoint{$package} > $i || $logged{$package}{$sequence[$i]}) { push @exclude, $package; } } - if (@exclude eq @{$dh{DOPACKAGES}}) { + if (@exclude eq @packages) { # 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=@_; - # If a third party command is not in /usr/bin, don't try to run it. - if ($thirdparty{$command} && ! -x "/usr/bin/$command") { - return; + # 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)) { + $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; } # 3 space indent lines the command being run up under the @@ -383,32 +474,65 @@ sub run { 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 %targets; +my $rules_parsed; + +sub rules_explicit_target { + # Checks if a specified target exists as an explicit target + # in debian/rules. + my $target=shift; - my @log; - open(LOG, "<", "debian/${ext}debhelper.log") || return; - while () { - chomp; - push @log, $_; - $logged{$package}{$_}=1; + if (! $rules_parsed) { + my $processing_targets = 0; + my $not_a_target = 0; + 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 && /^([^#:]+)::?/) { + # Target is defined. + # NOTE: if it is a depenency + # of .PHONY it will be + # defined too but that's ok. + $targets{$1} = 1; + } + # "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 exists $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