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