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

Last change on this file was 2638, checked in by Bruno Cornec, 4 years ago

Another fix for #187 now tested in a VE

File size: 33.1 KB
RevLine 
[11]1#!/usr/bin/perl -w
[2]2#
[11]3# Creates common environment for distributions
[2]4#
[2488]5# Copyright B. Cornec 2007-today
[1528]6# Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard
7# Provided under the GPL v2
8#
[2]9# $Id$
10#
11
[329]12package ProjectBuilder::Distribution;
13
[11]14use strict;
[423]15use Data::Dumper;
[2362]16use Carp qw/cluck confess/;
[1148]17use ProjectBuilder::Version;
[395]18use ProjectBuilder::Base;
[702]19use ProjectBuilder::Conf;
20use File::Basename;
21use File::Copy;
[1507]22# requires perl 5.004 minimum in VM/VE
23use File::Compare;
[2]24
[1148]25# Global vars
[329]26# Inherit from the "Exporter" module which handles exporting functions.
27
[2499]28use vars qw(@ISA @EXPORT);
[329]29use Exporter;
30
31# Export, by default, all the functions into the namespace of
32# any code which uses this module.
33
34our @ISA = qw(Exporter);
[2488]35our @EXPORT = qw(pb_distro_init pb_distro_conffile pb_distro_sysconffile pb_distro_api pb_distro_get pb_distro_get_if pb_distro_getlsb pb_distro_installdeps pb_distro_installpkgs pb_distro_getdeps pb_distro_only_deps_needed pb_distro_setuprepo pb_distro_setuposrepo pb_distro_setuprepo_gen pb_distro_get_context pb_distro_to_keylist pb_distro_conf_print pb_apply_conf_proxy);
[2499]36our ($VERSION,$REVISION,$PBCONFVER) = pb_version_init();
[329]37
[391]38=pod
39
40=head1 NAME
41
42ProjectBuilder::Distribution, part of the project-builder.org - module dealing with distribution detection
43
44=head1 DESCRIPTION
45
46This modules provides functions to allow detection of Linux distributions, and giving back some attributes concerning them.
47
48=head1 SYNOPSIS
49
50 use ProjectBuilder::Distribution;
51
52 #
53 # Return information on the running distro
54 #
[1177]55 my $pbos = pb_distro_get_context();
56 print "distro tuple: ".Dumper($pbos->name, $pbos->ver, $pbos->fam, $pbos->type, $pbos->pbsuf, $pbos->pbupd, $pbos->pbins, $pbos->arch)."\n";
[391]57 #
58 # Return information on the requested distro
59 #
[1177]60 my $pbos = pb_distro_get_context("ubuntu-7.10-x86_64");
61 print "distro tuple: ".Dumper($pbos->name, $pbos->ver, $pbos->fam, $pbos->type, $pbos->pbsuf, $pbos->pbupd, $pbos->pbins, $pbos->arch)."\n";
[391]62 #
63 # Return information on the running distro
64 #
[2488]65 my ($ddir,$dver) = pb_distro_guess();
[391]66
67=head1 USAGE
68
69=over 4
70
[2426]71=item B<pb_distro_api>
[891]72
[2426]73This function returns the mandatory configuration file used for api
[891]74
75=cut
76
[2338]77sub pb_distro_api {
78
[2632]79return("CCCC/api.yaml");
[2338]80}
81
82
83=item B<pb_distro_conffile>
84
85This function returns the mandatory configuration file used for distribution/OS detection
86
87=cut
88
[891]89sub pb_distro_conffile {
90
[2279]91if ($PBCONFVER < 1) {
92 return("CCCC/pb.conf");
93} else {
94 return("CCCC/pb.yml");
[891]95}
[2279]96}
[891]97
[2136]98=item B<pb_distro_sysconffile>
[891]99
[2136]100This function returns the optional configuration file used for local customization
101
102=cut
103
104sub pb_distro_sysconffile {
105
[2279]106if ($PBCONFVER < 1) {
107 return("SSSS/pb.conf");
108} else {
109 return("SSSS/pb.yml");
[2136]110}
[2279]111}
[2136]112
113
[756]114=item B<pb_distro_init>
[395]115
[1177]116This function returns a hash of parameters indicating the distribution name, version, family, type of build system, suffix of packages, update command line, installation command line and architecture of the underlying Linux distribution. The value of the fields may be "unknown" in case the function was unable to recognize on which distribution it is running.
[391]117
[756]118As an example, Ubuntu and Debian are in the same "du" family. As well as RedHat, RHEL, CentOS, fedora are on the same "rh" family.
[1177]119Mandriva, Open SuSE and Fedora have all the same "rpm" type of build system. Ubuntu and Debian have the same "deb" type of build system.
[756]120And "fc" is the extension generated for all Fedora packages (Version will be added by pb).
[2289]121All this information is stored in an external configuration file typically at /etc/pb/pb.yml
[391]122
[756]123When 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.
[391]124
[756]125Cf: http://linuxmafia.com/faq/Admin/release-files.html
126Ideas taken from http://search.cpan.org/~kerberus/Linux-Distribution-0.14/lib/Linux/Distribution.pm
127
[391]128=cut
129
[756]130
[74]131sub pb_distro_init {
[2]132
[1177]133my $pbos = {
134 'name' => undef,
135 'version' => undef,
136 'arch' => undef,
137 'family' => "unknown",
138 'suffix' => "unknown",
139 'update' => "unknown",
140 'install' => "unknown",
141 'type' => "unknown",
142 'os' => "unknown",
143 'nover' => "false",
144 'rmdot' => "false",
[1540]145 'useminor' => "false",
[1177]146 };
147$pbos->{'name'} = shift;
148$pbos->{'version'} = shift;
149$pbos->{'arch'} = shift;
[2]150
[869]151# Adds conf file for distribution description
152# the location of the conf file is finalyzed at install time
153# depending whether we deal with package install or tar file install
154
[2136]155pb_conf_add(pb_distro_sysconffile());
156
[2152]157# Similarly for the local file available for sysadmin. After the previous one to allow overwrite to work
158pb_conf_add(pb_distro_conffile());
159
[11]160# If we don't know which distribution we're on, then guess it
[2488]161($pbos->{'name'},$pbos->{'version'}) = pb_distro_guess() if ((not defined $pbos->{'name'}) || (not defined $pbos->{'version'}));
[2]162
[1159]163# For some rare cases, typically nover ones
[1177]164$pbos->{'name'} = "unknown" if (not defined $pbos->{'name'});
165$pbos->{'version'} = "unknown" if (not defined $pbos->{'version'});
[1159]166
[757]167# Initialize arch
[1177]168$pbos->{'arch'} = pb_get_arch() if (not defined $pbos->{'arch'});
[1652]169# Solves a bug on Red Hat 6.x where real arch is not detected when using setarch and a chroot
170# As it was only i386 forcing it here.
171$pbos->{'arch'} = "i386" if (($pbos->{'name'} eq "redhat") && ($pbos->{'version'} =~ /^6\./));
[757]172
[969]173# Dig into the tuple to find the best answer
[1177]174# Do NOT factorize here, as it won't work as of now for hash creation
[1530]175# Do NOT change order without caution
[2488]176$pbos->{'useminor'} = pb_distro_get($pbos,"osuseminorrel");
177$pbos->{'family'} = pb_distro_get($pbos,"osfamily");
178$pbos->{'type'} = pb_distro_get($pbos,"ostype");
[2490]179($pbos->{'os'},$pbos->{'install'},$pbos->{'update'}) = pb_distro_get($pbos,("os","osins","osupd"));
180($pbos->{'localinstall'},$pbos->{'nover'},$pbos->{'rmdot'},$pbos->{'suffix'}) = pb_distro_get_if($pbos,"oslocalins","osnover","osremovedotinver","ossuffix");
[867]181
182# Some OS have no interesting version
[1177]183$pbos->{'version'} = "nover" if ((defined $pbos->{'nover'}) && ($pbos->{'nover'} eq "true"));
[867]184
[1167]185# For some OS remove the . in version name for extension
[1177]186my $dver2 = $pbos->{'version'};
187$dver2 =~ s/\.//g if ((defined $pbos->{'rmdot'}) && ($pbos->{'rmdot'} eq "true"));
[867]188
[1177]189if ((not defined $pbos->{'suffix'}) || ($pbos->{'suffix'} eq "")) {
190 # By default suffix is a concatenation of name and version
191 $pbos->{'suffix'} = ".$pbos->{'name'}$dver2"
[11]192} else {
[867]193 # concat just the version to what has been found
[1177]194 $pbos->{'suffix'} = ".$pbos->{'suffix'}$dver2";
[11]195}
196
[867]197# if ($arch eq "x86_64") {
198# $opt="--exclude=*.i?86";
199# }
[1177]200pb_log(2,"DEBUG: pb_distro_init: ".Dumper($pbos)."\n");
[867]201
[1177]202return($pbos);
[11]203}
[23]204
[2488]205=item B<pb_distro_guess>
[395]206
[756]207This 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.
[395]208
[1156]209On my home machine it would currently report ("mandriva","2010.2").
[395]210
211=cut
212
[2488]213sub pb_distro_guess {
[23]214
[869]215# 1: List of files that unambiguously indicates what distro we have
216# 2: List of files that ambiguously indicates what distro we have
217# 3: Should have the same keys as the previous one. If ambiguity, which other distributions should be checked
218# 4: Matching Rg. Expr to detect distribution and version
[2333]219my ($single_rel_files, $ambiguous_rel_files,$distro_similar,$distro_match,$nover) = pb_conf_get("osrelfile","osrelambfile","osambiguous","osrelexpr","osnover");
[23]220
221my $release;
222my $distro;
223
[391]224# Begin to test presence of non-ambiguous files
[23]225# that way we reduce the choice
[24]226my ($d,$r);
[869]227while (($d,$r) = each %$single_rel_files) {
[1027]228 if (defined $ambiguous_rel_files->{$d}) {
[2362]229 print STDERR "The key $d is considered as both unambiguous and ambiguous.\n";
[2361]230 confess "Please fix your configuration file.\n"
[1027]231 }
[869]232 if (-f "$r" && ! -l "$r") {
233 my $tmp=pb_get_content("$r");
[23]234 # Found the only possibility.
235 # Try to get version and return
[869]236 if (defined ($distro_match->{$d})) {
237 ($release) = $tmp =~ m/$distro_match->{$d}/m;
[23]238 } else {
[2333]239 if (not defined ($nover->{$d})) {
240 print STDERR "Unable to find $d version in $r (non-ambiguous)\n";
[2361]241 confess "Please report to the maintainer bruno_at_project-builder.org\n";
[2333]242 }
[23]243 $release = "unknown";
244 }
245 return($d,$release);
246 }
247}
248
[423]249# Now look at ambiguous files
[1027]250# Ubuntu before 10.04 includes a /etc/debian_version file that creates an ambiguity with debian
[423]251# So we need to look at distros in reverse alphabetic order to treat ubuntu always first via lsb
[1969]252my $found = 0;
[869]253foreach $d (reverse keys %$ambiguous_rel_files) {
254 $r = $ambiguous_rel_files->{$d};
255 if (-f "$r" && !-l "$r") {
[23]256 # Found one possibility.
257 # Get all distros concerned by that file
[2360]258 my $tmp = pb_get_content("$r");
[869]259 my $ptr = $distro_similar->{$d};
[423]260 pb_log(2,"amb: ".Dumper($ptr)."\n");
[24]261 $release = "unknown";
[869]262 foreach my $dd (split(/,/,$ptr)) {
[423]263 pb_log(2,"check $dd\n");
[23]264 # Try to check pattern
[869]265 if (defined $distro_match->{$dd}) {
266 pb_log(2,"cmp: $distro_match->{$dd} - vs - $tmp\n");
267 ($release) = $tmp =~ m/$distro_match->{$dd}/m;
[24]268 if ((defined $release) && ($release ne "unknown")) {
269 $distro = $dd;
270 $found = 1;
271 last;
272 }
[23]273 }
274 }
[1969]275 last if ($found == 1);
[23]276 }
277}
[2394]278if ($found == 0) {
279 #
280 # Now look at the os-release file to see if we have a std distribution description
281 #
282 foreach my $r ("/usr/lib/os-release","/etc/os-release") {
283 if (-r $r) {
284 my $tmp = pb_get_content("$r");
285 ($release) = $tmp =~ m/.*\nVERSION_ID=[\"\']*([0-9a-z\._-]+)[\"\']*\n/m;
286 ($distro) = $tmp =~ m/.*\nID=[\"\']*([0-9A-z\._-]+)[\"\']*\n/m;
287 # Remove the leap suffix if present (OpenSUSE)
288 $distro =~ s/-leap//;
289 if ((defined $release) && (defined $distro)) {
290 $found = 1;
291 last;
292 }
[2390]293 }
294 }
[2360]295}
[1969]296if ($found == 0) {
297 print STDERR "Unable to find a version in ".join(' ',keys %$ambiguous_rel_files)." (ambiguous)\n";
[2360]298 confess "Please report to the maintainer bruno_at_project-builder.org\n";
[1969]299} else {
300 return($distro,$release);
[24]301}
[1969]302}
[23]303
[1071]304=item B<pb_distro_getlsb>
[621]305
[1071]306This function returns the 5 lsb values LSB version, distribution ID, Description, release and codename.
307As entry it takes an optional parameter to specify whether the output is short or not.
308
309=cut
310
311sub pb_distro_getlsb {
312
313my $s = shift;
314pb_log(3,"Entering pb_distro_getlsb\n");
315
316my ($ambiguous_rel_files) = pb_conf_get("osrelambfile");
317my $lsbf = $ambiguous_rel_files->{"lsb"};
318
319# LSB has not been configured.
320if (not defined $lsbf) {
321 print STDERR "no lsb entry defined for osrelambfile\n";
[1678]322 confess "You modified upstream delivery and lost !\n";
[1071]323}
324
325if (-r $lsbf) {
326 my $rep = pb_get_content($lsbf);
327 # Create elementary fields
328 my ($c, $r, $d, $i, $l) = ("", "", "", "", "");
329 for my $f (split(/\n/,$rep)) {
330 pb_log(3,"Reading file part ***$f***\n");
331 $c = $f if ($f =~ /^DISTRIB_CODENAME/);
332 $c =~ s/DISTRIB_CODENAME=/Codename:\t/;
333 $r = $f if ($f =~ /^DISTRIB_RELEASE/);
334 $r =~ s/DISTRIB_RELEASE=/Release:\t/;
335 $d = $f if ($f =~ /^DISTRIB_DESCRIPTION/);
336 $d =~ s/DISTRIB_DESCRIPTION=/Description:\t/;
337 $d =~ s/"//g;
338 $i = $f if ($f =~ /^DISTRIB_ID/);
339 $i =~ s/DISTRIB_ID=/Distributor ID:\t/;
340 $l = $f if ($f =~ /^LSB_VERSION/);
341 $l =~ s/LSB_VERSION=/LSB Version:\t/;
342 }
[1177]343 my $regexp = "^[A-z ]*:[\t ]*";
344 $c =~ s/$regexp// if (defined $s);
345 $r =~ s/$regexp// if (defined $s);
346 $d =~ s/$regexp// if (defined $s);
347 $i =~ s/$regexp// if (defined $s);
348 $l =~ s/$regexp// if (defined $s);
[1071]349 return($l, $i, $d, $r, $c);
350} else {
351 print STDERR "Unable to read $lsbf file\n";
[1678]352 confess "Please report to the maintainer bruno_at_project-builder.org\n";
[1071]353}
354}
355
[1517]356# Internal function
357
[1713]358sub pb_apply_conf_proxy {
[1517]359my ($pbos) = @_;
360
[2488]361my $ftp_proxy = pb_distro_get_if($pbos,"ftp_proxy");
362my $http_proxy = pb_distro_get_if($pbos,"http_proxy");
363my $https_proxy = pb_distro_get_if($pbos,"https_proxy");
[1517]364
365# We do not overwrite shell settings
[2287]366$ENV{'ftp_proxy'} ||= $ftp_proxy if ((defined $ftp_proxy) && ($ftp_proxy ne ""));
367$ENV{'http_proxy'} ||= $http_proxy if ((defined $http_proxy) && ($http_proxy ne ""));
368$ENV{'https_proxy'} ||= $https_proxy if ((defined $https_proxy) && ($https_proxy ne ""));
[1517]369}
370
[2427]371=item B<pb_distro_installpkgs>
372
373This function install the packages passed as parameters on a distribution.
374
375=cut
376
377sub pb_distro_installpkgs {
378
379my $pbos = shift;
380my $pkgs = shift; # list of pkgs to install
381my $local = shift; # optional should we install local packages or remote (for deb command is different)
382
383# Protection
384confess "Missing install command for $pbos->{name}-$pbos->{version}-$pbos->{arch}" unless (defined $pbos->{install} && $pbos->{install} =~ /\w/);
385pb_apply_conf_proxy($pbos);
386pb_log(1, "ftp_proxy=$ENV{'ftp_proxy'}\n") if (defined $ENV{'ftp_proxy'});
387pb_log(1, "http_proxy=$ENV{'http_proxy'}\n") if (defined $ENV{'http_proxy'});
388pb_log(1, "https_proxy=$ENV{'https_proxy'}\n") if (defined $ENV{'https_proxy'});
389
[2638]390my $npkgs = "";
391foreach my $p (split(/ /,$pkgs)) {
392 $npkgs .= "'".$p."' "
393 }
394
[2427]395# This may not be // proof. We should test for availability of repo and sleep if not
[2638]396my $cmd = "$pbos->{'install'} $npkgs";
397$cmd = "$pbos->{'localinstall'} $npkgs" if ((defined $local) && (defined $pbos->{'localinstall'}) && ($pbos->{'localinstall'} !~ /[ ]*/));
[2427]398my $ret = pb_system($cmd, "Installing packages ($cmd)","mayfail");
399# Try to accomodate deficient proxies
400if ($ret != 0) {
401 $ret = pb_system($cmd, "Re-trying installing packages ($cmd)");
402}
403confess "Some packages did not install" if (($ret != 0) && ($Global::pb_stop_on_error));
404}
405
406
[621]407=item B<pb_distro_installdeps>
408
[1177]409This function install the dependencies required to build the package on a distro.
[2189]410If $forcerepo is defined then do not assume packages are alredy installed, but reinstall them
[2182]411(useful if you add a repo which contains more up to date packages that you need)
412Dependencies can be passed as the 4th parameter in which case they are not computed
[621]413
414=cut
415
416sub pb_distro_installdeps {
417
418# SPEC file
[1907]419my $f = shift;
[1177]420my $pbos = shift;
[2182]421my $forcerepo = shift;
422my $deps = shift; # optional list of deps to install
[2324]423my $local = shift; # optional should we install local packages or remote (for deb command is different)
[2499]424my $deps2;
[621]425
[2499]426if (not defined $deps) {
427 $deps = pb_distro_getdeps($f,$pbos, $forcerepo);
428}
[2503]429pb_log(2,"DEBUG: Packages to install: $deps\n") if (defined $deps);
430return if ((not defined $deps) || ($deps =~ /^\s*$/));
[1505]431
[2427]432pb_distro_installpkgs($pbos,$deps,$local);
[1517]433# Check that all deps have been installed correctly
[2217]434# This time we don't forcerepo to avoid getting a list as a return as we have
435# already forced it previously, and this time we just want to check
436$deps = pb_distro_getdeps($f, $pbos, undef);
[1879]437confess "Some dependencies did not install ($deps)" if ((defined $deps) && ($deps =~ /\S/) && ($Global::pb_stop_on_error));
[1515]438}
[621]439
440=item B<pb_distro_getdeps>
441
442This function computes the dependencies indicated in the build file and return them as a string of packages to install
443
444=cut
445
446sub pb_distro_getdeps {
447
[1907]448my $f = shift;
[1177]449my $pbos = shift;
[2182]450my $forcerepo = shift;
[621]451
452my $regexp = "";
453my $deps = "";
454my $sep = $/;
455
456# Protection
[1177]457return("") if (not defined $pbos->{'type'});
[899]458return("") if (not defined $f);
459
[1177]460pb_log(3,"entering pb_distro_getdeps: $pbos->{'type'} - $f\n");
461if ($pbos->{'type'} eq "rpm") {
[621]462 # In RPM this could include files, but we do not handle them atm.
463 $regexp = '^BuildRequires:(.*)$';
[1177]464} elsif ($pbos->{'type'} eq "deb") {
[621]465 $regexp = '^Build-Depends:(.*)$';
[2632]466} elsif ($pbos->{'type'} eq "aur") {
467 $regexp = '^makedepends=(.*)$';
[2333]468} elsif ($pbos->{'type'} eq "apk") {
[2334]469 $regexp = '^makedepends=(.*)$';
[1177]470} elsif ($pbos->{'type'} eq "ebuild") {
[621]471 $sep = '"'.$/;
[2333]472 $regexp = '^DEPEND="(.*)"\n';
[621]473} else {
474 # No idea
[622]475 return("");
[621]476}
477pb_log(2,"regexp: $regexp\n");
478
479# Preserve separator before using the one we need
480my $oldsep = $/;
481$/ = $sep;
[2434]482open(DESC,"$f") || (cluck "Unable to open $f" && return(""));
[621]483while (<DESC>) {
484 pb_log(4,"read: $_\n");
485 next if (! /$regexp/);
486 chomp();
[1514]487
488 my $nextline;
489 # Support multi-lines deps for .deb
490 if ($pbos->{type} eq 'deb') {
491 while ($nextline = <DESC>) {
492 last unless $nextline =~ /^\s+(.+)$/o;
493 $_ .= $1;
494 }
495 }
496
[621]497 # What we found with the regexp is the list of deps.
498 pb_log(2,"found deps: $_\n");
[681]499 s/$regexp/$1/i;
[1972]500 pb_log(4,"found deps 1: $_\n");
[698]501 # Remove conditions in the middle and at the end for deb
[2189]502 s/\([><=]+[^,]*,/,/g;
[1972]503 pb_log(4,"found deps 2: $_\n");
[2189]504 s/\([><=]+[^,]*$//g;
[1972]505 pb_log(4,"found deps 3: $_\n");
[698]506 # Same for rpm
[931]507 s/[><=]+[^,]*,/,/g;
[1972]508 pb_log(4,"found deps 4: $_\n");
[652]509 s/[><=]+.*$//g;
[1972]510 pb_log(4,"found deps 5: $_\n");
[621]511 # Improve string format (remove , and spaces at start, end and in double
[652]512 s/,/ /g;
[1972]513 pb_log(4,"found deps 6: $_\n");
[621]514 s/^\s*//;
[1972]515 pb_log(4,"found deps 7: $_\n");
516 # $ here removes the \n
[621]517 s/\s*$//;
[1972]518 pb_log(4,"found deps 8: $_\n");
[621]519 s/\s+/ /g;
[1972]520 pb_log(4,"found deps 9: $_\n");
[621]521 $deps .= " ".$_;
[1972]522 pb_log(4,"found deps end: $deps\n");
[1514]523
524 # Support multi-lines deps for .deb (fwup)
525 if (defined $nextline) {
526 $_ = $nextline;
527 redo;
528 }
[621]529}
530close(DESC);
531$/ = $oldsep;
532pb_log(2,"now deps: $deps\n");
[2182]533if (defined $forcerepo) {
534 # We want to force installation of all pkgs
535 # because a repo was setup in between, which may contains updated versions
536 pb_log(0,"Forcing installation of all packages due to previous repo setup\n");
537 return($deps);
538} else {
539 pb_log(0,"Installation of only necessary packages\n");
540 my $deps2 = pb_distro_only_deps_needed($pbos,$deps);
541 return($deps2);
[622]542}
[2182]543}
[622]544
545
546=item B<pb_distro_only_deps_needed>
547
548This function returns only the dependencies not yet installed
549
550=cut
551
552sub pb_distro_only_deps_needed {
553
[1177]554my $pbos = shift;
[1907]555my $deps = shift;
[622]556
[623]557return("") if ((not defined $deps) || ($deps =~ /^\s*$/));
[621]558my $deps2 = "";
559# Avoid to install what is already there
[2287]560delete $ENV{'COLUMNS'};
[1505]561foreach my $p (split(/\s+/,$deps)) {
562 next if $p =~ /^\s*$/o;
[1177]563 if ($pbos->{'type'} eq "rpm") {
[1653]564 my $rpmcmd = "rpm -q --whatprovides --quiet";
565 # whatprovides doesn't work for RH6.2
566 $rpmcmd = "rpm -q --quiet" if (($pbos->{'name'} eq "redhat") && ($pbos->{'version'} =~ /6/));
[2636]567 my $res = pb_system("$rpmcmd '".$p."'","Looking for $p","mayfail");
[621]568 next if ($res eq 0);
[1524]569 pb_log(1, "INFO: missing dependency $p\n");
[1177]570 } elsif ($pbos->{'type'} eq "deb") {
[1597]571 my $res = pb_system("dpkg -L $p","Looking for $p","mayfail");
[621]572 next if ($res eq 0);
[2434]573 open(CMD,"dpkg -l $p |") || (cluck "Unable to run dpkg -l $p: $!" && next);
[1516]574 my $ok = 0;
575 while (<CMD>) {
576 $ok = 1 if /^ii\s+$p/;
577 }
[1530]578 close(CMD);
[1516]579 next if $ok;
[1524]580 pb_log(1, "INFO: missing dependency $p\n");
[1177]581 } elsif ($pbos->{'type'} eq "ebuild") {
[2334]582 } elsif ($pbos->{'type'} eq "apk") {
[2337]583 my $res = pb_system("apk -e info $p","Looking for $p","mayfail");
584 next if ($res eq 0);
[2334]585 pb_log(1, "INFO: missing dependency $p\n");
[621]586 } else {
587 # Not reached
588 }
589 $deps2 .= " $p";
590}
591
592$deps2 =~ s/^\s*//;
[2499]593pb_log(2,"List of missing packages: $deps2\n");
[621]594return($deps2);
595}
596
[2410]597# Internal
598sub pb_distro_compare_repo {
599
600my $src = shift;
601my $dest = shift;
602
603if (not -f $dest) {
604 pb_log(1, "INFO: Creating new file $dest\n");
605} elsif (-f $dest && -s $dest == 0) {
606 pb_log(1, "INFO: Overwriting empty file $dest\n");
607} elsif (-f $dest && compare("$src", $dest) == 0) {
608 pb_log(1, "INFO: Overwriting identical file $dest\n");
609} else {
610 pb_log(0, "ERROR: destination file $dest exists and is different than source $src\n");
611 pb_system("cat $dest","INFO: Dest...\n","verbose");
612 pb_system("cat $src","INFO: New...\n","verbose");
613 pb_log(1, "INFO: Returning...\n");
614 return(1);
615}
616return(0);
617}
618
619
[1132]620=item B<pb_distro_setuposrepo>
621
622This function sets up potential additional repository for the setup phase
623
624=cut
625
626sub pb_distro_setuposrepo {
627
[1177]628my $pbos = shift;
[1132]629
[2410]630pb_log(3, "INFO: Adding osrepo from config file\n");
[2426]631my %h;
632my $h = \%h;
633# Adds conf file for availability of conf elements either from the local build env or from a VE/VM/RM in which the conf file has been passed
634$h = pb_conf_cache(pb_distro_conffile(),$h);
[2488]635#my $repo = pb_distro_get_param($pbos,$osrepo);
636my $repo = pb_distro_get_in_hash_if($pbos,$h,"osrepo");
[2429]637return(pb_distro_setuprepo_gen($pbos,$repo));
[1132]638}
639
[702]640=item B<pb_distro_setuprepo>
641
[2426]642This function sets up potential additional repository to the build/install/test environment
[2465]643If done, it returns forcerepo if a repo was added, if not undef
[702]644
645=cut
646
647sub pb_distro_setuprepo {
648
[1177]649my $pbos = shift;
[2426]650my $repotype = shift;
[702]651
[2426]652my %h;
653my $h = \%h;
654# Adds conf file for availability of conf elements either from the local build env or from a VE/VM/RM in which the conf file has been passed
655$h = pb_conf_cache("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.yml",$h) if ((defined $ENV{'PBROOTDIR'}) && (-f "$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.yml"));
656$h = pb_conf_cache("$ENV{'PBDESTDIR'}/pbrc.yml",$h) if ((defined $ENV{'PBDESTDIR'}) && (-f "$ENV{'PBDESTDIR'}/pbrc.yml"));
[1132]657
[2488]658my $repo = pb_distro_get_in_hash_if($pbos,$h,"add".$repotype."repo");
[2465]659# If no repo then set it up as undef so the return value is correct from pb_distro_setuprepo_gen
[2490]660$repo = undef if ((defined $repo) && ($repo eq ""));
[2426]661if ($repotype =~ /install/) {
662 # Give a probable default if nothing is provided to avoid overloading conf files
663 #
[2488]664 if (not defined $repo) {
[2426]665 my ($pbrepo) = pb_conf_get_in_hash_if($h,"pbrepo");
[2465]666 if (not defined $pbrepo) {
667 cluck("No pbrepo parameter defined in your project configuration file, please fix !");
668 return(undef);
669 }
[2426]670 my $url = "$pbrepo->{$ENV{'PBPROJ'}}";
671 my ($testver,$delivery) = pb_conf_get_in_hash_if($h,"testver","delivery");
672 $delivery->{$ENV{'PBPROJ'}} = "" if (not defined $delivery->{$ENV{'PBPROJ'}});
673 $url .= "/$delivery->{$ENV{'PBPROJ'}}/";
674 my $repotag = "";
675 $repotag = "-$delivery->{$ENV{'PBPROJ'}}" if ($delivery->{$ENV{'PBPROJ'}} ne "");
676 $url .= "/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/$ENV{PBPROJ}$repotag.";
677 my $ext = "";
678 if ($pbos->{'type'} eq "rpm") {
679 $ext = "repo";
680 if ($pbos->{'family'} eq "md") {
681 $ext = "addmedia";
682 }
683 } elsif ($pbos->{'type'} eq "deb") {
684 $ext = ".sources.list";
685 }
[2462]686 $repo = $url.$ext;
[2426]687 }
[2187]688}
[2468]689pb_log(1, "INFO: Adding $repo from config file for $repotype step\n") if (defined $repo);
[2462]690return(pb_distro_setuprepo_gen($pbos,$repo));
[2426]691}
[2187]692
693=item B<pb_distro_setuprepo_gen>
694
[2465]695This functionthe sets up in a generic way potential additional repository passed as a param
696It returns forcerepo if one was added, else undef
[2187]697
698=cut
699
700sub pb_distro_setuprepo_gen {
701
702my $pbos = shift;
703my $param = shift;
704
[2427]705return(undef) if (not defined $param);
[2187]706
[1517]707pb_apply_conf_proxy($pbos);
708
[702]709# Loop on the list of additional repo
710foreach my $i (split(/,/,$param)) {
711
[2171]712 pb_log(1,"Adding repository defined by $i\n");
[702]713 my ($scheme, $account, $host, $port, $path) = pb_get_uri($i);
714 my $bn = basename($i);
715
716 # The repo file can be local or remote. download or copy at the right place
[2169]717 if (($scheme eq "ftp") || ($scheme =~ /http/)) {
[1507]718 pb_system("wget -O $ENV{'PBTMP'}/$bn $i","Downloading additional repository file $i");
[702]719 } else {
[1834]720 copy($i,"$ENV{'PBTMP'}/$bn");
[702]721 }
722
723 # The repo file can be a real file or a package
[1177]724 if ($pbos->{'type'} eq "rpm") {
[702]725 if ($bn =~ /\.rpm$/) {
[721]726 my $pn = $bn;
727 $pn =~ s/\.rpm//;
[1595]728 if (pb_system("rpm -q --quiet $pn","","mayfail") != 0) {
[2177]729 pb_system("sudo rpm -Uvh $ENV{'PBTMP'}/$bn","Adding package $bn to setup repository");
[721]730 }
731 } elsif ($bn =~ /\.repo$/) {
[1521]732 my $dirdest = "";
733 my $reponame = "";
[2289]734 # TODO: could go in pb.yml in fact
[1521]735 if ($pbos->{install} =~ /\byum\b/) {
736 $reponame="yum";
737 $dirdest = "/etc/yum.repos.d";
[2012]738 } elsif ($pbos->{install} =~ /\bdnf\b/) {
739 $reponame="dnf";
740 $dirdest = "/etc/yum.repos.d";
[1521]741 } elsif ($pbos->{install} =~ /\bzypper\b/) {
742 $reponame="zypper";
743 $dirdest = "/etc/zypp/repos.d";
744 } else {
[2362]745 cluck "Unknown location for repository file for '$pbos->{install}' command";
746 next;
[1521]747 }
748 my $dest = "$dirdest/$bn";
[2427]749 return(undef) if (pb_distro_compare_repo("$ENV{'PBTMP'}/$bn",$dest) == 1);
[2362]750 if (! -d $dirdest) {
751 cluck "Missing directory $dirdest ($reponame)";
[2427]752 return(undef);
[2362]753 }
[2171]754 pb_system("sudo mv $ENV{'PBTMP'}/$bn $dest","Adding $reponame repository") if (not -f "$dest");
[2178]755 # OpenSUSE does't seem to import keys automatically
756 # :-(
757 if ($pbos->{install} =~ /\bzypper\b/) {
758 my $keyfile = undef;
[2434]759 open(REPO,"$dest") || (cluck "Unable to open $dest" && next);
[2178]760 while (<REPO>) {
[2181]761 $keyfile = $_;
762 if ($keyfile =~ /^gpgkey=/) {
763 $keyfile =~ s/gpgkey=//;
764 last;
[2178]765 }
766 }
767 close(REPO);
768 if (defined $keyfile) {
769 pb_system("wget -O $ENV{'PBTMP'}/$bn $keyfile","Downloading GPG key file $keyfile");
[2181]770 pb_system("sudo rpm --import $ENV{'PBTMP'}/$bn","Importing GPG key file $keyfile");
[2178]771 unlink("$ENV{'PBTMP'}/$bn");
772 }
773 }
[702]774 } elsif ($bn =~ /\.addmedia/) {
775 # URPMI repo
[2427]776 # We should test that it's not an already setup urpmi repo
[2434]777 open(URPMI,"/etc/urpmi/urpmi.cfg") || (cluck "Unable to open /etc/urpmi/urpmi.cfg" && next);
[2427]778 my $found = 0;
779 my $entry = $bn;
780 $entry =~ s/.addmedia$//;
781 while (<URPMI>) {
782 $found = 1 if ($_ =~ /^$entry /);
783 }
784 pb_system("chmod 755 $ENV{'PBTMP'}/$bn ; sudo $ENV{'PBTMP'}/$bn 2>&1 > /dev/null","Adding urpmi repository") if ($found == 0);
785 pb_log(0,"INFO urpmi $bn already set up\n") if ($found == 1);
[702]786 } else {
[1507]787 pb_log(0,"ERROR: Unable to deal with repository file $i on rpm distro ! Please report to dev team\n");
[702]788 }
[1177]789 } elsif ($pbos->{'type'} eq "deb") {
[1507]790 if ($bn =~ /\.sources.list$/) {
791 my $dest = "/etc/apt/sources.list.d/$bn";
[2427]792 return(undef) if (pb_distro_compare_repo("$ENV{'PBTMP'}/$bn",$dest) == 1);
[2188]793 pb_system("sudo mv $ENV{'PBTMP'}/$bn $dest","Adding apt repository $dest");
794 # Check whether GPG keys for this repo are already known and if
795 # not add them
[2434]796 open(REPO,"$dest") || (cluck "Unable to open $dest" && next);
[2188]797 my $debrepo;
798 while (<REPO>) {
799 if (/^deb\s/) {
800 $debrepo = $_;
801 chomp($debrepo);
802 $debrepo =~ s|^deb ([^\s]+)\s([^\s]+)\s([^\s]+)|$1/dists/$2|;
803 last;
804 }
805 }
806 close(REPO);
[2427]807 return(undef) if (not defined $debrepo);
[2188]808
809 pb_system("wget -O $ENV{'PBTMP'}/Release $debrepo/Release","Downloading $debrepo/Release");
810 pb_system("wget -O $ENV{'PBTMP'}/Release.gpg $debrepo/Release.gpg","Downloading $debrepo/Release.gpg");
[2410]811 my $signature = undef;
812 my ($pbgpgserver) = pb_conf_get("pbgpgserver");
813 confess "Unable to find a GPG server in configuration, please define pbgpgserver" if (not defined $pbgpgserver);
814 my $keyserver = $pbgpgserver->{$ENV{'PBPROJ'}};
815 $keyserver = $pbgpgserver->{'default'} if (not defined $keyserver);
816 confess "Unable to find a GPG server in configuration, please define correctly pbgpgserver" if (not defined $keyserver);
[2434]817 open(SIGN,"LANGUAGE=C LANG=C gpg --verify --keyid-format=long $ENV{'PBTMP'}/Release.gpg $ENV{'PBTMP'}/Release 2>&1 |") || (cluck "Unable to verify GPG signature from Release.gpg\n" && next);
[2188]818 while(<SIGN>) {
819 chomp();
[2410]820 if (/^gpg: .*key /) {
[2188]821 $signature = $_;
[2410]822 $signature =~ s/^gpg: .*key [ID ]*([A-Z0-9]+)/$1/;
823 pb_system("gpg --recv-keys --keyserver $keyserver $signature","Importing GPG signature for $signature");
[2188]824 last;
825 }
826 }
827 close(SIGN);
[2427]828 return(undef) if (not defined $signature);
[2188]829
830 pb_log(3, "GnuPG repo verify returned: $signature\n");
831 pb_system("gpg -a --export -o $ENV{'PBTMP'}/apt.sig \'$signature\'","Exporting GnuPG signature of $signature");
832 pb_system("sudo apt-key add $ENV{'PBTMP'}/apt.sig","Adding GnuPG signature of $signature to APT key ring");
[711]833 pb_system("sudo apt-get update","Updating apt repository");
[702]834 } else {
[1507]835 pb_log(0,"ERROR: Unable to deal with repository file $i on deb distro ! Please report to dev team\n");
[702]836 }
837 } else {
[1507]838 pb_log(0,"ERROR: Unable to deal with repository file $i on that distro ! Please report to dev team\n");
[702]839 }
840}
[2182]841return("forcerepo");
[702]842}
843
[1553]844=item B<pb_distro_to_keylist>
[1523]845
[1553]846Given a pbos object (first param) and the generic key (second param), get the list of possible keys for looking up variable for
[1523]847filter names. The list will be sorted most-specific to least specific.
848
849=cut
850
[1553]851sub pb_distro_to_keylist ($$) {
[1523]852
853my ($pbos, $generic) = @_;
854
855foreach my $key (qw/name version arch family type os/) {
[1529]856 confess "missing pbos key $key" unless (defined $pbos->{$key});
[1523]857}
858
859my @keylist = ("$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}", "$pbos->{'name'}-$pbos->{'version'}");
860
861# Loop to include also previous minor versions
862# if configured so
[1530]863if ((defined $pbos->{'useminor'}) && ($pbos->{'useminor'} eq "true") && ($pbos->{'version'} =~ /^(\d+)\.(\d+)$/o)) {
[1523]864 my ($major, $minor) = ($1, $2);
865 while ($minor > 0) {
866 $minor--;
[1530]867 push (@keylist, "$pbos->{'name'}-${major}.$minor");
[1523]868 }
[1530]869 push (@keylist, "$pbos->{'name'}-$major");
[1523]870}
871
[1530]872push (@keylist, $pbos->{'name'}, $pbos->{'family'}, $pbos->{'type'}, $pbos->{'os'}, $generic);
[1523]873return @keylist;
874}
875
[702]876=item B<pb_distro_get_param>
877
[2488]878This internal function gets the parameters in the conf file from the most precise tuple up to default
[702]879
880=cut
881
882sub pb_distro_get_param {
883
[2488]884my $pbos = shift;
885my $var = shift;
[1540]886my @param = ();
[2488]887my $i = 0;
888pb_log(3,"var: ".Dumper($var));
[702]889
[1553]890my @keylist = pb_distro_to_keylist($pbos,"default");
[2488]891pb_log(3,"keylist: ".Dumper(@keylist));
892
893my $p = $var->{"ptr"};
894foreach my $opt (@$p) {
895 pb_log(3,'opt: '.Dumper($opt));
896 my $param = undef;
897 my $fkey = undef;
[1523]898 foreach my $key (@keylist) {
[2488]899 pb_log(3,"key: $key\n");
[1523]900 if (defined $opt->{$key}) {
901 $param = $opt->{$key};
[2488]902 $fkey = $key;
[1523]903 last;
904 }
[1177]905 }
[2488]906 my $field = $var->{"val"};
907 pb_log(3,"field: ".Dumper($field));
908 $fkey = "default" if (not defined $fkey);
909 pb_log(3,"key: $fkey\n");
910 pb_log(2,"DEBUG: pb_distro_get_if on $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} for $field->[$i]".'{'.$fkey.'}'." returns ");
911 if (defined $param) {
912 # Allow replacement of variables inside the parameter such as name, version, arch for rpmbootstrap
913 # but not shell variable which are backslashed
914 if ($param =~ /[^\\]\$/) {
915 pb_log(3,"Expanding variable on $param\n");
916 eval { $param =~ s/(\$\w+->\{\'\w+\'\})/$1/eeg };
917 }
918 pb_log(2,"$param\n");
919 } else {
920 pb_log(2,"undefined\n");
[1177]921 }
922 push @param,$param;
[2488]923 $i++;
[702]924}
[974]925
[1523]926# Return one param if user only asked for one lookup, an array if not.
[1177]927my $nb = @param;
[2488]928pb_log(3,"Param".Dumper(@param)." has $nb members\n");
[1177]929if ($nb eq 1) {
[2490]930 pb_log(3,"Return param $param[0]\n") if (defined $param[0]);
[1523]931 return($param[0]);
[1177]932} else {
933 return(@param);
[982]934}
[1177]935}
[974]936
[2488]937
938=item B<pb_distro_get_if>
939
940This function gets the parameters in the conf file from the most precise tuple up to default
941
942=cut
943
944sub pb_distro_get_if {
945
946my $pbos = shift;
947my @ptr = pb_conf_get_if(@_);
948my $var;
949$var->{"ptr"} = \@ptr;
950$var->{"val"} = \@_;
951return(pb_distro_get_param($pbos,$var));
952}
953
954=item B<pb_distro_get>
955
956This function gets the parameters in the conf file from the most precise tuple up to default.
957Aborts of one param doesn't exist whereas it should
958
959=cut
960
961sub pb_distro_get {
962
963my $pbos = shift;
964my @param = @_;
965my @return = pb_distro_get_if($pbos,@param);
966
967foreach my $i (0..$#param) {
968 confess "No $param[$i] defined for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}" if (not defined $return[$i]);
969}
970my $nb = @return;
971if ($nb eq 1) {
972 return($return[0]);
973} else {
974 return(@return);
975}
976}
977
978=item B<pb_distro_get_in_hash_if>
979
980This function gets the parameters in the conf file passed as hash from the most precise tuple up to default
981
982=cut
983
984sub pb_distro_get_in_hash_if {
985
986my $pbos = shift;
987my $lh = shift || return(());
988
989my @ptr = pb_conf_get_in_hash_if($lh,@_);
990my $var;
991$var->{"ptr"} = \@ptr;
992$var->{"val"} = \@_;
993return(pb_distro_get_param($pbos,$var));
994}
995
[1177]996=item B<pb_distro_get_context>
[702]997
[1177]998This function gets the OS context passed as parameter and return the corresponding distribution hash
[1402]999If passed undef or "" then auto-detects
[1177]1000
1001=cut
1002
1003
1004sub pb_distro_get_context {
1005
1006my $os = shift;
1007my $pbos;
1008
[1402]1009if ((defined $os) && ($os ne "")) {
[1177]1010 my ($name,$ver,$darch) = split(/-/,$os);
1011 pb_log(0,"Bad format for $os") if ((not defined $name) || (not defined $ver) || (not defined $darch)) ;
1012 chomp($darch);
1013 $pbos = pb_distro_init($name,$ver,$darch);
1014} else {
1015 $pbos = pb_distro_init();
[702]1016}
[1177]1017return($pbos);
1018}
[749]1019
[1795]1020=item B<pb_distro_conf_print>
1021
[2152]1022This function prints every configuration parameter in order to help debug stacking issues with conf files. If a VM/VE/RM is given, restrict display to this distribution. If parameters are passed, restrict again the display to these values only.
[1795]1023
1024=cut
1025
1026sub pb_distro_conf_print {
1027
1028my $pbos = shift;
1029my @keys = @_;
[2350]1030my $all = 0;
[1795]1031
1032if ($#keys == -1) {
1033 pb_log(0,"Full pb configuration for project $ENV{'PBPROJ'}\n");
1034 pb_log(0,"================================================\n");
[2153]1035 @keys = pb_conf_get_all();
[2350]1036 $all = 1;
[1795]1037}
1038if (defined $ENV{'PBV'}) {
[2161]1039 pb_log(1,"Distribution $ENV{'PBV'}\n");
1040 pb_log(1,"========================\n");
[1795]1041} else {
[2161]1042 pb_log(1,"Local Distribution\n");
1043 pb_log(1,"==================\n");
[1795]1044}
1045
[2153]1046my %rep;
1047my $i = 0;
[2155]1048# Index on distro
[2511]1049foreach my $r (pb_distro_get_if($pbos,@keys)) {
[2155]1050 $rep{$keys[$i]} = $r if (defined $keys[$i]);
1051 $i++;
1052}
1053$i = 0;
1054# Then Index on prj to overwrite previous value if needed
[2511]1055foreach my $r (pb_conf_get_if(@keys)) {
[2153]1056 $rep{$keys[$i]} = $r->{'default'} if (defined $r->{'default'});
1057 $rep{$keys[$i]} = $r->{$ENV{'PBPROJ'}} if (defined $r->{$ENV{'PBPROJ'}});
1058 $i++;
[1795]1059}
[2153]1060foreach my $r (keys %rep) {
[2161]1061 pb_log(1, "$r => ");
[2511]1062 pb_log(0, "$rep{$r}\n") if (($all == 0) && (defined $rep{$r}));
1063 pb_log(0, "$r = $rep{$r}\n") if (($all == 1) && (defined $rep{$r}));
[2153]1064}
1065}
[1795]1066
1067
[395]1068=back
[23]1069
[395]1070=head1 WEB SITES
[23]1071
[395]1072The 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/>.
1073
1074=head1 USER MAILING LIST
1075
1076None exists for the moment.
1077
1078=head1 AUTHORS
1079
1080The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
1081
1082=head1 COPYRIGHT
1083
1084Project-Builder.org is distributed under the GPL v2.0 license
1085described in the file C<COPYING> included with the distribution.
1086
1087=cut
1088
1089
[11]10901;
Note: See TracBrowser for help on using the repository browser.