--- /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 %<varName>% 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 (<FDIR>)
+ {
+ 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 = <LFILE>)
+ {
+ 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 = <LFILE>)
+ {
+ 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__
+