chiark / gitweb /
devscripts (2.10.69+squeeze4) stable-security; urgency=high
[devscripts.git] / scripts / mk-build-deps.pl
1 #!/usr/bin/perl
2
3 # mk-build-deps: make a dummy package to satisfy build-deps of a package
4 # Copyright 2008 by Vincent Fourmond
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
20 # Changes:
21 # * (Vincent Fourmond 4/4/2008): now take Build-Depends-Indep
22 #   into consideration
23
24 =head1 NAME
25
26 mk-build-deps - build a package satisfying a package's build-dependencies
27
28 =head1 SYNOPSIS
29
30 B<mk-build-deps> --help|--version
31
32 B<mk-build-deps> [options] <control file | package name> [...]
33
34 =head1 DESCRIPTION
35
36 Given a package name and/or control file, B<mk-build-deps>
37 will use B<equivs> to generate a binary package which may be installed to
38 satisfy all the build dependencies of the given package.
39
40 If B<--build-dep> and/or B<--build-indep> are given, then the resulting binary
41 package(s) will depend solely on the Build-Depends/Build-Depends-Indep
42 dependencies, respectively.
43
44 =head1 OPTIONS
45
46 =over 4
47
48 =item B<-i>, B<--install>
49
50 Install the generated packages and its build-dependencies.
51
52 =item B<-t>, B<--tool>
53
54 When installing the generated package use the specified tool.
55 (default: apt-get)
56
57 =item B<-r>, B<--remove>
58
59 Remove the package file after installing it. Ignored if used without
60 the install switch.
61
62 =item B<-a> I<foo>, B<--arch> I<foo>
63
64 If the source package has architecture-specific build dependencies, produce
65 a package for architecture I<foo>, not for the system architecture. (If the
66 source package does not have architecture-specific build dependencies,
67 the package produced is always for the pseudo-architecture B<all>.)
68
69 =item B<-B>, B<--build-dep>
70
71 Generate a package which only depends on the source package's Build-Depends
72 dependencies.
73
74 =item B<-A>, B<--build-indep>
75
76 Generate a package which only depends on the source package's
77 Build-Depends-Indep dependencies.
78
79 =item B<-h>, B<--help>
80
81 Show a summary of options.
82
83 =item B<-v>, B<--version>
84
85 Show version and copyright information.
86
87 =back
88
89 =head1 AUTHOR
90
91 B<mk-build-deps> is copyright by Vincent Fourmond and was modified for the
92 devscripts package by Adam D. Barratt <adam@adam-barratt.org.uk>.
93
94 This program comes with ABSOLUTELY NO WARRANTY.
95 You are free to redistribute this code under the terms of the GNU
96 General Public License, version 2 or later.
97
98 =cut
99
100 use strict;
101 use warnings;
102 use Getopt::Long;
103 use File::Basename;
104 use Pod::Usage;
105 use Dpkg::Control;
106
107 my $progname = basename($0);
108 my $opt_install;
109 my $opt_remove=0;
110 my ($opt_help, $opt_version, $opt_arch, $opt_dep, $opt_indep);
111 my $control;
112 my $install_tool;
113 my @packages;
114 my @deb_files;
115
116 my @config_files = ('/etc/devscripts.conf', '~/.devscripts');
117 my %config_vars = (
118                     'MKBUILDDEPS_TOOL' => 'apt-get',
119                     'MKBUILDDEPS_REMOVE_AFTER_INSTALL' => 'no'
120                     );
121 my %config_default = %config_vars;
122
123 my $shell_cmd;
124 # Set defaults
125 foreach my $var (keys %config_vars) {
126         $shell_cmd .= qq[$var="$config_vars{$var}";\n];
127 }
128 $shell_cmd .= 'for file in ' . join(" ",@config_files) . "; do\n";
129 $shell_cmd .= '[ -f $file ] && . $file; done;' . "\n";
130 # Read back values
131 foreach my $var (keys %config_vars) { $shell_cmd .= "echo \$$var;\n" }
132 my $shell_out = `/bin/bash -c '$shell_cmd'`;
133 @config_vars{keys %config_vars} = split /\n/, $shell_out, -1;
134
135 # Check validity
136 $config_vars{'MKBUILDDEPS_TOOL'} =~ /./
137         or $config_vars{'MKBUILDDEPS_TOOL'}='/usr/bin/apt-get';
138 $config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'} =~ /^(yes|no)$/
139         or $config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'}='no';
140
141 $install_tool = $config_vars{'MKBUILDDEPS_TOOL'};
142
143 if ($config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'} =~ /yes/) {
144         $opt_remove=1;
145 }
146
147
148 GetOptions("help|h" => \$opt_help,
149            "version|v" => \$opt_version,
150            "install|i" => \$opt_install,
151            "remove|r" => \$opt_remove,
152            "tool|t=s" => \$install_tool,
153            "arch|a=s" => \$opt_arch,
154            "build-dep|B" => \$opt_dep,
155            "build-indep|A" => \$opt_indep,
156            )
157     or pod2usage({ -exitval => 1, -verbose => 0 });
158
159 pod2usage({ -exitval => 0, -verbose => 1 }) if ($opt_help);
160 if ($opt_version) { version(); exit 0; }
161
162 if (!@ARGV) {
163     if (-r 'debian/control') {
164         push(@ARGV, 'debian/control');
165     }
166 }
167
168 pod2usage({ -exitval => 1, -verbose => 0 }) unless @ARGV;
169
170 system("command -v equivs-build >/dev/null 2>&1");
171 if ($?) {
172     die "$progname: You must have equivs installed to use this program.\n";
173 }
174
175 while ($control = shift) {
176     my ($name, $fh);
177     if (-r $control and -f $control) {
178         open $fh, $control || do {
179             warn "Unable to open $control: $!\n";
180             next;
181         };
182         $name = 'Source';
183     }
184     else {
185         open $fh, "apt-cache showsrc $control |" || do {
186             warn "Unable to run apt-cache: $!\n";
187             next;
188         };
189         $name = 'Package';
190     }
191
192     my $ctrl = Dpkg::Control->new(type => CTRL_INFO_SRC);
193     if ($ctrl->parse($fh, $control)) {
194         my $args = '';
195         my $arch = 'all';
196         my ($build_deps, $build_dep, $build_indep);
197
198         if (exists $ctrl->{'Build-Depends'}) {
199             $build_dep = $ctrl->{'Build-Depends'};
200             $build_dep =~ s/\n/ /g;
201             $build_deps = $build_dep;
202         }
203         if (exists $ctrl->{'Build-Depends-Indep'}) {
204             $build_indep = $ctrl->{'Build-Depends-Indep'};
205             $build_indep =~ s/\n/ /g;
206             $build_deps .= ', ' if $build_deps;
207             $build_deps .= $build_indep;
208         }
209
210         die "$progname: Unable to find build-deps for $ctrl->{$name}\n" unless $build_deps;
211
212         # Only build a package with both B-D and B-D-I in Depends if the
213         # B-D/B-D-I specific packages weren't requested
214         if (!($opt_dep || $opt_indep)) {
215             push(@packages,
216                  build_equiv({ depends => $build_deps,
217                                name => $ctrl->{$name},
218                                type => 'build-deps',
219                                version => $ctrl->{Version} }));
220             next;
221         }
222         if ($opt_dep) {
223             push(@packages,
224                  build_equiv({ depends => $build_dep,
225                                name => $ctrl->{$name},
226                                type => 'build-deps-depends',
227                                version => $ctrl->{Version} }));
228         }
229         if ($opt_indep) {
230             push(@packages,
231                  build_equiv({ depends => $build_indep,
232                                name => $ctrl->{$name},
233                                type => 'build-deps-indep',
234                                version => $ctrl->{Version} }));
235         }
236     }
237     else {
238         die "$progname: Unable to find package name in '$control'\n";
239     }
240 }
241
242 use Text::ParseWords;
243
244 if ($opt_install) {
245     for my $package (@packages) {
246         my $file = glob "${package}_*.deb";
247         push @deb_files, $file;
248     }
249
250     system 'dpkg', '--unpack', @deb_files;
251     system shellwords($install_tool), '-f', 'install';
252
253     if ($opt_remove) {
254         foreach my $file (@deb_files) {
255             unlink $file;
256         }
257     }
258 }
259
260 sub version {
261     print <<"EOF";
262 This is $progname, from the Debian devscripts package, version ###VERSION###
263 Copyright (C) 2008 Vincent Fourmond
264
265 This program comes with ABSOLUTELY NO WARRANTY.
266 You are free to redistribute this code under the terms of the
267 GNU General Public License, version 2, or (at your option) any
268 later version.
269 EOF
270 }
271
272 sub build_equiv
273 {
274     my ($opts) = @_;
275     my $args = '';
276     my $arch = 'all';
277
278     if ($opts->{depends} =~ /\[|\]/) {
279         $arch = 'any';
280
281         if (defined $opt_arch) {
282             $args = "--arch=$opt_arch ";
283         }
284     }
285
286     open EQUIVS, "| equivs-build $args-"
287         or die "$progname: Failed to execute equivs-build: $!\n";
288     print EQUIVS "Section: devel\n" .
289     "Priority: optional\n".
290     "Standards-Version: 3.7.3\n\n".
291     "Package: $opts->{name}-$opts->{type}\n".
292     "Architecture: $arch\n".
293     "Depends: build-essential, $opts->{depends}\n";
294     print EQUIVS "Version: $opts->{version}\n" if $opts->{version};
295
296     print EQUIVS "Description: build-dependencies for $opts->{name}\n" .
297     " Depencency package to build the '$opts->{name}' package\n";
298
299     close EQUIVS;
300     return "$opts->{name}-$opts->{type}";
301 }