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

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

Take only the major number of the version for asianux

File size: 16.5 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;
13use ProjectBuilder::Conf;
14use File::Basename;
15use File::Copy;
16
17# Inherit from the "Exporter" module which handles exporting functions.
18
19use Exporter;
20
21# Export, by default, all the functions into the namespace of
22# any code which uses this module.
23
24our @ISA = qw(Exporter);
25our @EXPORT = qw(pb_distro_init pb_distro_get pb_distro_installdeps pb_distro_getdeps pb_distro_only_deps_needed pb_distro_setuprepo pb_distro_get_param);
26
27=pod
28
29=head1 NAME
30
31ProjectBuilder::Distribution, part of the project-builder.org - module dealing with distribution detection
32
33=head1 DESCRIPTION
34
35This modules provides functions to allow detection of Linux distributions, and giving back some attributes concerning them.
36
37=head1 SYNOPSIS
38
39 use ProjectBuilder::Distribution;
40
41 #
42 # Return information on the running distro
43 #
44 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init();
45 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
46 #
47 # Return information on the requested distro
48 #
49 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init("ubuntu","7.10");
50 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
51 #
52 # Return information on the running distro
53 #
54 my ($ddir,$dver) = pb_distro_get();
55 my ($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd) = pb_distro_init($ddir,$dver);
56 print "distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf, $pbupd)."\n";
57
58=head1 USAGE
59
60=over 4
61
62
63=item B<pb_distro_get>
64
65This 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.
66
67On my home machine it would currently report ("mandriva","2008.0").
68
69=cut
70
71sub pb_distro_init {
72
73my $ddir = shift || undef;
74my $dver = shift || undef;
75my $dfam = "unknown";
76my $dtype = "unknown";
77my $dsuf = "unknown";
78my $dupd = "unknown";
79
80# If we don't know which distribution we're on, then guess it
81($ddir,$dver) = pb_distro_get() if ((not defined $ddir) || (not defined $dver));
82
83# There should be unicity of names between ddir dfam and dtype
84# In case of duplicate, bad things can happen
85if (($ddir =~ /debian/) ||
86 ($ddir =~ /ubuntu/)) {
87 $dfam="du";
88 $dtype="deb";
89 $dsuf=".$ddir$dver";
90 # Chaining the commands allow to only test for what is able o be installed,
91 # not the update of the repo which may well be unaccessible if too old
92 $dupd="sudo apt-get update ; sudo apt-get -y install ";
93} elsif ($ddir =~ /gentoo/) {
94 $dfam="gen";
95 $dtype="ebuild";
96 $dver="nover";
97 $dsuf=".$ddir";
98 $dupd="sudo emerge ";
99} elsif ($ddir =~ /slackware/) {
100 $dfam="slack";
101 $dtype="tgz";
102 $dsuf=".$dfam$dver";
103} elsif (($ddir =~ /suse/) ||
104 ($ddir =~ /sles/)) {
105 if ($ddir =~ /opensuse/) {
106 $ddir = "suse";
107 }
108 $dfam="novell";
109 $dtype="rpm";
110 $dsuf=".$ddir$dver";
111 $dupd="export TERM=linux ; export PATH=\$PATH:/sbin:/usr/sbin ; sudo yast2 -i ";
112} elsif (($ddir =~ /redhat/) ||
113 ($ddir =~ /rhel/) ||
114 ($ddir =~ /fedora/) ||
115 ($ddir =~ /vmware/) ||
116 ($ddir =~ /asianux/) ||
117 ($ddir =~ /centos/)) {
118 $dfam="rh";
119 $dtype="rpm";
120 my $dver1 = $dver;
121 $dver1 =~ s/\.//;
122
123 # By defaut propose yum
124 my $arch=`uname -m`;
125 my $opt = "";
126 chomp($arch);
127 if ($arch eq "x86_64") {
128 $opt="--exclude=*.i?86";
129 }
130 $dupd="sudo yum clean all; sudo yum update ; sudo yum -y $opt install ";
131 if ($ddir =~ /fedora/) {
132 $dsuf=".fc$dver1";
133 } elsif ($ddir =~ /redhat/) {
134 $dsuf=".rh$dver1";
135 $dupd="unknown";
136 } elsif ($ddir =~ /asianux/) {
137 $dsuf=".asianux$dver1";
138 } elsif ($ddir =~ /vmware/) {
139 $dsuf=".vwm$dver1";
140 $dupd="unknown";
141 } else {
142 # older versions of rhel ran up2date
143 if ((($dver eq "2.1") || ($dver eq "3") || ($dver eq "4")) && ($ddir eq "rhel")) {
144 $dupd="sudo up2date -y ";
145 }
146 $dsuf=".$ddir$dver1";
147 }
148} elsif (($ddir =~ /mandrake/) ||
149 ($ddir =~ /mandrakelinux/) ||
150 ($ddir =~ /mandriva/)) {
151 $dfam="md";
152 $dtype="rpm";
153 if ($ddir =~ /mandrakelinux/) {
154 $ddir = "mandrake";
155 }
156 if ($ddir =~ /mandrake/) {
157 my $dver1 = $dver;
158 $dver1 =~ s/\.//;
159 $dsuf=".mdk$dver1";
160 } else {
161 $dsuf=".mdv$dver";
162 }
163 # Chaining the commands allow to only test for what is able o be installed,
164 # not the update of the repo which may well be unaccessible if too old
165 $dupd="sudo urpmi.update -a ; sudo urpmi --auto ";
166} elsif ($ddir =~ /freebsd/) {
167 $dfam="bsd";
168 $dtype="port";
169 my $dver1 = $dver;
170 $dver1 =~ s/\.//;
171 $dsuf=".$dfam$dver1";
172} else {
173 $dfam="unknown";
174}
175
176return($ddir, $dver, $dfam, $dtype, $dsuf, $dupd);
177}
178
179=item B<pb_distro_init>
180
181This 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.
182
183As an example, Ubuntu and Debian are in the same "du" family. As well as RedHat, RHEL, CentOS, fedora are on the same "rh" family.
184Mandriva, Open SuSE and Fedora have all the same "rpm" type of build system. Ubuntu ad Debian have the same "deb" type of build system.
185And "fc" is the extension generated for all Fedora packages (Version will be added by pb).
186
187When 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.
188
189Cf: http://linuxmafia.com/faq/Admin/release-files.html
190Ideas taken from http://search.cpan.org/~kerberus/Linux-Distribution-0.14/lib/Linux/Distribution.pm
191
192=cut
193
194sub pb_distro_get {
195
196my $base="/etc";
197
198# List of files that unambiguously indicates what distro we have
199my %single_rel_files = (
200# Tested
201 'gentoo' => 'gentoo-release', # >= 1.6
202 'slackware' => 'slackware-version', # >= 10.2
203 'mandriva' => 'mandriva-release', # >=2006.0
204 'mandrakelinux' => 'mandrakelinux-release',# = 10.2
205 'fedora' => 'fedora-release', # >= 4
206 'vmware' => 'vmware-release', # >= 3
207 'sles' => 'sles-release', # Doesn't exist as of 10
208 'asianux' => 'asianux-release', # >= 2.2
209# Untested
210 'knoppix' => 'knoppix_version', #
211 'yellowdog' => 'yellowdog-release', #
212 'esmith' => 'e-smith-release', #
213 'turbolinux' => 'turbolinux-release', #
214 'blackcat' => 'blackcat-release', #
215 'aurox' => 'aurox-release', #
216 'annvix' => 'annvix-release', #
217 'cobalt' => 'cobalt-release', #
218 'redflag' => 'redflag-release', #
219 'ark' => 'ark-release', #
220 'pld' => 'pld-release', #
221 'nld' => 'nld-release', #
222 'lfs' => 'lfs-release', #
223 'mk' => 'mk-release', #
224 'conectiva' => 'conectiva-release', #
225 'immunix' => 'immunix-release', #
226 'tinysofa' => 'tinysofa-release', #
227 'trustix' => 'trustix-release', #
228 'adamantix' => 'adamantix_version', #
229 'yoper' => 'yoper-release', #
230 'arch' => 'arch-release', #
231 'libranet' => 'libranet_version', #
232 'valinux' => 'va-release', #
233 'yellowdog' => 'yellowdog-release', #
234 'ultrapenguin' => 'ultrapenguin-release', #
235 );
236
237# List of files that ambiguously indicates what distro we have
238my %ambiguous_rel_files = (
239 'mandrake' => 'mandrake-release', # <= 10.1
240 'debian' => 'debian_version', # >= 3.1
241 'suse' => 'SuSE-release', # >= 10.0
242 'redhat' => 'redhat-release', # >= 7.3
243 'lsb' => 'lsb-release', # ???
244 );
245
246# Should have the same keys as the previous one.
247# If ambiguity, which other distributions should be checked
248my %distro_similar = (
249 'mandrake' => ['mandrake', 'mandrakelinux'],
250 'debian' => ['debian', 'ubuntu'],
251 'suse' => ['suse', 'sles', 'opensuse'],
252 'redhat' => ['redhat', 'rhel', 'centos', 'mandrake', 'vmware'],
253 'lsb' => ['ubuntu', 'lsb'],
254 );
255
256my %distro_match = (
257# Tested
258 'gentoo' => '.* version (.+)',
259 'slackware' => 'S[^ ]* (.+)$',
260# There should be no ambiguity between potential ambiguous distro
261 'mandrakelinux' => 'Mandrakelinux release (.+) \(',
262 'mandrake' => 'Mandr[^ ]* release (.+) \(',
263 'mandriva' => 'Mandr[^ ]* [^ ]* release (.+) \(',
264 'fedora' => 'Fedora .*release (\d+) \(',
265 'vmware' => 'VMware ESX Server (\d+) \(',
266 'rhel' => 'Red Hat (?:Enterprise Linux|Linux Advanced Server) .*release ([0-9.]+).* \(',
267 'centos' => '.*CentOS .*release ([0-9]).* ',
268 'redhat' => 'Red Hat Linux release (.+) \(',
269 'sles' => 'SUSE .* Enterprise Server (\d+) \(',
270 'suse' => 'SUSE LINUX (\d.+) \(',
271 'opensuse' => 'openSUSE (\d.+) \(',
272 'asianux' => 'Asianux (?:Server|release) ([0-9]).* \(',
273 'lsb' => '.*[^Ubunt].*\nDISTRIB_RELEASE=(.+)',
274# Ubuntu includes a /etc/debian_version file that creates an ambiguity with debian
275# So we need to look at distros in reverse alphabetic order to treat ubuntu always first
276 'ubuntu' => '.*Ubuntu.*\nDISTRIB_RELEASE=(.+)',
277 'debian' => '(.+)',
278# Not tested
279 'arch' => '.* ([0-9.]+) .*',
280 'redflag' => 'Red Flag (?:Desktop|Linux) (?:release |\()(.*?)(?: \(.+)?\)',
281);
282
283my $release;
284my $distro;
285
286# Begin to test presence of non-ambiguous files
287# that way we reduce the choice
288my ($d,$r);
289while (($d,$r) = each %single_rel_files) {
290 if (-f "$base/$r" && ! -l "$base/$r") {
291 my $tmp=pb_get_content("$base/$r");
292 # Found the only possibility.
293 # Try to get version and return
294 if (defined ($distro_match{$d})) {
295 ($release) = $tmp =~ m/$distro_match{$d}/m;
296 } else {
297 print STDERR "Unable to find $d version in $r\n";
298 print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
299 $release = "unknown";
300 }
301 return($d,$release);
302 }
303}
304
305# Now look at ambiguous files
306# Ubuntu includes a /etc/debian_version file that creates an ambiguity with debian
307# So we need to look at distros in reverse alphabetic order to treat ubuntu always first via lsb
308foreach $d (reverse keys %ambiguous_rel_files) {
309 $r = $ambiguous_rel_files{$d};
310 if (-f "$base/$r" && !-l "$base/$r") {
311 # Found one possibility.
312 # Get all distros concerned by that file
313 my $tmp=pb_get_content("$base/$r");
314 my $found = 0;
315 my $ptr = $distro_similar{$d};
316 pb_log(2,"amb: ".Dumper($ptr)."\n");
317 $release = "unknown";
318 foreach my $dd (@$ptr) {
319 pb_log(2,"check $dd\n");
320 # Try to check pattern
321 if (defined $distro_match{$dd}) {
322 pb_log(2,"cmp: $distro_match{$dd} - vs - $tmp\n");
323 ($release) = $tmp =~ m/$distro_match{$dd}/m;
324 if ((defined $release) && ($release ne "unknown")) {
325 $distro = $dd;
326 $found = 1;
327 last;
328 }
329 }
330 }
331 if ($found == 0) {
332 print STDERR "Unable to find $d version in $r\n";
333 print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
334 $release = "unknown";
335 } else {
336 return($distro,$release);
337 }
338 }
339}
340return("unknown","unknown");
341}
342
343
344=over 4
345
346=item B<pb_distro_installdeps>
347
348This function install the dependencies required to build the package on an RPM based distro
349dependencies can be passed as a prameter in which case they are not computed
350
351=cut
352
353sub pb_distro_installdeps {
354
355# SPEC file
356my $f = shift || undef;
357my $dtype = shift || undef;
358my $dupd = shift || undef;
359my $deps = shift || undef;
360
361# Protection
362return if (not defined $dupd);
363
364# Get dependecies in the build file if not forced
365$deps = pb_distro_getdeps("$f", $dtype) if (not defined $deps);
366pb_log(2,"deps: $deps\n");
367return if ((not defined $deps) || ($deps =~ /^\s*$/));
368if ($deps !~ /^[ ]*$/) {
369 pb_system("$dupd $deps","Installing dependencies ($deps)");
370 }
371}
372
373=over 4
374
375=item B<pb_distro_getdeps>
376
377This function computes the dependencies indicated in the build file and return them as a string of packages to install
378
379=cut
380
381sub pb_distro_getdeps {
382
383my $f = shift || undef;
384my $dtype = shift || undef;
385
386my $regexp = "";
387my $deps = "";
388my $sep = $/;
389
390pb_log(3,"entering pb_distro_getdeps: $dtype - $f\n");
391# Protection
392return("") if (not defined $dtype);
393if ($dtype eq "rpm") {
394 # In RPM this could include files, but we do not handle them atm.
395 $regexp = '^BuildRequires:(.*)$';
396} elsif ($dtype eq "deb") {
397 $regexp = '^Build-Depends:(.*)$';
398} elsif ($dtype eq "ebuild") {
399 $sep = '"'.$/;
400 $regexp = '^DEPEND="(.*)"\n'
401} else {
402 # No idea
403 return("");
404}
405pb_log(2,"regexp: $regexp\n");
406
407
408# Protection
409return("") if (not defined $f);
410
411# Preserve separator before using the one we need
412my $oldsep = $/;
413$/ = $sep;
414open(DESC,"$f") || die "Unable to open $f";
415while (<DESC>) {
416 pb_log(4,"read: $_\n");
417 next if (! /$regexp/);
418 chomp();
419 # What we found with the regexp is the list of deps.
420 pb_log(2,"found deps: $_\n");
421 s/$regexp/$1/i;
422 # Remove conditions in the middle and at the end for deb
423 s/\(\s*[><=]+.*\)\s*,/,/g;
424 s/\(\s*[><=]+.*$//g;
425 # Same for rpm
426 s/[><=]+.*,/,/g;
427 s/[><=]+.*$//g;
428 # Improve string format (remove , and spaces at start, end and in double
429 s/,/ /g;
430 s/^\s*//;
431 s/\s*$//;
432 s/\s+/ /g;
433 $deps .= " ".$_;
434}
435close(DESC);
436$/ = $oldsep;
437pb_log(2,"now deps: $deps\n");
438my $deps2 = pb_distro_only_deps_needed($dtype,$deps);
439return($deps2);
440}
441
442
443=over 4
444
445=item B<pb_distro_only_deps_needed>
446
447This function returns only the dependencies not yet installed
448
449=cut
450
451sub pb_distro_only_deps_needed {
452
453my $dtype = shift || undef;
454my $deps = shift || undef;
455
456return("") if ((not defined $deps) || ($deps =~ /^\s*$/));
457my $deps2 = "";
458# Avoid to install what is already there
459foreach my $p (split(/ /,$deps)) {
460 if ($dtype eq "rpm") {
461 my $res = pb_system("rpm -q --whatprovides --quiet $p","","quiet");
462 next if ($res eq 0);
463 } elsif ($dtype eq "deb") {
464 my $res = pb_system("dpkg -L $p","","quiet");
465 next if ($res eq 0);
466 } elsif ($dtype eq "ebuild") {
467 } else {
468 # Not reached
469 }
470 pb_log(2,"found deps2: $p\n");
471 $deps2 .= " $p";
472}
473
474$deps2 =~ s/^\s*//;
475pb_log(2,"now deps2: $deps2\n");
476return($deps2);
477}
478
479=over 4
480
481=item B<pb_distro_setuprepo>
482
483This function sets up potential additional repository to the build environment
484
485=cut
486
487sub pb_distro_setuprepo {
488
489my $ddir = shift || undef;
490my $dver = shift;
491my $darch = shift;
492my $dtype = shift || undef;
493
494my ($addrepo) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","addrepo");
495return if (not defined $addrepo);
496
497my $param = pb_distro_get_param($ddir,$dver,$darch,$addrepo);
498return if ($param eq "");
499
500# Loop on the list of additional repo
501foreach my $i (split(/,/,$param)) {
502
503 my ($scheme, $account, $host, $port, $path) = pb_get_uri($i);
504 my $bn = basename($i);
505
506 # The repo file can be local or remote. download or copy at the right place
507 if (($scheme eq "ftp") || ($scheme eq "http")) {
508 pb_system("wget -O $ENV{'PBTMP'}/$bn $i","Donwloading additional repository file $i");
509 } else {
510 copy($i,$ENV{'PBTMP'}/$bn);
511 }
512
513 # The repo file can be a real file or a package
514 if ($dtype eq "rpm") {
515 if ($bn =~ /\.rpm$/) {
516 pb_system("sudo rpm -Uvh $ENV{'PBTMP'}/$bn","Adding package to setup repostory");
517 } elsif ($bn =~ /\.repo$/) {
518 # Yum repo
519 pb_system("sudo mv $ENV{'PBTMP'}/$bn /etc/yum.repo.d","Adding yum repository");
520 } elsif ($bn =~ /\.addmedia/) {
521 # URPMI repo
522 pb_system("chmod 755 $ENV{'PBTMP'}/$bn ; sudo $ENV{'PBTMP'}/$bn 2>&1 > /dev/null","Adding urpmi repository");
523 } else {
524 pb_log(0,"Unable to deal with repository file $i on rpm distro ! Please report to dev team\n");
525 }
526 } elsif ($dtype eq "deb") {
527 if ($bn =~ /\.sources.list$/) {
528 pb_system("sudo mv $ENV{'PBTMP'}/$bn /etc/apt/sources.list.d","Adding apt repository");
529 pb_system("sudo apt-get update","Updating apt repository");
530 } else {
531 pb_log(0,"Unable to deal with repository file $i on deb distro ! Please report to dev team\n");
532 }
533 } else {
534 pb_log(0,"Unable to deal with repository file $i on that distro ! Please report to dev team\n");
535 }
536}
537return;
538}
539
540=over 4
541
542=item B<pb_distro_get_param>
543
544This function gets the parameter in the conf file from the most precise tuple up to default
545
546=cut
547
548sub pb_distro_get_param {
549
550my $param = "";
551my $ddir = shift;
552my $dver = shift;
553my $darch = shift;
554my $opt = shift;
555
556if (defined $opt->{"$ddir-$dver-$darch"}) {
557 $param = $opt->{"$ddir-$dver-$darch"};
558} elsif (defined $opt->{"$ddir-$dver"}) {
559 $param = $opt->{"$ddir-$dver"};
560} elsif (defined $opt->{"$ddir"}) {
561 $param = $opt->{"$ddir"};
562} elsif (defined $opt->{"default"}) {
563 $param = $opt->{"default"};
564} else {
565 $param = "";
566}
567return($param);
568
569}
570=back
571
572=head1 WEB SITES
573
574The 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/>.
575
576=head1 USER MAILING LIST
577
578None exists for the moment.
579
580=head1 AUTHORS
581
582The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
583
584=head1 COPYRIGHT
585
586Project-Builder.org is distributed under the GPL v2.0 license
587described in the file C<COPYING> included with the distribution.
588
589=cut
590
591
5921;
Note: See TracBrowser for help on using the repository browser.