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