]> git.donarmstrong.com Git - debhelper.git/blob - dh
b1da30b26674cc504a019e857efa20c7c38b9ed3
[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.2 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 the package's source tree might get files with names
186 like build or clean in it, the rules file would not
187 run targets with the same names. This issue can be worked
188 around by passing -B to make.
189
190         #!/usr/bin/make -Bf
191         %:
192                 dh $@
193
194 If your package is a python package, dh will use dh_pysupport by
195 default. This is how to use dh_pycentral instead.
196
197         #!/usr/bin/make -f
198         %:
199                 dh --with python_central
200
201 =cut
202
203 # Stash this away before init modifies it.
204 my @ARGV_orig=@ARGV;
205
206 init(options => {
207         "until=s" => \$dh{UNTIL},
208         "after=s" => \$dh{AFTER},
209         "before=s" => \$dh{BEFORE},
210         "remaining" => \$dh{REMAINING},
211         "with=s" => sub {
212                 my ($option,$value)=@_;
213                 push @{$dh{WITH}},$value;
214         },
215 });
216 inhibit_log();
217
218 # Definitions of sequences.
219 my %sequences;
220 $sequences{build} = [qw{
221         dh_testdir
222         dh_auto_configure
223         dh_auto_build
224         dh_auto_test
225 }],
226 $sequences{clean} = [qw{
227         dh_testdir
228         dh_auto_clean
229         dh_clean
230 }];
231 $sequences{install} = [@{$sequences{build}}, qw{
232         dh_testroot
233         dh_prep
234         dh_installdirs
235         dh_auto_install
236
237         dh_install
238         dh_installdocs
239         dh_installchangelogs
240         dh_installexamples
241         dh_installman
242
243         dh_installcatalogs
244         dh_installcron
245         dh_installdebconf
246         dh_installcatalogs
247         dh_installemacsen
248         dh_installifupdown
249         dh_installinfo
250         dh_installinit
251         dh_installmenu
252         dh_installmime
253         dh_installmodules
254         dh_installlogcheck
255         dh_installlogrotate
256         dh_installpam
257         dh_installppp
258         dh_installudev
259         dh_installwm
260         dh_installxfonts
261         dh_lintian
262         dh_desktop
263         dh_gconf
264         dh_icons
265         dh_perl
266         dh_scrollkeeper
267         dh_usrlocal
268
269         dh_link
270         dh_compress
271         dh_fixperms
272 }];
273 my @b=qw{
274         dh_installdeb
275         dh_gencontrol
276         dh_md5sums
277         dh_builddeb
278 };
279 $sequences{'binary-indep'} = [@{$sequences{install}}, @b];
280 $sequences{binary} = [@{$sequences{install}}, qw{
281         dh_strip
282         dh_makeshlibs
283         dh_shlibdeps
284 }, @b];
285 $sequences{'binary-arch'} = [@{$sequences{binary}}];
286
287 # --with python-support is enabled by default, at least for now
288 unshift @{$dh{WITH}}, "python-support";
289
290 # sequence addon interface
291 sub _insert {
292         my $offset=shift;
293         my $existing=shift;
294         my $new=shift;
295         foreach my $sequence (keys %sequences) {
296                 my @list=@{$sequences{$sequence}};
297                 next unless grep $existing, @list;
298                 my @new;
299                 foreach my $command (@list) {
300                         if ($command eq $existing) {
301                                 push @new, $new if $offset < 0;
302                                 push @new, $command;
303                                 push @new, $new if $offset > 0;
304                         }
305                         else {
306                                 push @new, $command;
307                         }
308                 }
309                 $sequences{$sequence}=\@new;
310         }
311 }
312 sub insert_before {
313         _insert(-1, @_);
314 }
315 sub insert_after {
316         _insert(1, @_);
317 }
318 sub remove_command {
319         my $command=shift;
320         foreach my $sequence (keys %sequences) {
321                 $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}];
322         }
323         
324 }
325 foreach my $addon (@{$dh{WITH}}) {
326         my $mod="Debian::Debhelper::Sequence::$addon";
327         $mod=~s/-/_/g;
328         eval "use $mod";
329         if ($@) {
330                 error("--with $addon not supported or failed to load module $mod");
331         }
332 }
333
334 # Get the sequence of commands to run.
335 if (! @ARGV) {
336         error "specify a sequence to run";
337 }
338 my $sequence=shift;
339 if ($sequence eq 'debian/rules' ||
340     $sequence =~ /^override_dh_/) {
341         # make -B causes the rules file to be run as a target
342         # and support completly empty override targets
343         exit 0
344 }       
345 elsif (! exists $sequences{$sequence}) {
346         error "Unknown sequence $sequence (choose from: ".
347                 join(" ", sort keys %sequences).")";
348 }
349 my @sequence=@{$sequences{$sequence}};
350
351 # The list of all packages that can be acted on.
352 my @packages=@{$dh{DOPACKAGES}};
353
354 # Get the options to pass to commands in the sequence.
355 # Filter out options intended only for this program.
356 my @options;
357 if ($sequence eq 'binary-arch') {
358         push @options, "-a";
359         # as an optimisation, remove from the list any packages
360         # that are not arch dependent
361         my %arch_packages = map { $_ => 1 } getpackages("arch");
362         @packages = grep { $arch_packages{$_} } @packages;
363 }
364 elsif ($sequence eq 'binary-indep') {
365         push @options, "-i";
366         # ditto optimisation for arch indep
367         my %indep_packages = map { $_ => 1 } getpackages("indep");
368         @packages = grep { $indep_packages{$_} } @packages;
369 }
370 while (@ARGV_orig) {
371         my $opt=shift @ARGV_orig;
372         next if $opt eq $sequence;
373         if ($opt =~ /^--?(after|until|before|with)$/) {
374                 shift @ARGV_orig;
375                 next;
376         }
377         elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with)=)/) {
378                 next;
379         }
380         push @options, $opt;
381 }
382
383 # Figure out at what point in the sequence to start for each package.
384 my %logged;
385 my %startpoint;
386 foreach my $package (@packages) {
387         my @log=loadlog($package);
388         if ($dh{AFTER}) {
389                 # Run commands in the sequence that come after the
390                 # specified command.
391                 $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1;
392                 # Write a dummy log entry indicating that the specified
393                 # command was, in fact, run. This handles the case where
394                 # no commands remain to run after it, communicating to
395                 # future dh instances that the specified command should not
396                 # be run again.
397                 writelog($package, $sequence[$startpoint{$package}-1]);
398         }
399         elsif ($dh{REMAINING}) {
400                 # Start at the beginning so all remaining commands will get
401                 # run.
402                 $startpoint{$package}=0;
403         }
404         else {
405                 # Find the last logged command that is in the sequence, and
406                 # continue with the next command after it. If no logged
407                 # command is in the sequence, we're starting at the beginning..                         
408                 $startpoint{$package}=0;
409 COMMAND:        foreach my $command (reverse @log) {
410                         foreach my $i (0..$#sequence) {
411                                 if ($command eq $sequence[$i]) {
412                                         $startpoint{$package}=$i+1;
413                                         last COMMAND;
414                                 }
415                         }
416                 }
417         }
418 }
419
420 # Figure out what point in the sequence to go to.
421 my $stoppoint=$#sequence;
422 if ($dh{UNTIL}) {
423         $stoppoint=command_pos($dh{UNTIL}, @sequence);
424 }
425 elsif ($dh{BEFORE}) {
426         $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1;
427 }
428
429 # Now run the commands in the sequence.
430 foreach my $i (0..$stoppoint) {
431         # Figure out which packages need to run this command.
432         my @exclude;
433         foreach my $package (@packages) {
434                 if ($startpoint{$package} > $i ||
435                     $logged{$package}{$sequence[$i]}) {
436                         push @exclude, $package;
437                 }
438         }
439         
440         if (@exclude eq @packages) {
441                 # Command already done for all packages.
442                 next;
443         }
444
445         run($sequence[$i], \@packages, \@exclude, @options);
446 }
447
448 sub run {
449         my $command=shift;
450         my @packages=@{shift()};
451         my @exclude=@{shift()};
452         my @options=@_;
453         
454         # Check for override targets in debian/rules and
455         # run them instead of running the command directly.
456         my $override_command;
457         if (rules_explicit_target("override_".$command)) {
458                 $override_command=$command;
459                 # This passes the options through to commands called
460                 # inside the target.
461                 $ENV{DH_INTERNAL_OPTIONS}=join(" ", @options);
462                 $command="debian/rules";
463                 @options="override_".$override_command;
464         }
465         else {
466                 # If some packages are excluded, add flags
467                 # to prevent them from being acted on.
468                 push @options, map { "-N$_" } @exclude;
469         }
470
471         # 3 space indent lines the command being run up under the 
472         # sequence name after "dh ".
473         print "   ".escape_shell($command, @options)."\n";
474
475         if (! $dh{NO_ACT}) {
476                 my $ret=system($command, @options);
477                 if ($ret >> 8 != 0) {
478                         exit $ret >> 8;
479                 }
480                 elsif ($ret) {
481                         exit 1;
482                 }
483
484                 if (defined $override_command) {
485                         delete $ENV{DH_INTERNAL_OPTIONS};
486                         # Need to handle logging for overriden commands here,
487                         # because the actual debhelper command may not have
488                         # been run by the rules file target.
489                         my %packages=map { $_ => 1 } @packages;
490                         map { delete $packages{$_} } @exclude;
491                         Debian::Debhelper::Dh_Lib::write_log($override_command, keys %packages);
492                 }
493         }
494 }
495
496 sub loadlog {
497         my $package=shift;
498         my $ext=pkgext($package);
499         
500         my @log;
501         open(LOG, "<", "debian/${ext}debhelper.log") || return;
502         while (<LOG>) {
503                 chomp;
504                 push @log, $_;
505                 $logged{$package}{$_}=1;
506         }
507         close LOG;
508         return @log;
509 }
510                 
511 sub writelog {
512         my $package=shift;
513         my $cmd=shift;
514         my $ext=pkgext($package);
515         
516         open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
517         print LOG $cmd."\n";
518         close LOG;
519 }
520
521 {
522 my %targets;
523 my $rules_parsed;
524
525 sub rules_explicit_target {
526         # Checks if a specified target exists as an explicit target
527         # in debian/rules. 
528         my $target=shift;
529         
530         if (! $rules_parsed) {  
531                 my $processing_targets = 0;
532                 my $not_a_target = 0;
533                 open(MAKE, "make -Rrnpsf debian/rules debhelper-fail-me 2>/dev/null |");
534                 while (<MAKE>) {
535                         if ($processing_targets) {
536                                 if (/^# Not a target:/) {
537                                         $not_a_target = 1;
538                                 }
539                                 else {
540                                         if (!$not_a_target && /^([^#:]+)::?/) {
541                                                 # Target is defined.
542                                                 # NOTE: if it is a depenency
543                                                 # of .PHONY it will be
544                                                 # defined too but that's ok.
545                                                 $targets{$1} = 1;
546                                         }
547                                         # "Not a target:" is always followed by
548                                         # a target name, so resetting this one
549                                         # here is safe.
550                                         $not_a_target = 0;
551                                 }
552                         } elsif (/^# Files$/) {
553                                 $processing_targets = 1;
554                         }
555                 }
556                 close MAKE;
557                 $rules_parsed = 1;
558         }
559
560         return exists $targets{$target};
561 }
562
563 }
564
565 =head1 SEE ALSO
566
567 L<debhelper(7)>
568
569 This program is a part of debhelper.
570
571 =head1 AUTHOR
572
573 Joey Hess <joeyh@debian.org>
574
575 =cut