X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=dh;h=710117ead15d9db779a913b4068118e3322a2367;hb=d8edabf803f9e687cd2a626a6b28c921a0c645ab;hp=ab814d7f2b98885678059e9628776ae077e3ca00;hpb=28f84cd5c972f683506bee5f201cd93a2c09ee56;p=debhelper.git diff --git a/dh b/dh index ab814d7..710117e 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<--list>] [B<--until> I] [B<--before> I] [B<--after> I] [B<--remaining>] [S>] =head1 DESCRIPTION @@ -24,10 +24,6 @@ they only work on binary independent packages, and commands in the binary-arch sequences are passed the "-a" option to ensure they only work on architecture dependent packages. -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. - Each debhelper command will record when it's successfully run in debian/package.debhelper.log. (Which dh_clean deletes.) So dh can tell which commands have already been run, for which packages, and skip running @@ -38,10 +34,34 @@ 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<--list>, B<-l> + +List all available addons. + =item B<--until> I Run commands in the sequence until and including I, then stop. @@ -58,6 +78,12 @@ Run commands in the sequence that come after I. Run all commands in the sequence that have yet to be run. +=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 can be a full name of a debhelper command, or a substring. It'll first @@ -98,80 +124,106 @@ 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 + override_dh_strip: + dh_strip -Xfoo + + override_dh_installdocs: + dh_installdocs README TODO - install: build - dh install +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-arch: install - dh binary-arch + #!/usr/bin/make -f + %: + dh $@ - binary-indep: install - dh binary-indep + override_dh_auto_configure: + ./mondoconfig - binary: binary-arch binary-indep + override_dh_auto_build: + make universe-explode-in-delight -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. +Another common case is wanting to do something manually before or +after a particular debhelper command is run. - build: - dh build --before configure - dh_auto_configure --kitchen-sink=yes - dh build --after configure + #!/usr/bin/make -f + %: + dh $@ -Here's how to skip two automated in a row (configure and build), and -instead run the commands by hand. + override_dh_fixperms: + dh_fixperms + chmod 4755 debian/foo/usr/bin/foo - build: - dh build --before configure - ./mondoconfig - make universe-explode-in-delight - dh build --after build +If your package is a python package, dh will use dh_pysupport by +default. This is how to use dh_pycentral instead. -Another common case is wanting to run some code manually after a particular -debhelper command is run. + #!/usr/bin/make -f + %: + dh --with python-central $@ - binary-arch: install - dh binary-arch --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 +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 $@ -It's also fine to run debhelper commands before starting the 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. +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_fixperms -X bar - 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"; + +# 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(); # Definitions of sequences. my %sequences; @@ -188,7 +240,7 @@ $sequences{clean} = [qw{ }]; $sequences{install} = [@{$sequences{build}}, qw{ dh_testroot - dh_clean + dh_prep dh_installdirs dh_auto_install @@ -216,13 +268,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 @@ -230,6 +280,7 @@ $sequences{install} = [@{$sequences{build}}, qw{ dh_fixperms }]; my @b=qw{ + dh_installdeb dh_gencontrol dh_md5sums dh_builddeb @@ -242,41 +293,146 @@ $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, -); +# Additional command options +my %command_opts; + +# 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}}]; + } + +} +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("unable to load addon $addon: $@"); + } +} # 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 =~ /^--?(remaining|(after|until|before)=)/) { + elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with|without)=)/) { next; } push @options, $opt; @@ -285,12 +441,18 @@ 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. $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. + write_log($sequence[$startpoint{$package}-1], $package); } elsif ($dh{REMAINING}) { # Start at the beginning so all remaining commands will get @@ -326,44 +488,50 @@ 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=@_; - # dh_clean -k is a special case - if ($command eq 'dh_clean' && $sequence ne 'clean') { - unshift @options, "-k"; + # 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("\x1e", @options); + $command="debian/rules"; + @options="override_".$override_command; } - - # If a third party command is not in /usr/bin, don't try to run it. - if ($thirdparty{$command} && ! -x "/usr/bin/$command") { - return; + else { + # Pass additional command options if any + unshift @options, @{$command_opts{$command}} if exists $command_opts{$command}; } - # The 4 spaces is a kind of half indent. - print " ".escape_shell($command, @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); @@ -373,22 +541,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}; +} + } =head1 SEE ALSO