]> git.donarmstrong.com Git - debhelper.git/blob - dh
Merge branch 'dh_overrides'
[debhelper.git] / dh
1 #!/usr/bin/perl -w
2
3 =head1 NAME
4
5 dh - debhelper command sequencer
6
7 =cut
8
9 use strict;
10 use Debian::Debhelper::Dh_Lib;
11
12 =head1 SYNOPSIS
13
14 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>>]
15
16 =head1 DESCRIPTION
17
18 dh runs a sequence of debhelper commands. The supported sequences
19 correspond to the targets of a debian/rules file: "build", "clean",
20 "install", "binary-arch", "binary-indep", and "binary".
21
22 Commands in the binary-indep sequence are passed the "-i" option to ensure
23 they only work on binary independent packages, and commands in the
24 binary-arch sequences are passed the "-a" option to ensure they only work
25 on architecture dependent packages.
26
27 Each debhelper command will record when it's successfully run in
28 debian/package.debhelper.log. (Which dh_clean deletes.) So dh can tell
29 which commands have already been run, for which packages, and skip running
30 those commands again.
31
32 Each time dh is run, it examines the log, and finds the last logged command
33 that is in the specified sequence. It then continues with the next command
34 in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining>
35 options can override this behavior.
36
37 If debian/rules contains a target with a name like "override_I<dh_command>",
38 then when it gets to that command in the sequence, dh will run that
39 target from the rules file, rather than running the actual command. The
40 override target can then run the command with additional options, or run
41 entirely different commands instead. (Note that to use this feature,
42 you should Build-Depend on debhelper 7.0.50 or above.)
43
44 =head1 OPTIONS
45
46 =over 4
47
48 =item B<--with> I<addon>
49
50 Add the debhelper commands specified by the given addon to appropriate places
51 in the sequence of commands that is run. This option can be repeated more
52 than once, and is used when there is a third-party package that provides
53 debhelper commands. See "SEQUENCE ADDONS" below for documentation about what
54 such packages should do to be supported by --with.
55
56 =item B<--until> I<cmd>
57
58 Run commands in the sequence until and including I<cmd>, then stop.
59
60 =item B<--before> I<cmd>
61
62 Run commands in the sequence before I<cmd>, then stop.
63
64 =item B<--after> I<cmd>
65
66 Run commands in the sequence that come after I<cmd>.
67
68 =item B<--remaining>
69
70 Run all commands in the sequence that have yet to be run.
71
72 =back
73
74 All other options passed to dh are passed on to each command it runs. This
75 can be used to set an option like "-v" or "-X" or "-N", as well as for more
76 specialised options.
77
78 =head1 COMMAND SPECIFICATION
79
80 I<cmd> can be a full name of a debhelper command, or a substring. It'll first
81 search for a command in the sequence exactly matching the name, to avoid any
82 ambiguity. If there are multiple substring matches, the last one in the
83 sequence will be used.
84
85 =head1 SEQUENCE ADDONS
86
87 When B<--with> I<addon> is used, dh loads the perl module
88 Debian::Debhelper::Sequence::I<addon>. Two functions are provided to let
89 the module add its commands to sequences:
90
91 =over 4
92
93 =item Debian::Debhelper::Dh_Lib::insert_before(existing_command, new_command)
94
95 Insert I<new_command> in sequences before I<existing_command>.
96
97 =item Debian::Debhelper::Dh_Lib::insert_after(existing_command, new_command)
98
99 Insert I<new_command> in sequences after I<existing_command>.
100
101 =item Debian::Debhelper::Dh_Lib::remove_command(existing_command)
102
103 Remove I<existing_command> from the list of commands to run.
104
105 =back
106
107 =cut
108
109 sub command_pos {
110         my $command=shift;
111         my @sequence=@_;
112
113         foreach my $i (0..$#sequence) {
114                 if ($command eq $sequence[$i]) {
115                         return $i;
116                 }
117         }
118
119         my @matches;
120         foreach my $i (0..$#sequence) {
121                 if ($sequence[$i] =~ /\Q$command\E/) {
122                         push @matches, $i;
123                 }
124         }
125         if (! @matches) {
126                 error "command specification \"$command\" does not match any command in the sequence"
127         }
128         else {
129                 return pop @matches;
130         }
131 }
132
133 =head1 EXAMPLES
134
135 To see what commands are included in a sequence, without actually doing
136 anything:
137
138         dh binary-arch --no-act
139
140 This is a very simple rules file, for packages where the default sequences of
141 commands work with no additional options.
142
143         #!/usr/bin/make -f
144         %:
145                 dh $@
146
147 Often you'll want to pass an option to a specific debhelper command. The
148 easy way to do with is by adding an override target for that command.
149         
150         #!/usr/bin/make -f
151         %:
152                 dh $@
153
154         override_dh_strip:
155                 dh_strip -Xfoo
156                 
157         override_dh_installdocs:
158                 dh_installdocs README TODO
159
160 Sometimes the automated dh_auto_configure and dh_auto_build can't guess
161 what to do for a strange package. Here's how to avoid running either
162 and instead run your own commands.
163
164         #!/usr/bin/make -f
165         %:
166                 dh $@
167
168         override_dh_auto_configure:
169                 ./mondoconfig
170
171         override_dh_auto_build:
172                 make universe-explode-in-delight
173
174 Another common case is wanting to do something manually before or
175 after a particular debhelper command is run.
176
177         #!/usr/bin/make -f
178         %:
179                 dh $@
180
181         override_dh_fixperms:
182                 dh_fixperms
183                 chmod 4755 debian/foo/usr/bin/foo
184
185 If your package is a python package, dh will use dh_pysupport by
186 default. This is how to use dh_pycentral instead.
187
188         #!/usr/bin/make -f
189         %:
190                 dh --with python-central $@
191
192 =cut
193
194 # Stash this away before init modifies it.
195 my @ARGV_orig=@ARGV;
196
197 init(options => {
198         "until=s" => \$dh{UNTIL},
199         "after=s" => \$dh{AFTER},
200         "before=s" => \$dh{BEFORE},
201         "remaining" => \$dh{REMAINING},
202         "with=s" => sub {
203                 my ($option,$value)=@_;
204                 push @{$dh{WITH}},$value;
205         },
206 });
207 inhibit_log();
208
209 # Definitions of sequences.
210 my %sequences;
211 $sequences{build} = [qw{
212         dh_testdir
213         dh_auto_configure
214         dh_auto_build
215         dh_auto_test
216 }],
217 $sequences{clean} = [qw{
218         dh_testdir
219         dh_auto_clean
220         dh_clean
221 }];
222 $sequences{install} = [@{$sequences{build}}, qw{
223         dh_testroot
224         dh_prep
225         dh_installdirs
226         dh_auto_install
227
228         dh_install
229         dh_installdocs
230         dh_installchangelogs
231         dh_installexamples
232         dh_installman
233
234         dh_installcatalogs
235         dh_installcron
236         dh_installdebconf
237         dh_installcatalogs
238         dh_installemacsen
239         dh_installifupdown
240         dh_installinfo
241         dh_installinit
242         dh_installmenu
243         dh_installmime
244         dh_installmodules
245         dh_installlogcheck
246         dh_installlogrotate
247         dh_installpam
248         dh_installppp
249         dh_installudev
250         dh_installwm
251         dh_installxfonts
252         dh_lintian
253         dh_desktop
254         dh_gconf
255         dh_icons
256         dh_perl
257         dh_scrollkeeper
258         dh_usrlocal
259
260         dh_link
261         dh_compress
262         dh_fixperms
263 }];
264 my @b=qw{
265         dh_installdeb
266         dh_gencontrol
267         dh_md5sums
268         dh_builddeb
269 };
270 $sequences{'binary-indep'} = [@{$sequences{install}}, @b];
271 $sequences{binary} = [@{$sequences{install}}, qw{
272         dh_strip
273         dh_makeshlibs
274         dh_shlibdeps
275 }, @b];
276 $sequences{'binary-arch'} = [@{$sequences{binary}}];
277
278 # --with python-support is enabled by default, at least for now
279 unshift @{$dh{WITH}}, "python-support";
280
281 # sequence addon interface
282 sub _insert {
283         my $offset=shift;
284         my $existing=shift;
285         my $new=shift;
286         foreach my $sequence (keys %sequences) {
287                 my @list=@{$sequences{$sequence}};
288                 next unless grep $existing, @list;
289                 my @new;
290                 foreach my $command (@list) {
291                         if ($command eq $existing) {
292                                 push @new, $new if $offset < 0;
293                                 push @new, $command;
294                                 push @new, $new if $offset > 0;
295                         }
296                         else {
297                                 push @new, $command;
298                         }
299                 }
300                 $sequences{$sequence}=\@new;
301         }
302 }
303 sub insert_before {
304         _insert(-1, @_);
305 }
306 sub insert_after {
307         _insert(1, @_);
308 }
309 sub remove_command {
310         my $command=shift;
311         foreach my $sequence (keys %sequences) {
312                 $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}];
313         }
314         
315 }
316 foreach my $addon (@{$dh{WITH}}) {
317         my $mod="Debian::Debhelper::Sequence::$addon";
318         $mod=~s/-/_/g;
319         eval "use $mod";
320         if ($@) {
321                 error("--with $addon not supported or failed to load module $mod");
322         }
323 }
324
325 # Get the sequence of commands to run.
326 if (! @ARGV) {
327         error "specify a sequence to run";
328 }
329 my $sequence=shift;
330 if ($sequence eq 'debian/rules' ||
331     $sequence =~ /^override_dh_/) {
332         # make -B causes the rules file to be run as a target
333         # and support completly empty override targets
334         exit 0
335 }       
336 elsif (! exists $sequences{$sequence}) {
337         error "Unknown sequence $sequence (choose from: ".
338                 join(" ", sort keys %sequences).")";
339 }
340 my @sequence=@{$sequences{$sequence}};
341
342 # The list of all packages that can be acted on.
343 my @packages=@{$dh{DOPACKAGES}};
344
345 # Get the options to pass to commands in the sequence.
346 # Filter out options intended only for this program.
347 my @options;
348 if ($sequence eq 'binary-arch') {
349         push @options, "-a";
350         # as an optimisation, remove from the list any packages
351         # that are not arch dependent
352         my %arch_packages = map { $_ => 1 } getpackages("arch");
353         @packages = grep { $arch_packages{$_} } @packages;
354 }
355 elsif ($sequence eq 'binary-indep') {
356         push @options, "-i";
357         # ditto optimisation for arch indep
358         my %indep_packages = map { $_ => 1 } getpackages("indep");
359         @packages = grep { $indep_packages{$_} } @packages;
360 }
361 while (@ARGV_orig) {
362         my $opt=shift @ARGV_orig;
363         next if $opt eq $sequence;
364         if ($opt =~ /^--?(after|until|before|with)$/) {
365                 shift @ARGV_orig;
366                 next;
367         }
368         elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with)=)/) {
369                 next;
370         }
371         push @options, $opt;
372 }
373
374 # Figure out at what point in the sequence to start for each package.
375 my %logged;
376 my %startpoint;
377 foreach my $package (@packages) {
378         my @log=loadlog($package);
379         if ($dh{AFTER}) {
380                 # Run commands in the sequence that come after the
381                 # specified command.
382                 $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1;
383                 # Write a dummy log entry indicating that the specified
384                 # command was, in fact, run. This handles the case where
385                 # no commands remain to run after it, communicating to
386                 # future dh instances that the specified command should not
387                 # be run again.
388                 writelog($sequence[$startpoint{$package}-1], $package);
389         }
390         elsif ($dh{REMAINING}) {
391                 # Start at the beginning so all remaining commands will get
392                 # run.
393                 $startpoint{$package}=0;
394         }
395         else {
396                 # Find the last logged command that is in the sequence, and
397                 # continue with the next command after it. If no logged
398                 # command is in the sequence, we're starting at the beginning..                         
399                 $startpoint{$package}=0;
400 COMMAND:        foreach my $command (reverse @log) {
401                         foreach my $i (0..$#sequence) {
402                                 if ($command eq $sequence[$i]) {
403                                         $startpoint{$package}=$i+1;
404                                         last COMMAND;
405                                 }
406                         }
407                 }
408         }
409 }
410
411 # Figure out what point in the sequence to go to.
412 my $stoppoint=$#sequence;
413 if ($dh{UNTIL}) {
414         $stoppoint=command_pos($dh{UNTIL}, @sequence);
415 }
416 elsif ($dh{BEFORE}) {
417         $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1;
418 }
419
420 # Now run the commands in the sequence.
421 foreach my $i (0..$stoppoint) {
422         # Figure out which packages need to run this command.
423         my @exclude;
424         foreach my $package (@packages) {
425                 if ($startpoint{$package} > $i ||
426                     $logged{$package}{$sequence[$i]}) {
427                         push @exclude, $package;
428                 }
429         }
430         
431         if (@exclude eq @packages) {
432                 # Command already done for all packages.
433                 next;
434         }
435
436         run($sequence[$i], \@packages, \@exclude, @options);
437 }
438
439 sub run {
440         my $command=shift;
441         my @packages=@{shift()};
442         my @exclude=@{shift()};
443         my @options=@_;
444         
445         # Check for override targets in debian/rules and
446         # run them instead of running the command directly.
447         my $override_command;
448         if (rules_explicit_target("override_".$command)) {
449                 $override_command=$command;
450                 # This passes the options through to commands called
451                 # inside the target.
452                 $ENV{DH_INTERNAL_OPTIONS}=join(" ", @options);
453                 $command="debian/rules";
454                 @options="override_".$override_command;
455         }
456         else {
457                 # If some packages are excluded, add flags
458                 # to prevent them from being acted on.
459                 push @options, map { "-N$_" } @exclude;
460         }
461
462         # 3 space indent lines the command being run up under the 
463         # sequence name after "dh ".
464         print "   ".escape_shell($command, @options)."\n";
465
466         if (! $dh{NO_ACT}) {
467                 my $ret=system($command, @options);
468                 if ($ret >> 8 != 0) {
469                         exit $ret >> 8;
470                 }
471                 elsif ($ret) {
472                         exit 1;
473                 }
474
475                 if (defined $override_command) {
476                         delete $ENV{DH_INTERNAL_OPTIONS};
477                         # Need to handle logging for overriden commands here,
478                         # because the actual debhelper command may not have
479                         # been run by the rules file target.
480                         my %packages=map { $_ => 1 } @packages;
481                         map { delete $packages{$_} } @exclude;
482                         writelog($override_command, keys %packages);
483                 }
484         }
485 }
486
487 sub loadlog {
488         my $package=shift;
489         my $ext=pkgext($package);
490         
491         my @log;
492         open(LOG, "<", "debian/${ext}debhelper.log") || return;
493         while (<LOG>) {
494                 chomp;
495                 push @log, $_;
496                 $logged{$package}{$_}=1;
497         }
498         close LOG;
499         return @log;
500 }
501
502 sub writelog {
503         Debian::Debhelper::Dh_Lib::write_log(@_);
504 }
505
506 {
507 my %targets;
508 my $rules_parsed;
509
510 sub rules_explicit_target {
511         # Checks if a specified target exists as an explicit target
512         # in debian/rules. 
513         my $target=shift;
514         
515         if (! $rules_parsed) {  
516                 my $processing_targets = 0;
517                 my $not_a_target = 0;
518                 open(MAKE, "LANG=C make -Rrnpsf debian/rules debhelper-fail-me 2>/dev/null |");
519                 while (<MAKE>) {
520                         if ($processing_targets) {
521                                 if (/^# Not a target:/) {
522                                         $not_a_target = 1;
523                                 }
524                                 else {
525                                         if (!$not_a_target && /^([^#:]+)::?/) {
526                                                 # Target is defined.
527                                                 # NOTE: if it is a depenency
528                                                 # of .PHONY it will be
529                                                 # defined too but that's ok.
530                                                 $targets{$1} = 1;
531                                         }
532                                         # "Not a target:" is always followed by
533                                         # a target name, so resetting this one
534                                         # here is safe.
535                                         $not_a_target = 0;
536                                 }
537                         } elsif (/^# Files$/) {
538                                 $processing_targets = 1;
539                         }
540                 }
541                 close MAKE;
542                 $rules_parsed = 1;
543         }
544
545         return exists $targets{$target};
546 }
547
548 }
549
550 =head1 SEE ALSO
551
552 L<debhelper(7)>
553
554 This program is a part of debhelper.
555
556 =head1 AUTHOR
557
558 Joey Hess <joeyh@debian.org>
559
560 =cut