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