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