]> git.donarmstrong.com Git - debhelper.git/blob - dh
dh: Fix typo in example. Closes: #500836
[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: build-stamp
146         build-stamp:
147                 dh build
148                 touch build-stamp
149
150         clean:
151                 dh clean
152
153         install: build install-stamp
154         install-stamp:
155                 dh install
156                 touch install-stamp
157
158         binary-arch: install
159                 dh binary-arch
160
161         binary-indep: install
162                 dh binary-indep
163
164         binary: binary-arch binary-indep
165
166 Often you'll want to pass an option to ./configure. This uses dh to run all
167 commands before L<dh_auto_configure(1)>, then runs that command by hand,
168 and then finished up by running the rest of the sequence. You could also
169 run ./configure by hand, instead of bothering with using dh_auto_configure.
170 And if necessary, you can add commands to run automake, etc here too.
171
172         build: build-stamp
173         build-stamp:
174                 dh build --before configure
175                 dh_auto_configure -- --kitchen-sink=yes
176                 dh build --after configure
177                 touch build-stamp
178
179 Here's how to skip two automated in a row (configure and build), and
180 instead run the commands by hand.
181
182         build: build-stamp
183         build-stamp:
184                 dh build --before configure
185                 ./mondoconfig
186                 make universe-explode-in-delight
187                 dh build --after build
188                 touch build-stamp
189
190 Another common case is wanting to run some code manually after a particular
191 debhelper command is run.
192
193         install: build install-stamp
194         install-stamp:
195                 dh install --until dh_fixperms
196                 # dh_fixperms has run, now override it for one program
197                 chmod 4755 debian/foo/usr/bin/foo
198                 # and continue
199                 dh install --after dh_fixperms
200                 touch install-stamp
201
202 It's also fine to run debhelper commands early. Just make sure that at
203 least dh_prep is run from the sequence first, and be sure to use the
204 B<--remaining> option to ensure that commands that normally come before
205 those in the sequence are still run.
206
207         install: build install-stamp
208         install-stamp:
209                 dh install --until dh_prep
210                 dh_installdocs README TODO
211                 dh_installchangelogs Changes
212                 dh install --remaining
213                 touch install-stamp
214
215         binary-arch: install
216                 dh_strip -X foo
217                 dh binary-arch --remaining
218
219 =cut
220
221 # Stash this away before init modifies it.
222 my @ARGV_orig=@ARGV;
223
224 init();
225 inhibit_log();
226
227 # Definitions of sequences.
228 my %sequences;
229 $sequences{build} = [qw{
230         dh_testdir
231         dh_auto_configure
232         dh_auto_build
233         dh_auto_test
234 }],
235 $sequences{clean} = [qw{
236         dh_testdir
237         dh_auto_clean
238         dh_clean
239 }];
240 $sequences{install} = [@{$sequences{build}}, qw{
241         dh_testroot
242         dh_prep
243         dh_installdirs
244         dh_auto_install
245
246         dh_install
247         dh_installdocs
248         dh_installchangelogs
249         dh_installexamples
250         dh_installman
251
252         dh_installcatalogs
253         dh_installcron
254         dh_installdebconf
255         dh_installcatalogs
256         dh_installemacsen
257         dh_installifupdown
258         dh_installinfo
259         dh_installinit
260         dh_installmenu
261         dh_installmime
262         dh_installmodules
263         dh_installlogcheck
264         dh_installlogrotate
265         dh_installpam
266         dh_installppp
267         dh_installudev
268         dh_installwm
269         dh_installxfonts
270         dh_lintian
271         dh_desktop
272         dh_gconf
273         dh_icons
274         dh_perl
275         dh_scrollkeeper
276         dh_usrlocal
277
278         dh_link
279         dh_compress
280         dh_fixperms
281 }];
282 my @b=qw{
283         dh_installdeb
284         dh_gencontrol
285         dh_md5sums
286         dh_builddeb
287 };
288 $sequences{'binary-indep'} = [@{$sequences{install}}, @b];
289 $sequences{binary} = [@{$sequences{install}}, qw{
290         dh_strip
291         dh_makeshlibs
292         dh_shlibdeps
293 }, @b];
294 $sequences{'binary-arch'} = [@{$sequences{binary}}];
295
296 # --with python-support is enabled by default, at least for now
297 unshift @{$dh{WITH}}, "python-support";
298
299 # sequence addon interface
300 sub _insert {
301         my $offset=shift;
302         my $existing=shift;
303         my $new=shift;
304         foreach my $sequence (keys %sequences) {
305                 my @list=@{$sequences{$sequence}};
306                 next unless grep $existing, @list;
307                 my @new;
308                 foreach my $command (@list) {
309                         if ($command eq $existing) {
310                                 push @new, $new if $offset < 0;
311                                 push @new, $command;
312                                 push @new, $new if $offset > 0;
313                         }
314                         else {
315                                 push @new, $command;
316                         }
317                 }
318                 $sequences{$sequence}=\@new;
319         }
320 }
321 sub insert_before {
322         _insert(-1, @_);
323 }
324 sub insert_after {
325         _insert(1, @_);
326 }
327 sub remove_command {
328         my $command=shift;
329         foreach my $sequence (keys %sequences) {
330                 $sequences{$sequence}=[grep { $_ ne $command } @{$sequences{$sequence}}];
331         }
332         
333 }
334 foreach my $addon (@{$dh{WITH}}) {
335         my $mod="Debian::Debhelper::Sequence::$addon";
336         $mod=~s/-/_/g;
337         eval "use $mod";
338         if ($@) {
339                 error("--with $addon not supported or failed to load module $mod");
340         }
341 }
342
343 # Get the sequence of commands to run.
344 if (! @ARGV) {
345         error "specify a sequence to run";
346 }
347 my $sequence=shift;
348 if (! exists $sequences{$sequence}) {
349         error "Unknown sequence $sequence (chose from: ".
350                 join(" ", sort keys %sequences).")";
351 }
352 my @sequence=@{$sequences{$sequence}};
353
354 # The list of all packages that can be acted on.
355 my @packages=@{$dh{DOPACKAGES}};
356
357 # Get the options to pass to commands in the sequence.
358 # Filter out options intended only for this program.
359 my @options;
360 if ($sequence eq 'binary-arch') {
361         push @options, "-a";
362         # as an optimisation, remove from the list any packages
363         # that are not arch dependent
364         my %arch_packages = map { $_ => 1 } getpackages("arch");
365         @packages = grep { $arch_packages{$_} } @packages;
366 }
367 elsif ($sequence eq 'binary-indep') {
368         push @options, "-i";
369         # ditto optimisation for arch indep
370         my %indep_packages = map { $_ => 1 } getpackages("indep");
371         @packages = grep { $indep_packages{$_} } @packages;
372 }
373 while (@ARGV_orig) {
374         my $opt=shift @ARGV_orig;
375         next if $opt eq $sequence;
376         if ($opt =~ /^--?(after|until|before|with)$/) {
377                 shift @ARGV_orig;
378                 next;
379         }
380         elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with)=)/) {
381                 next;
382         }
383         push @options, $opt;
384 }
385
386 # Figure out at what point in the sequence to start for each package.
387 my %logged;
388 my %startpoint;
389 foreach my $package (@packages) {
390         my @log=loadlog($package);
391         if ($dh{AFTER}) {
392                 # Run commands in the sequence that come after the
393                 # specified command.
394                 $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1;
395                 # Write a dummy log entry indicating that the specified
396                 # command was, in fact, run. This handles the case where
397                 # no commands remain to run after it, communicating to
398                 # future dh instances that the specified command should not
399                 # be run again.
400                 writelog($package, $sequence[$startpoint{$package}-1]);
401         }
402         elsif ($dh{REMAINING}) {
403                 # Start at the beginning so all remaining commands will get
404                 # run.
405                 $startpoint{$package}=0;
406         }
407         else {
408                 # Find the last logged command that is in the sequence, and
409                 # continue with the next command after it. If no logged
410                 # command is in the sequence, we're starting at the beginning..                         
411                 $startpoint{$package}=0;
412 COMMAND:        foreach my $command (reverse @log) {
413                         foreach my $i (0..$#sequence) {
414                                 if ($command eq $sequence[$i]) {
415                                         $startpoint{$package}=$i+1;
416                                         last COMMAND;
417                                 }
418                         }
419                 }
420         }
421 }
422
423 # Figure out what point in the sequence to go to.
424 my $stoppoint=$#sequence;
425 if ($dh{UNTIL}) {
426         $stoppoint=command_pos($dh{UNTIL}, @sequence);
427 }
428 elsif ($dh{BEFORE}) {
429         $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1;
430 }
431
432 # Now run the commands in the sequence.
433 foreach my $i (0..$stoppoint) {
434         # Figure out which packages need to run this command.
435         my @exclude;
436         foreach my $package (@packages) {
437                 if ($startpoint{$package} > $i ||
438                     $logged{$package}{$sequence[$i]}) {
439                         push @exclude, $package;
440                 }
441         }
442         
443         if (@exclude eq @packages) {
444                 # Command already done for all packages.
445                 next;
446         }
447         elsif (! @exclude) {
448                 # Run command for all packages.
449                 run($sequence[$i], @options);
450         }
451         else {
452                 # Run command for only a subset of packages.
453                 run($sequence[$i], @options,
454                         map { "-N$_" } @exclude);
455         }
456 }
457
458 sub run {
459         my $command=shift;
460         my @options=@_;
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 }
476
477 sub loadlog {
478         my $package=shift;
479         my $ext=pkgext($package);
480         
481         my @log;
482         open(LOG, "<", "debian/${ext}debhelper.log") || return;
483         while (<LOG>) {
484                 chomp;
485                 push @log, $_;
486                 $logged{$package}{$_}=1;
487         }
488         close LOG;
489         return @log;
490 }
491                 
492 sub writelog {
493         my $package=shift;
494         my $cmd=shift;
495         my $ext=pkgext($package);
496         
497         open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
498         print LOG $cmd."\n";
499         close LOG;
500 }
501
502 =head1 SEE ALSO
503
504 L<debhelper(7)>
505
506 This program is a part of debhelper.
507
508 =head1 AUTHOR
509
510 Joey Hess <joeyh@debian.org>
511
512 =cut