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