diff -r 000000000000 -r 83f4b4db085c bldsystemtools/commonbldutils/PreBldChecks.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bldsystemtools/commonbldutils/PreBldChecks.pm Tue Feb 02 01:39:43 2010 +0200 @@ -0,0 +1,509 @@ +# Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# This module is intended to be run at an early stage when starting a Master Codeline build (or analogous "steady state) build. +# As such it is called from StartBuild.pl. It can also be called by PreBuildChecks.pl +# It will check for disk space and other aspects of the build environment. +# It issues errors and/or warnings by pushing texts onto global arrays and returning references to these arrays. +# +# + +package PreBldChecks; +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use lib "$FindBin::Bin\\..\\tools\\build\\lib"; +use lib "$FindBin::Bin\\..\\buildsystemtools\\lib"; +use XML::Parser; +use IO::Socket; +use Socket; +use Date::Manip; + +# Set TimeZone because Date:Manip needs it set and then tell it to IGNORE the TimeZone +Date::Manip::Date_Init("TZ=GMT","ConvTZ=IGNORE"); + +my @Errors = (); +my @Warnings = (); + +# XMLEnvironment +# This is a public interface to this module +# Reads supplied XML file and resolves back references (i.e the %% syntax!). +# +# Inputs +# Name of input XML file +# +# Returns +# Reference to hash containing environment data read from XML file, or undef on error. +# +sub XMLEnvironment +{ + my $iXMLfile = shift; + my %iXML_ENV; # Hash whose reference will be returned + @SubHandlers::gXMLdata = (); # Clear global array. This allows this subroutine to be called twice. + my $iParser = new XML::Parser(Style=>'Subs', Pkg=>'SubHandlers', ErrorContext => 2); + + unless (-e $iXMLfile) + { + push @Errors, "XML File not found at: \"$iXMLfile\"!"; + return undef; + } + + # Pass XML data source filename to the XML Parser + $iParser->parsefile($iXMLfile); + for (my $iIndx = 0; $iIndx < scalar @SubHandlers::gXMLdata; $iIndx++) + { + my $iHashRef = $SubHandlers::gXMLdata[$iIndx]; + unless (defined $iHashRef) { next; } + # Resolve references to preceding variables in the current XML file or in the Windows environment + while ($iHashRef->{Value} =~ m/%(\w+)%/) + { + my $iVarName = $1; + if (defined $iXML_ENV{$iVarName}) + { # First substitute from our own XML file data + $iHashRef->{Value} =~ s/%\w+%/$iXML_ENV{$iVarName}/; + } + elsif (defined $ENV{$iVarName}) + { # Secondly substitute from the Windows environment + $iHashRef->{Value} =~ s/%\w+%/$ENV{$iVarName}/; + } + else + { + $iHashRef->{Value} =~ s/%\w+%//; # Undefined variables become 'nothing'. + } + } # End while() + $iHashRef->{Value} =~ s/%%//g; # Any remaining double % become single % + $iXML_ENV{$iHashRef->{Name}} = $iHashRef->{Value}; + } # End for() + return \%iXML_ENV; +} + +# MergeEnvironment +# This is a public interface to this module +# Merge supplied environment variables into %ENV. It seems that %ENV is a form of tied hash which supports +# Windows (case-preserving) variable names. Names are always returns (by key function) in upper case. +# +# Input: New variables to be added to %ENV (hash ref.) +# +# Output: Modifications to global %ENV +# +# Return: None +# +sub MergeEnvironment +{ + my $iEnvRef = shift; # Environment variables to be added to %ENV + + for my $iName (keys %$iEnvRef) + { + $ENV{$iName} = $iEnvRef->{$iName}; + } +} + +# AllChecks +# This is a public interface to this module +# It checks various items in the build environment and reports any anomalies. +# +# Inputs +# Reference to environment hash. This may be the hash populated by a previous call to sub XMLEnvironment() +# or may be the predefined hash %ENV +# +# Returns +# Two array refs: \@Errors,\@Warnings +# +sub AllChecks +{ + my $iEnvRef = shift; + my $iXMLerror = 0; + + checkdiskspace($iEnvRef); # Check Disk Space + checkCWlicensing(); # Check CodeWarrior licensing + checkARMlicensing(); # Check ARM licensing + return \@Errors,\@Warnings; +} + +# checkdiskspace +# +# Inputs +# Reference to hash containing environment variables +# +# Outputs +# Pushes error/warning texts onto global arrays +# +sub checkdiskspace +{ + my $iEnvRef = shift; + my $iPublishLoc = $iEnvRef->{'PublishLocation'}; # Directory (network share) to which build is to be published e.g \\Builds01\DevBuilds + $iPublishLoc =~ s/([^\\])$/$1\\/; # Ensure trailing backslash + my $iCBRLocation = $iEnvRef->{'CBRLocation'}; # Directory (network share) containg CBR archive(s) + unless (defined $iCBRLocation) { $iCBRLocation = '\\\\Builds01\\devbuilds\\ComponentisedReleases'; }; + $iPublishLoc .= $iEnvRef->{'Type'}; # Append Type to gaive a real directory name for DIR to check + my $iPublishMin = $iEnvRef->{'PublishDiskSpaceMin'};# Space in gigabytes required on that drive + my $iLocalMin = $iEnvRef->{'LocalDiskSpaceMin'}; # Space in gigabytes required on local (current) drive + +# Check disk space on local drive (assumed to be the Windows current drive) + unless (defined $iLocalMin) + { + push @Errors, "Unable to check disk space on local drive!\n\tCheck environment variable \"LocalDiskSpaceMin\""; + } + else + { + my $free = freespace(''); + unless (defined $free) + { + push @Errors, 'Unable to check disk space on local drive!'; + } + elsif ($free < ($iLocalMin * 1000000000)) + { + push @Errors, "Insufficient space on local drive! $iLocalMin gigabytes required."; + } + } + +# Check disk space on "Publishing Location" + unless ((defined $iEnvRef->{'PublishLocation'}) and (defined $iEnvRef->{'Type'}) and (defined $iPublishMin)) + { + push @Errors, "Unable to check disk space on \"Publishing\" drive\"!\n\tCheck env. var\'s \"PublishLocation\", \"Type\" and \"PublishDiskSpaceMin\""; + } + else + { + my $free = freespace($iPublishLoc); + unless (defined $free) + { + push @Errors, "Unable to check disk space on \"$iPublishLoc\"!"; + } + elsif ($free < ($iPublishMin * 1000000000)) + { + push @Warnings, "Insufficient space on \"$iPublishLoc\"! $iPublishMin gigabytes required."; + } + } + + # Check disk space on CBR location + unless ((defined $iCBRLocation) and (defined $iPublishMin)) + { + push @Errors, "Unable to check disk space on \"CBR\" drive\"!\n\tCheck env. var\'s \"CBRLocation\" and \"PublishDiskSpaceMin\""; + } + else + { + my $free = freespace($iCBRLocation); + unless (defined $free) + { + push @Errors, "Unable to check disk space on \"$iCBRLocation\""; + } + elsif ($free < ($iPublishMin * 1000000000)) + { + push @Warnings, "Insufficient space on \"$iCBRLocation\"! $iPublishMin gigabytes required."; + } + } +} + +# freespace +# +# Inputs +# Drive letter or share name (or empty string for current drive) +# +# Returns +# Free space in bytes or undef on error. +# +sub freespace +{ + my $drive = shift; # Typically 'D:' (including the colon!) or '\\Builds01\DevBuilds' + my $free = undef; # Free bytes on drive + if (defined $drive) + { + open FDIR, 'DIR /-c ' . $drive. '\* |'; + while () + { + if ($_ =~ /\s+(\d+) bytes free/) { $free=$1;} + } + } + return $free; +} + +# checkCWlicensing +# +# Inputs +# None. Environment variables must come from the Windows environment (via global hash %ENV) +# +# Outputs +# Pushes warning texts onto global arrays +# (Licensing problems are always treated as warnings because new compiler versions +# tend to create apparent errors and it takes a finite time to update this script.) +# +sub checkCWlicensing +{ # Environment variables: LM_LICENSE_FILE and/or NOKIA_LICENSE_FILE + my @licensefiles; + if (defined $ENV{'MWVER'}) + { + if($ENV{'MWVER'} gt '3.0') + { + ####???? print "No CodeWarrior licence required!"; For debugging + return; + } + } + if (defined $ENV{'LM_LICENSE_FILE'}) + { + push @licensefiles, split /;/, $ENV{'LM_LICENSE_FILE'}; + } + if (defined $ENV{'NOKIA_LICENSE_FILE'}) + { + push @licensefiles, split /;/, $ENV{'NOKIA_LICENSE_FILE'}; + } + unless (@licensefiles) + { # Environment variable(s) not set up + push @Warnings, 'Neither LM_LICENSE_FILE nor NOKIA_LICENSE_FILE defined!'; + return; + } + foreach my $licensefile (@licensefiles) + { + if (-e $licensefile) + { # File exists. So open and parse + if (parseCWlicensefile($licensefile)) + { return; } # If parsing subroutine returns TRUE, do not look for any more files + } + else + { + push @Warnings, "Environment specifies file $licensefile but not found!"; + } + } # End foreach() + push @Warnings, "No valid CodeWarrior license found!"; +} + +# parseCWlicensefile +# +# Inputs +# Filename +# +# Outputs +# Pushes error/warning texts onto global arrays +# Returns TRUE if relevant license information found. FALSE means "Try another file." +# +sub parseCWlicensefile +{ + my $fname = shift; + my $return = 0; # Default to FALSE - "Try another file." + unless (open (LFILE, "$fname")) + { + push @Warnings, "License file ($fname) cannot be opened!"; + return $return; # "Try another file." + } + my $wholeline; # Used to assemble continuation lines into one entry + while(my $line = ) + { + chomp $line; + $line =~ s/^\s*//; # Remove leading spaces + $wholeline .= $line; + if ($wholeline =~ s/\\$//) { next; } # Trailing backslash means entry continues on next line + if ($wholeline =~ m/^FEATURE.+symbian/i) # FEATURE is CW usage (not ARM !?) + { + if ($wholeline =~ m/permanent/i) + { + $return = 1; # Licence OK. "Do not try another file." + last; + } + if ($wholeline =~ m/(\d{1,2}-\w{3}-\d{2,4})/i) + { + my ($date2) = Date::Manip::ParseDate($1); + unless (defined $date2) + { + push @Warnings, "Failed to parse CodeWarrior license expiry date! (License file $fname)"; + last; # "Try another file." + } + my $expirytext = Date::Manip::UnixDate($date2,"%Y/%m/%d"); + my $delta = Date::Manip::DateCalc("today",$date2); + my $Dd = Date::Manip::Delta_Format($delta,'0',"%dt"); + if ($Dd < 1) + { + push @Warnings, "CodeWarrior license expired on $expirytext! (License file $fname)"; + } + elsif ($Dd < 7) + { + push @Warnings, "CodeWarrior license expires on $expirytext! (License file $fname)"; + } + $return = 1; # Licence expiry date parsed. "Do not try another file." + last; + } + } + $wholeline = ''; + } # End while() + close LFILE; + return $return; +} + +# checkARMlicensing +# +# Inputs +# None. Environment variables must come from the Windows environment (via global hash %ENV) +# +# Outputs +# Pushes warning texts onto global arrays +# (Licensing problems are always treated as warnings because new compiler versions +# tend to create apparent errors and it takes a finite time to update this script.) +# +sub checkARMlicensing +{ # Environment variables: LM_LICENSE_FILE and/or ARMLMD_LICENSE_FILE + my @licensefiles; + if (defined $ENV{'LM_LICENSE_FILE'}) + { + push @licensefiles, split /;/, $ENV{'LM_LICENSE_FILE'}; + } + if (defined $ENV{'ARMLMD_LICENSE_FILE'}) + { + push @licensefiles, split /;/, $ENV{'ARMLMD_LICENSE_FILE'}; + } + unless (@licensefiles) + { # Environment variable(s) not set up + push @Warnings, 'Neither LM_LICENSE_FILE nor ARMLMD_LICENSE_FILE defined!'; + return; + } + my $iLicenceFound = 0; + foreach my $licensefile (@licensefiles) + { + if($licensefile =~ m/^(\d+)\@([-\w\.]+)$/) + { + if(VerifySocket($2,$1)) + { $iLicenceFound = 1; next; } + push @Warnings, "Apparent licence server cannot be accessed. (Host=$2 Port=$1)!"; + } + elsif (-e $licensefile) + { # File exists. So open and parse + if (parseARMlicensefile($licensefile)) + { $iLicenceFound = 1; next; } + } + else + { + push @Warnings, "Environment specifies file $licensefile but not found!"; + } + } # End foreach() + unless ($iLicenceFound) + { push @Warnings, "No valid ARM license found!"; } +} + +# parseARMlicensefile +# +# Inputs +# Filename +# +# Outputs +# Pushes error/warning texts onto global arrays +# Returns TRUE if relevant license information found. FALSE means "Try another file." +# +sub parseARMlicensefile +{ + my $fname = shift; + my $return = 0; # Default to FALSE - "Try another file." + unless (open (LFILE, "$fname")) + { + push @Warnings, "License file ($fname) cannot be opened!"; + return $return; # "Try another file." + } + my $wholeline; # Used to assemble continuation lines into one entry + while(my $line = ) + { + chomp $line; + $line =~ s/^\s*//; # Remove leading spaces + $wholeline .= $line; + if ($wholeline =~ s/\\$//) { next; } # Trailing backslash means entry continues on next line + if ($wholeline =~ m/^INCREMENT.+symbian/i) # INCREMENT is ARM usage (not CW !?) + { + if ($wholeline =~ m/permanent/i) + { + $return = 1; # Licence OK. "Do not try another file." + last; + } + if ($wholeline =~ m/(\d{1,2}-\w{3}-\d{2,4})/i) + { + my ($date2) = Date::Manip::ParseDate($1); + unless (defined $date2) + { + push @Warnings, "Failed to parse ARM license expiry date! (License file $fname)"; + last; # "Try another file." + } + my $expirytext = Date::Manip::UnixDate($date2,"%Y/%m/%d"); + my $delta = Date::Manip::DateCalc("today",$date2); + my $Dd = Date::Manip::Delta_Format($delta,'0',"%dt"); + if ($Dd < 1) + { + push @Warnings, "ARM license expired on $expirytext! (License file $fname)"; + } + elsif ($Dd < 7) + { + push @Warnings, "ARM license expires on $expirytext! (License file $fname)"; + } + $return = 1; # Licence expiry date parsed. "Do not try another file." + last; + } + } + $wholeline = ''; + } # End while() + close LFILE; + return $return; +} + +# VerifySocket +# +# Verify that the specified host+port exists and that a socket can be opened +# +# Input: Hostname, Port number +# +# Return: TRUE if socket can be opened +# +sub VerifySocket +{ + my $iHost = shift; + my $iPort = shift; + my $iSocket; + + # Attempt to create a socket connection + $iSocket = IO::Socket::INET->new(PeerAddr => $iHost, + PeerPort => $iPort, + Proto => "tcp", + Type => SOCK_STREAM); + + unless ($iSocket) { return 0; } # FALSE = Failure + close($iSocket); + return 1; # TRUE = Success +} + + +package SubHandlers; +our @gXMLdata; # Stores data as read from XML file. Is accessed by PreBldChecks::XMLEnvironment() only + +# SetEnv +# +# Description +# This subroutine handles the callback from the XML parser for the SetEnv tag in the XML file. +# Multiple instances allowed +# In the Build System context, each call to this subroutine corresponds to one environment variable. +# +# Inputs +# Reference to an instance of XML::Parser::Expat +# The name of the element ('SetEnv') +# A list of alternating attribute names and their values. +# +# Outputs +# Adds data directly to global array @gXMLdata +# +sub SetEnv +{ + shift; # Hashref (instance of XML::Parser::Expat) + shift; # Always 'SetEnv' + + # Read the attributes of the tag into a hash + my %iAttribs = @_; + + # Add this hash (representing a single tag) to the array of SetEnv tags from this file + push @gXMLdata, \%iAttribs; +} + +1; + +__END__ +