]> git.donarmstrong.com Git - debhelper.git/blob - dh
dh: Man page fix. Closes: #485116
[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<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [B<--with> I<addon>] [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 =head1 OPTIONS
38
39 =over 4
40
41 =item B<--until> I<cmd>
42
43 Run commands in the sequence until and including I<cmd>, then stop.
44
45 =item B<--before> I<cmd>
46
47 Run commands in the sequence before I<cmd>, then stop.
48
49 =item B<--after> I<cmd>
50
51 Run commands in the sequence that come after I<cmd>.
52
53 =item B<--remaining>
54
55 Run all commands in the sequence that have yet to be run.
56
57 =item B<--with> I<addon>
58
59 Add the debhelper commands specified by the given addon to appropriate places
60 in the sequence of commands that is run. This option can be repeated more
61 than once, and is used when there is a third-party package that provides
62 debhelper commands. See "SEQUENCE ADDONS" below for documentation about what
63 such packages should do to be supported by --with.
64
65 =back
66
67 All other options passed to dh are passed on to each command it runs. This
68 can be used to set an option like "-v" or "-X" or "-N", as well as for more
69 specialised options.
70
71 =head1 COMMAND SPECIFICATION
72
73 I<cmd> can be a full name of a debhelper command, or a substring. It'll first
74 search for a command in the sequence exactly matching the name, to avoid any
75 ambiguity. If there are multiple substring matches, the last one in the
76 sequence will be used.
77
78 =head1 SEQUENCE ADDONS
79
80 When B<--with> I<addon> is used, dh loads the perl module
81 Debian::Debhelper::Sequence::I<addon>. Two functions are provided to let
82 the module add its commands to sequences:
83
84 =over 4
85
86 =item Debian::Debhelper::Dh_Lib::insert_before(existing_command, new_command)
87
88 Insert I<new_command> in sequences before I<existing_command>.
89
90 =item Debian::Debhelper::Dh_Lib::insert_after(existing_command, new_command)
91
92 Insert I<new_command> in sequences after I<existing_command>.
93
94 =item Debian::Debhelper::Dh_Lib::remove_command(existing_command)
95
96 Remove I<existing_command> from the list of commands to run.
97
98 =back
99
100 =cut
101
102 sub command_pos {
103         my $command=shift;
104         my @sequence=@_;
105
106         foreach my $i (0..$#sequence) {
107                 if ($command eq $sequence[$i]) {
108                         return $i;
109                 }
110         }
111
112         my @matches;
113         foreach my $i (0..$#sequence) {
114                 if ($sequence[$i] =~ /\Q$command\E/) {
115                         push @matches, $i;
116                 }
117         }
118         if (! @matches) {
119                 error "command specification \"$command\" does not match any command in the sequence"
120         }
121         else {
122                 return pop @matches;
123         }
124 }
125
126 =head1 EXAMPLES
127
128 To see what commands are included in a sequence, without actually doing
129 anything:
130
131         dh binary-arch --no-act
132
133 This is a very simple rules file, for packages where the default sequences of
134 commands work with no additional options.
135
136         #!/usr/bin/make -f
137         %:
138                 dh $@
139
140 This is a simple rules file that is a good starting place for customisation.
141 (It's also available in F</usr/share/doc/debhelper/examples/rules.simple>
142
143         #!/usr/bin/make -f
144
145         build:
146                 dh build
147
148         clean:
149                 dh clean
150
151         install: build
152                 dh install
153
154         binary-arch: install
155                 dh binary-arch
156
157         binary-indep: install
158                 dh binary-indep
159
160         binary: binary-arch binary-indep
161
162 Often you'll want to pass an option to ./configure. This uses dh to run all
163 commands before L<dh_auto_configure(1)>, then runs that command by hand,
164 and then finished up by running the rest of the sequence. You could also
165 run ./configure by hand, instead of bothering with using dh_auto_configure.
166 And if necessary, you can add commands to run automake, etc here too.
167
168         build:
169                 dh build --before configure
170                 dh_auto_configure -- --kitchen-sink=yes
171                 dh build --after configure
172
173 Here's how to skip two automated in a row (configure and build), and
174 instead run the commands by hand.
175
176         build:
177                 dh build --before configure
178                 ./mondoconfig
179                 make universe-explode-in-delight
180                 dh build --after build
181
182 Another common case is wanting to run some code manually after a particular
183 debhelper command is run.
184
185         install: build
186                 dh install --until dh_fixperms
187                 # dh_fixperms has run, now override it for one program
188                 chmod 4755 debian/foo/usr/bin/foo
189                 # and continue
190                 dh install --after dh_fixperms
191
192 It's also fine to run debhelper commands early. Just make sure that at
193 least dh_prep is run from the sequence first, and be sure to use the
194 B<--remaining> option to ensure that commands that normally come before
195 those in the sequence are still run.
196
197         install:
198                 dh install --until dh_prep
199                 dh_installdocs README TODO
200                 dh_installchangelogs Changes
201                 dh install --remaining
202
203         binary-arch: install
204                 dh_strip -X foo
205                 dh binary-arch --remaining
206
207 =cut
208
209 # Stash this away before init modifies it.
210 my @ARGV_orig=@ARGV;
211
212 init();
213 inhibit_log();
214
215 # Definitions of sequences.
216 my %sequences;
217 $sequences{build} = [qw{
218         dh_testdir
219         dh_auto_configure
220         dh_auto_build
221         dh_auto_test
222 }],
223 $sequences{clean} = [qw{
224         dh_testdir
225         dh_auto_clean
226         dh_clean
227 }];
228 $sequences{install} = [@{$sequences{build}}, qw{
229         dh_testroot
230         dh_prep
231         dh_installdirs
232         dh_auto_install
233
234         dh_install
235         dh_installdocs
236         dh_installchangelogs
237         dh_installexamples
238         dh_installman
239
240         dh_installcatalogs
241         dh_installcron
242         dh_installdebconf
243         dh_installcatalogs
244         dh_installemacsen
245         dh_installifupdown
246         dh_installinfo
247         dh_installinit
248         dh_installmenu
249         dh_installmime
250         dh_installmodules
251         dh_installlogcheck
252         dh_installlogrotate
253         dh_installpam
254         dh_installppp
255         dh_installudev
256         dh_installwm
257         dh_installxfonts
258         dh_lintian
259         dh_desktop
260         dh_gconf
261         dh_icons
262         dh_perl
263         dh_scrollkeeper
264         dh_usrlocal
265
266         dh_link
267         dh_compress
268         dh_fixperms
269 }];
270 my @b=qw{
271         dh_installdeb
272         dh_gencontrol
273         dh_md5sums
274         dh_builddeb
275 };
276 $sequences{'binary-indep'} = [@{$sequences{install}}, @b];
277 $sequences{binary} = [@{$sequences{install}}, qw{
278         dh_strip
279         dh_makeshlibs
280         dh_shlibdeps
281 }, @b];
282 $sequences{'binary-arch'} = [@{$sequences{binary}}];
283
284 # --with python-support is enabled by default, at least for now
285 push @{$dh{WITH}}, "python-support";
286
287 # sequence addon interface
288 sub _insert {
289         my $offset=shift;
290         my $existing=shift;
291         my $new=shift;
292         foreach my $sequence (keys %sequences) {
293                 my @list=@{$sequences{$sequence}};
294                 next unless grep $existing, @list;
295                 my @new;
296                 foreach my $command (@list) {
297                         if ($command eq $existing) {
298                                 push @new, $new if $offset < 0;
299                                 push @new, $command;
300                                 push @new, $new if $offset > 0;
301                         }
302                         else {
303                                 push @new, $command;
304                         }
305                 }
306                 $sequences{$sequence}=\@new;
307         }
308 }
309 sub insert_before {
310         _insert(-1, @_);
311 }
312 sub insert_after {
313         _insert(1, @_);
314 }
315 sub remove_command {
316         my $command=shift;
317         foreach my $sequence (keys %sequences) {
318                 $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}];
319         }
320         
321 }
322 foreach my $addon (@{$dh{WITH}}) {
323         my $mod="Debian::Debhelper::Sequence::$addon";
324         $mod=~s/-/_/g;
325         eval "use $mod";
326         if ($@) {
327                 error("--with $addon not supported or failed to load module $mod");
328         }
329 }
330
331 # Get the sequence of commands to run.
332 if (! @ARGV) {
333         error "specify a sequence to run";
334 }
335 my $sequence=shift;
336 if (! exists $sequences{$sequence}) {
337         error "Unknown sequence $sequence (chose 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)$/) {
365                 shift @ARGV_orig;
366                 next;
367         }
368         elsif ($opt =~ /^--?(no-act|remaining|(after|until|before)=)/) {
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($package, $sequence[$startpoint{$package}-1]);
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         elsif (! @exclude) {
436                 # Run command for all packages.
437                 run($sequence[$i], @options);
438         }
439         else {
440                 # Run command for only a subset of packages.
441                 run($sequence[$i], @options,
442                         map { "-N$_" } @exclude);
443         }
444 }
445
446 sub run {
447         my $command=shift;
448         my @options=@_;
449         
450         # 3 space indent lines the command being run up under the 
451         # sequence name after "dh ".
452         print "   ".escape_shell($command, @options)."\n";
453
454         if (! $dh{NO_ACT}) {
455                 my $ret=system($command, @options);
456                 if ($ret >> 8 != 0) {
457                         exit $ret >> 8;
458                 }
459                 elsif ($ret) {
460                         exit 1;
461                 }
462         }
463 }
464
465 sub loadlog {
466         my $package=shift;
467         my $ext=pkgext($package);
468         
469         my @log;
470         open(LOG, "<", "debian/${ext}debhelper.log") || return;
471         while (<LOG>) {
472                 chomp;
473                 push @log, $_;
474                 $logged{$package}{$_}=1;
475         }
476         close LOG;
477         return @log;
478 }
479                 
480 sub writelog {
481         my $package=shift;
482         my $cmd=shift;
483         my $ext=pkgext($package);
484         
485         open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
486         print LOG $cmd."\n";
487         close LOG;
488 }
489
490 =head1 SEE ALSO
491
492 L<debhelper(7)>
493
494 This program is a part of debhelper.
495
496 =head1 AUTHOR
497
498 Joey Hess <joeyh@debian.org>
499
500 =cut