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