source: ProjectBuilder/devel/pb-modules/lib/ProjectBuilder/Distribution.pm@ 621

Last change on this file since 621 was 621, checked in by Bruno Cornec, 15 years ago

Adds function pb_distro_installdeps to automatically istall dependencies on distro before building

File size: 12.9 KB
Line 
1#!/usr/bin/perl -w
2#
3# Creates common environment for distributions
4#
5# $Id$
6#
7
8package ProjectBuilder::Distribution;
9
10use strict;
11use Data::Dumper;
12use ProjectBuilder::Base;
13
14# Inherit from the "Exporter" module which handles exporting functions.
15
16use Exporter;
17
18# Export, by default, all the functions into the namespace of
19# any code which uses this module.
20
21our @ISA = qw(Exporter);
22our @EXPORT = qw(pb_distro_init pb_get_distro pb_distro_installdeps);
23
24=pod
25
26=head1 NAME
27
28ProjectBuilder::Distribution, part of the project-builder.org - module dealing with distribution detection
29
30=head1 DESCRIPTION
31
32This modules provides functions to allow detection of Linux distributions, and giving back some attributes concerning them.
33
34=head1 SYNOPSIS
35
36 use ProjectBuilder::Distribution;
37
38 #
39 # Return information on the running distro
40 #
41 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init();
42 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
43 #
44 # Return information on the requested distro
45 #
46 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init("ubuntu","7.10");
47 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
48 #
49 # Return information on the running distro
50 #
51 my ($ddir,$dver) = pb_get_distro();
52 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init($ddir,$dver);
53 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
54
55=head1 USAGE
56
57=over 4
58
59
60=item B<pb_get_distro>
61
62This function returns a list of 2 parameters indicating the distribution name and version of the underlying Linux distribution. The value of those 2 fields may be "unknown" in case the function was unable to recognize on which distribution it is running.
63
64On my home machine it would currently report ("mandriva","2008.0").
65
66=cut
67
68sub pb_distro_init {
69
70my $ddir = shift || undef;
71my $dver = shift || undef;
72my $dfam = "unknown";
73my $dtype = "unknown";
74my $dsuf = "unknown";
75my $dupd = "unknown";
76
77# If we don't know which distribution we're on, then guess it
78($ddir,$dver) = pb_get_distro() if ((not defined $ddir) || (not defined $dver));
79
80# There should be unicity of names between ddir dfam and dtype
81# In case of duplicate, bad things can happen
82if (($ddir =~ /debian/) ||
83 ($ddir =~ /ubuntu/)) {
84 $dfam="du";
85 $dtype="deb";
86 $dsuf=".$ddir$dver";
87 $dupd="apt-get -y install ";
88} elsif ($ddir =~ /gentoo/) {
89 $dfam="gen";
90 $dtype="ebuild";
91 $dver="nover";
92 $dsuf=".$ddir";
93 $dupd="emerge ";
94} elsif ($ddir =~ /slackware/) {
95 $dfam="slack";
96 $dtype="tgz";
97 $dsuf=".$dfam$dver";
98} elsif (($ddir =~ /suse/) ||
99 ($ddir =~ /sles/)) {
100 if ($ddir =~ /opensuse/) {
101 $ddir = "suse";
102 }
103 $dfam="novell";
104 $dtype="rpm";
105 $dsuf=".$ddir$dver";
106 $dupd="yast2 -y ";
107} elsif (($ddir =~ /redhat/) ||
108 ($ddir =~ /rhel/) ||
109 ($ddir =~ /fedora/) ||
110 ($ddir =~ /vmware/) ||
111 ($ddir =~ /centos/)) {
112 $dfam="rh";
113 $dtype="rpm";
114 my $dver1 = $dver;
115 $dver1 =~ s/\.//;
116
117 # By defaut propose yum
118 my $arch=`uname -m`;
119 my $opt = "";
120 chomp($arch);
121 if ($arch eq "x86_64") {
122 $opt="--exclude=*.i?86";
123 }
124 $dupd="yum -y $opt install ";
125 if ($ddir =~ /fedora/) {
126 $dsuf=".fc$dver1";
127 } elsif ($ddir =~ /redhat/) {
128 $dsuf=".rh$dver1";
129 $dupd="unknown";
130 } elsif ($ddir =~ /vmware/) {
131 $dsuf=".vwm$dver1";
132 $dupd="unknown";
133 } else {
134 # older versions of rhel and centos ran up2date
135 if (($dver eq "2.1") || ($dver eq "3") || ($dver eq "4")) {
136 $dupd="up2date -y ";
137 }
138 $dsuf=".$ddir$dver1";
139 }
140} elsif (($ddir =~ /mandrake/) ||
141 ($ddir =~ /mandrakelinux/) ||
142 ($ddir =~ /mandriva/)) {
143 $dfam="md";
144 $dtype="rpm";
145 if ($ddir =~ /mandrakelinux/) {
146 $ddir = "mandrake";
147 }
148 if ($ddir =~ /mandrake/) {
149 my $dver1 = $dver;
150 $dver1 =~ s/\.//;
151 $dsuf=".mdk$dver1";
152 } else {
153 $dsuf=".mdv$dver";
154 }
155 $dupd="urpmi --auto ";
156} elsif ($ddir =~ /freebsd/) {
157 $dfam="bsd";
158 $dtype="port";
159 my $dver1 = $dver;
160 $dver1 =~ s/\.//;
161 $dsuf=".$dfam$dver1";
162} else {
163 $dfam="unknown";
164}
165
166# Update command needs to be run by root
167$dupd = "sudo ".$dupd;
168
169return($ddir, $dver, $dfam, $dtype, $dsuf, $dupd);
170}
171
172=item B<pb_distro_init>
173
174This function returns a list of 5 parameters indicating the distribution name, version, family, type of build system and suffix of packages of the underlying Linux distribution. The value of the 5 fields may be "unknown" in case the function was unable to recognize on which distribution it is running.
175
176As an example, Ubuntu and Debian are in the same "du" family. As well as RedHat, RHEL, CentOS, fedora are on the same "rh" family.
177Mandriva, Open SuSE and Fedora have all the same "rpm" type of build system. Ubuntu ad Debian have the same "deb" type of build system.
178And "fc" is the extension generated for all Fedora packages (Version will be added by pb).
179
180When passing the distribution name and version as parameters, the B<pb_distro_init> function returns the parameter of that distribution instead of the underlying one.
181
182Cf: http://linuxmafia.com/faq/Admin/release-files.html
183Ideas taken from http://search.cpan.org/~kerberus/Linux-Distribution-0.14/lib/Linux/Distribution.pm
184
185=cut
186
187sub pb_get_distro {
188
189my $base="/etc";
190
191# List of files that unambiguously indicates what distro we have
192my %single_rel_files = (
193# Tested
194 'gentoo' => 'gentoo-release', # >= 1.6
195 'slackware' => 'slackware-version', # >= 10.2
196 'mandriva' => 'mandriva-release', # >=2006.0
197 'mandrakelinux' => 'mandrakelinux-release',# = 10.2
198 'fedora' => 'fedora-release', # >= 4
199 'vmware' => 'vmware-release', # >= 3
200 'sles' => 'sles-release', # Doesn't exist as of 10
201# Untested
202 'knoppix' => 'knoppix_version', #
203 'yellowdog' => 'yellowdog-release', #
204 'esmith' => 'e-smith-release', #
205 'turbolinux' => 'turbolinux-release', #
206 'blackcat' => 'blackcat-release', #
207 'aurox' => 'aurox-release', #
208 'annvix' => 'annvix-release', #
209 'cobalt' => 'cobalt-release', #
210 'redflag' => 'redflag-release', #
211 'ark' => 'ark-release', #
212 'pld' => 'pld-release', #
213 'nld' => 'nld-release', #
214 'lfs' => 'lfs-release', #
215 'mk' => 'mk-release', #
216 'conectiva' => 'conectiva-release', #
217 'immunix' => 'immunix-release', #
218 'tinysofa' => 'tinysofa-release', #
219 'trustix' => 'trustix-release', #
220 'adamantix' => 'adamantix_version', #
221 'yoper' => 'yoper-release', #
222 'arch' => 'arch-release', #
223 'libranet' => 'libranet_version', #
224 'valinux' => 'va-release', #
225 'yellowdog' => 'yellowdog-release', #
226 'ultrapenguin' => 'ultrapenguin-release', #
227 );
228
229# List of files that ambiguously indicates what distro we have
230my %ambiguous_rel_files = (
231 'mandrake' => 'mandrake-release', # <= 10.1
232 'debian' => 'debian_version', # >= 3.1
233 'suse' => 'SuSE-release', # >= 10.0
234 'redhat' => 'redhat-release', # >= 7.3
235 'lsb' => 'lsb-release', # ???
236 );
237
238# Should have the same keys as the previous one.
239# If ambiguity, which other distributions should be checked
240my %distro_similar = (
241 'mandrake' => ['mandrake', 'mandrakelinux'],
242 'debian' => ['debian', 'ubuntu'],
243 'suse' => ['suse', 'sles', 'opensuse'],
244 'redhat' => ['redhat', 'rhel', 'centos', 'mandrake', 'vmware'],
245 'lsb' => ['ubuntu', 'lsb'],
246 );
247
248my %distro_match = (
249# Tested
250 'gentoo' => '.* version (.+)',
251 'slackware' => 'S[^ ]* (.+)$',
252# There should be no ambiguity between potential ambiguous distro
253 'mandrakelinux' => 'Mandrakelinux release (.+) \(',
254 'mandrake' => 'Mandr[^ ]* release (.+) \(',
255 'mandriva' => 'Mandr[^ ]* [^ ]* release (.+) \(',
256 'fedora' => 'Fedora .*release (\d+) \(',
257 'vmware' => 'VMware ESX Server (\d+) \(',
258 'rhel' => 'Red Hat (?:Enterprise Linux|Linux Advanced Server) .*release ([0-9.]+).* \(',
259 'centos' => '.*CentOS .*release (.+) ',
260 'redhat' => 'Red Hat Linux release (.+) \(',
261 'sles' => 'SUSE .* Enterprise Server (\d+) \(',
262 'suse' => 'SUSE LINUX (\d.+) \(',
263 'opensuse' => 'openSUSE (\d.+) \(',
264 'lsb' => '.*[^Ubunt].*\nDISTRIB_RELEASE=(.+)',
265# Ubuntu includes a /etc/debian_version file that cretaes an ambiguity with debian
266# So we need to look at distros in reverse alphabetic order to treat ubuntu always first
267 'ubuntu' => '.*Ubuntu.*\nDISTRIB_RELEASE=(.+)',
268 'debian' => '(.+)',
269# Not tested
270 'arch' => '.* ([0-9.]+) .*',
271 'redflag' => 'Red Flag (?:Desktop|Linux) (?:release |\()(.*?)(?: \(.+)?\)',
272);
273
274my $release;
275my $distro;
276
277# Begin to test presence of non-ambiguous files
278# that way we reduce the choice
279my ($d,$r);
280while (($d,$r) = each %single_rel_files) {
281 if (-f "$base/$r" && ! -l "$base/$r") {
282 my $tmp=pb_get_content("$base/$r");
283 # Found the only possibility.
284 # Try to get version and return
285 if (defined ($distro_match{$d})) {
286 ($release) = $tmp =~ m/$distro_match{$d}/m;
287 } else {
288 print STDERR "Unable to find $d version in $r\n";
289 print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
290 $release = "unknown";
291 }
292 return($d,$release);
293 }
294}
295
296# Now look at ambiguous files
297# Ubuntu includes a /etc/debian_version file that creates an ambiguity with debian
298# So we need to look at distros in reverse alphabetic order to treat ubuntu always first via lsb
299foreach $d (reverse keys %ambiguous_rel_files) {
300 $r = $ambiguous_rel_files{$d};
301 if (-f "$base/$r" && !-l "$base/$r") {
302 # Found one possibility.
303 # Get all distros concerned by that file
304 my $tmp=pb_get_content("$base/$r");
305 my $found = 0;
306 my $ptr = $distro_similar{$d};
307 pb_log(2,"amb: ".Dumper($ptr)."\n");
308 $release = "unknown";
309 foreach my $dd (@$ptr) {
310 pb_log(2,"check $dd\n");
311 # Try to check pattern
312 if (defined $distro_match{$dd}) {
313 pb_log(2,"cmp: $distro_match{$dd} - vs - $tmp\n");
314 ($release) = $tmp =~ m/$distro_match{$dd}/m;
315 if ((defined $release) && ($release ne "unknown")) {
316 $distro = $dd;
317 $found = 1;
318 last;
319 }
320 }
321 }
322 if ($found == 0) {
323 print STDERR "Unable to find $d version in $r\n";
324 print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
325 $release = "unknown";
326 } else {
327 return($distro,$release);
328 }
329 }
330}
331return("unknown","unknown");
332}
333
334
335=over 4
336
337=item B<pb_distro_installdeps>
338
339This function install the dependencies required to build the package on an RPM based distro
340dependencies can be passed as a prameter in which case they are not computed
341
342=cut
343
344sub pb_distro_installdeps {
345
346# SPEC file
347my $f = shift || undef;
348my $dtype = shift || undef;
349my $dupd = shift || undef;
350my $deps = shift || undef;
351
352# Protection
353return if (not defined $dupd);
354
355# Get dependecies in the build file if not forced
356$deps = pb_distro_getdeps("$f", $dtype) if (not defined $deps);
357pb_log(2,"deps: $deps\n");
358return if (not defined $deps);
359if ($deps !~ /^[ ]*$/) {
360 pb_system("$dupd $deps","Installing dependencies ($deps)");
361 }
362}
363
364=over 4
365
366=item B<pb_distro_getdeps>
367
368This function computes the dependencies indicated in the build file and return them as a string of packages to install
369
370=cut
371
372sub pb_distro_getdeps {
373
374my $f = shift || undef;
375my $dtype = shift || undef;
376
377my $regexp = "";
378my $deps = "";
379my $sep = $/;
380
381pb_log(3,"entering pb_distro_getdeps: $dtype - $f\n");
382# Protection
383return if (not defined $dtype);
384if ($dtype eq "rpm") {
385 # In RPM this could include files, but we do not handle them atm.
386 $regexp = '^BuildRequires:(.*)$';
387} elsif ($dtype eq "du") {
388 $regexp = '^Build-Depends:(.*)$';
389} elsif ($dtype eq "ebuild") {
390 $sep = '"'.$/;
391 $regexp = '^DEPEND="(.*)"\n'
392} else {
393 # No idea
394 return;
395}
396pb_log(2,"regexp: $regexp\n");
397
398
399# Protection
400return if (not defined $f);
401
402# Preserve separator before using the one we need
403my $oldsep = $/;
404$/ = $sep;
405open(DESC,"$f") || die "Unable to open $f";
406while (<DESC>) {
407 pb_log(4,"read: $_\n");
408 next if (! /$regexp/);
409 chomp();
410 # What we found with the regexp is the list of deps.
411 pb_log(2,"found deps: $_\n");
412 s/$regexp/$1/;
413 # Remove conditions
414 s/>[=]*.*,//g;
415 # Improve string format (remove , and spaces at start, end and in double
416 s/,//g;
417 s/^\s*//;
418 s/\s*$//;
419 s/\s+/ /g;
420 $deps .= " ".$_;
421}
422close(DESC);
423$/ = $oldsep;
424pb_log(2,"now deps: $deps\n");
425my $deps2 = "";
426
427# Avoid to install what is already there
428foreach my $p (split(/ /,$deps)) {
429 if ($dtype eq "rpm") {
430 my $res = pb_system("rpm -q --whatprovides --quiet $p","","quiet");
431 next if ($res eq 0);
432 } elsif ($dtype eq "du") {
433 my $res = pb_system("dpkg -L $p","","quiet");
434 next if ($res eq 0);
435 } elsif ($dtype eq "ebuild") {
436 } else {
437 # Not reached
438 }
439 pb_log(2,"found deps2: $p\n");
440 $deps2 .= " $p";
441}
442
443$deps2 =~ s/^\s*//;
444pb_log(2,"now deps2: $deps2\n");
445return($deps2);
446}
447
448=back
449
450=head1 WEB SITES
451
452The main Web site of the project is available at L<http://www.project-builder.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
453
454=head1 USER MAILING LIST
455
456None exists for the moment.
457
458=head1 AUTHORS
459
460The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
461
462=head1 COPYRIGHT
463
464Project-Builder.org is distributed under the GPL v2.0 license
465described in the file C<COPYING> included with the distribution.
466
467=cut
468
469
4701;
Note: See TracBrowser for help on using the repository browser.