]> git.donarmstrong.com Git - debhelper.git/blob - dh
typo
[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=(
258         dh_pycompat => 1,
259         dh_pysupport => 1,
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 # Get the options to pass to commands in the sequence.
274 # Filter out options intended only for this program.
275 my @options;
276 if ($sequence eq 'binary-arch') {
277         push @options, "-a";
278 }
279 elsif ($sequence eq 'binary-indep') {
280         push @options, "-i";
281 }
282 while (@ARGV_orig) {
283         my $opt=shift @ARGV_orig;
284         next if $opt eq $sequence;
285         if ($opt =~ /^--?(after|until|before)$/) {
286                 shift @ARGV_orig;
287                 next;
288         }
289         elsif ($opt =~ /^--?(no-act|remaining|(after|until|before)=)/) {
290                 next;
291         }
292         push @options, $opt;
293 }
294
295 # Figure out at what point in the sequence to start for each package.
296 my %logged;
297 my %startpoint;
298 foreach my $package (@{$dh{DOPACKAGES}}) {
299         my @log=loadlog($package);
300         if ($dh{AFTER}) {
301                 # Run commands in the sequence that come after the
302                 # specified command.
303                 $startpoint{$package}=command_pos($dh{AFTER}, @sequence) + 1;
304                 # Write a dummy log entry indicating that the specified
305                 # command was, in fact, run. This handles the case where
306                 # no commands remain to run after it, communicating to
307                 # future dh instances that the specified command should not
308                 # be run again.
309                 writelog($package, $sequence[$startpoint{$package}-1]);
310         }
311         elsif ($dh{REMAINING}) {
312                 # Start at the beginning so all remaining commands will get
313                 # run.
314                 $startpoint{$package}=0;
315         }
316         else {
317                 # Find the last logged command that is in the sequence, and
318                 # continue with the next command after it. If no logged
319                 # command is in the sequence, we're starting at the beginning..                         
320                 $startpoint{$package}=0;
321 COMMAND:        foreach my $command (reverse @log) {
322                         foreach my $i (0..$#sequence) {
323                                 if ($command eq $sequence[$i]) {
324                                         $startpoint{$package}=$i+1;
325                                         last COMMAND;
326                                 }
327                         }
328                 }
329         }
330 }
331
332 # Figure out what point in the sequence to go to.
333 my $stoppoint=$#sequence;
334 if ($dh{UNTIL}) {
335         $stoppoint=command_pos($dh{UNTIL}, @sequence);
336 }
337 elsif ($dh{BEFORE}) {
338         $stoppoint=command_pos($dh{BEFORE}, @sequence) - 1;
339 }
340
341 # Now run the commands in the sequence.
342 foreach my $i (0..$stoppoint) {
343         # Figure out which packages need to run this command.
344         my @exclude;
345         foreach my $package (@{$dh{DOPACKAGES}}) {
346                 if ($startpoint{$package} > $i ||
347                     $logged{$package}{$sequence[$i]}) {
348                         push @exclude, $package;
349                 }
350         }
351         
352         if (@exclude eq @{$dh{DOPACKAGES}}) {
353                 # Command already done for all packages.
354                 next;
355         }
356         elsif (! @exclude) {
357                 # Run command for all packages.
358                 run($sequence[$i], @options);
359         }
360         else {
361                 # Run command for only a subset of packages.
362                 run($sequence[$i], @options,
363                         map { "-N$_" } @exclude);
364         }
365 }
366
367 sub run {
368         my $command=shift;
369         my @options=@_;
370         
371         # If a third party command is not in /usr/bin, don't try to run it.
372         if ($thirdparty{$command} && ! -x "/usr/bin/$command") {
373                 return;
374         }
375
376         # 3 space indent lines the command being run up under the 
377         # sequence name after "dh ".
378         print "   ".escape_shell($command, @options)."\n";
379
380         if (! $dh{NO_ACT}) {
381                 my $ret=system($command, @options);
382                 if ($ret >> 8 != 0) {
383                         exit $ret >> 8;
384                 }
385                 elsif ($ret) {
386                         exit 1;
387                 }
388         }
389 }
390
391 sub loadlog {
392         my $package=shift;
393         my $ext=pkgext($package);
394         
395         my @log;
396         open(LOG, "<", "debian/${ext}debhelper.log") || return;
397         while (<LOG>) {
398                 chomp;
399                 push @log, $_;
400                 $logged{$package}{$_}=1;
401         }
402         close LOG;
403         return @log;
404 }
405                 
406 sub writelog {
407         my $package=shift;
408         my $cmd=shift;
409         my $ext=pkgext($package);
410         
411         open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
412         print LOG $cmd."\n";
413         close LOG;
414 }
415
416 =head1 SEE ALSO
417
418 L<debhelper(7)>
419
420 This program is a part of debhelper.
421
422 =head1 AUTHOR
423
424 Joey Hess <joeyh@debian.org>
425
426 =cut