bldsystemtools/commonbldutils/PreBldChecks.pm
branchRCL_3
changeset 24 d90029decf65
parent 20 a9d4531388d0
child 33 54aa4a06a075
child 34 5e522efbae7b
equal deleted inserted replaced
20:a9d4531388d0 24:d90029decf65
     1 # Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 # This module is intended to be run at an early stage when starting a Master Codeline build (or analogous "steady state) build.
       
    15 # As such it is called from StartBuild.pl. It can also be called by PreBuildChecks.pl
       
    16 # It will check for disk space and other aspects of the build environment.
       
    17 # It issues errors and/or warnings by pushing texts onto global arrays and returning references to these arrays.
       
    18 # 
       
    19 #
       
    20 
       
    21 package PreBldChecks;
       
    22 use strict;
       
    23 use FindBin;
       
    24 use lib "$FindBin::Bin";
       
    25 use lib "$FindBin::Bin\\..\\tools\\build\\lib";
       
    26 use lib "$FindBin::Bin\\..\\buildsystemtools\\lib";
       
    27 use XML::Parser;
       
    28 use IO::Socket;
       
    29 use Socket;
       
    30 use Date::Manip;
       
    31 
       
    32 # Set TimeZone because Date:Manip needs it set and then tell it to IGNORE the TimeZone
       
    33 Date::Manip::Date_Init("TZ=GMT","ConvTZ=IGNORE");
       
    34 
       
    35 my @Errors = ();
       
    36 my @Warnings = ();
       
    37 
       
    38 # XMLEnvironment
       
    39 # This is a public interface to this module
       
    40 # Reads supplied XML file and resolves back references (i.e the %<varName>% syntax!).
       
    41 #
       
    42 # Inputs
       
    43 # Name of input XML file
       
    44 #
       
    45 # Returns
       
    46 # Reference to hash containing environment data read from XML file, or undef on error.
       
    47 #
       
    48 sub XMLEnvironment
       
    49 {
       
    50     my $iXMLfile = shift;
       
    51     my %iXML_ENV;       # Hash whose reference will be returned
       
    52     @SubHandlers::gXMLdata = ();     # Clear global array. This allows this subroutine to be called twice.
       
    53     my $iParser = new XML::Parser(Style=>'Subs', Pkg=>'SubHandlers', ErrorContext => 2);
       
    54 
       
    55     unless (-e $iXMLfile)
       
    56     {
       
    57         push @Errors, "XML File not found at: \"$iXMLfile\"!";
       
    58         return undef;
       
    59     }
       
    60     
       
    61     # Pass XML data source filename to the XML Parser
       
    62     $iParser->parsefile($iXMLfile);
       
    63     for (my $iIndx = 0; $iIndx < scalar @SubHandlers::gXMLdata; $iIndx++)
       
    64     {
       
    65         my $iHashRef = $SubHandlers::gXMLdata[$iIndx];
       
    66         unless (defined $iHashRef) { next; }
       
    67         # Resolve references to preceding variables in the current XML file or in the Windows environment
       
    68         while ($iHashRef->{Value} =~ m/%(\w+)%/)
       
    69         {
       
    70             my $iVarName = $1;
       
    71             if (defined $iXML_ENV{$iVarName})
       
    72             {   # First substitute from our own XML file data
       
    73                 $iHashRef->{Value} =~ s/%\w+%/$iXML_ENV{$iVarName}/;
       
    74             }
       
    75             elsif (defined $ENV{$iVarName})
       
    76             {   # Secondly substitute from the Windows environment
       
    77                 $iHashRef->{Value} =~ s/%\w+%/$ENV{$iVarName}/;
       
    78             }
       
    79             else
       
    80             {
       
    81                 $iHashRef->{Value} =~ s/%\w+%//;  # Undefined variables become 'nothing'.
       
    82             }
       
    83         }   # End while()
       
    84         $iHashRef->{Value} =~ s/%%//g;      # Any remaining double % become single %
       
    85         $iXML_ENV{$iHashRef->{Name}} = $iHashRef->{Value};
       
    86     }   # End for()
       
    87     return \%iXML_ENV;
       
    88 }
       
    89 
       
    90 # MergeEnvironment
       
    91 # This is a public interface to this module
       
    92 # Merge supplied environment variables into %ENV. It seems that %ENV is a form of tied hash which supports
       
    93 # Windows (case-preserving) variable names. Names are always returns (by key function) in upper case.
       
    94 #
       
    95 # Input: New variables to be added to %ENV (hash ref.)
       
    96 #
       
    97 # Output: Modifications to global %ENV
       
    98 #
       
    99 # Return: None
       
   100 #
       
   101 sub MergeEnvironment
       
   102 {
       
   103     my $iEnvRef = shift;            # Environment variables to be added to %ENV
       
   104 
       
   105     for my $iName (keys %$iEnvRef)
       
   106     {
       
   107         $ENV{$iName} = $iEnvRef->{$iName};
       
   108     }
       
   109 }
       
   110 
       
   111 # AllChecks
       
   112 # This is a public interface to this module
       
   113 # It checks various items in the build environment and reports any anomalies.
       
   114 #
       
   115 # Inputs
       
   116 # Reference to environment hash. This may be the hash populated by a previous call to sub XMLEnvironment()
       
   117 # or may be the predefined hash %ENV
       
   118 #
       
   119 # Returns
       
   120 # Two array refs: \@Errors,\@Warnings
       
   121 #
       
   122 sub AllChecks
       
   123 {
       
   124     my $iEnvRef = shift;
       
   125     my $iXMLerror = 0;
       
   126     
       
   127     checkdiskspace($iEnvRef);  # Check Disk Space
       
   128     checkCWlicensing();        # Check CodeWarrior licensing
       
   129     checkARMlicensing();       # Check ARM licensing
       
   130     return \@Errors,\@Warnings;
       
   131 }
       
   132 
       
   133 # checkdiskspace
       
   134 #
       
   135 # Inputs
       
   136 # Reference to hash containing environment variables
       
   137 #
       
   138 # Outputs
       
   139 # Pushes error/warning texts onto global arrays
       
   140 #
       
   141 sub checkdiskspace
       
   142 {
       
   143     my $iEnvRef = shift; 
       
   144     my $iPublishLoc = $iEnvRef->{'PublishLocation'};    # Directory (network share) to which build is to be published e.g \\Builds01\DevBuilds
       
   145     $iPublishLoc =~ s/([^\\])$/$1\\/;                   # Ensure trailing backslash   
       
   146     my $iCBRLocation = $iEnvRef->{'CBRLocation'};       # Directory (network share) containg CBR archive(s)
       
   147     unless (defined $iCBRLocation) { $iCBRLocation = '\\\\Builds01\\devbuilds\\ComponentisedReleases'; };
       
   148     $iPublishLoc .= $iEnvRef->{'Type'};                 # Append Type to gaive a real directory name for DIR to check
       
   149     my $iPublishMin = $iEnvRef->{'PublishDiskSpaceMin'};# Space in gigabytes required on that drive
       
   150     my $iLocalMin = $iEnvRef->{'LocalDiskSpaceMin'};    # Space in gigabytes required on local (current) drive
       
   151 
       
   152 # Check disk space on local drive (assumed to be the Windows current drive)
       
   153     unless (defined $iLocalMin)
       
   154     {
       
   155         push @Errors, "Unable to check disk space on local drive!\n\tCheck environment variable \"LocalDiskSpaceMin\"";
       
   156     }
       
   157     else
       
   158     {
       
   159         my $free = freespace('');
       
   160         unless (defined $free)
       
   161         {
       
   162             push @Errors, 'Unable to check disk space on local drive!';
       
   163         }
       
   164         elsif ($free < ($iLocalMin * 1000000000))
       
   165         {
       
   166             push @Errors, "Insufficient space on local drive! $iLocalMin gigabytes required.";
       
   167         }
       
   168     }
       
   169     
       
   170 # Check disk space on "Publishing Location"
       
   171     unless ((defined $iEnvRef->{'PublishLocation'}) and (defined $iEnvRef->{'Type'}) and (defined $iPublishMin))
       
   172     {
       
   173         push @Errors, "Unable to check disk space on \"Publishing\" drive\"!\n\tCheck env. var\'s \"PublishLocation\", \"Type\" and \"PublishDiskSpaceMin\"";
       
   174     }
       
   175     else
       
   176     {
       
   177         my $free = freespace($iPublishLoc);
       
   178         unless (defined $free)
       
   179         {
       
   180             push @Errors, "Unable to check disk space on \"$iPublishLoc\"!";
       
   181         }
       
   182         elsif ($free < ($iPublishMin * 1000000000))
       
   183         {
       
   184             push @Warnings, "Insufficient space on \"$iPublishLoc\"! $iPublishMin gigabytes required.";
       
   185         }
       
   186     }
       
   187 
       
   188     # Check disk space on CBR location
       
   189     unless ((defined $iCBRLocation) and (defined $iPublishMin))
       
   190     {
       
   191         push @Errors, "Unable to check disk space on \"CBR\" drive\"!\n\tCheck env. var\'s \"CBRLocation\" and \"PublishDiskSpaceMin\"";
       
   192     }
       
   193     else
       
   194     {
       
   195         my $free = freespace($iCBRLocation);
       
   196         unless (defined $free)
       
   197         {
       
   198             push @Errors, "Unable to check disk space on \"$iCBRLocation\"";
       
   199         }
       
   200         elsif ($free < ($iPublishMin * 1000000000))
       
   201         {
       
   202             push @Warnings, "Insufficient space on \"$iCBRLocation\"! $iPublishMin gigabytes required.";
       
   203         }
       
   204     }
       
   205 }
       
   206 
       
   207 # freespace
       
   208 #
       
   209 # Inputs
       
   210 # Drive letter or share name (or empty string for current drive)
       
   211 #
       
   212 # Returns
       
   213 # Free space in bytes or undef on error.
       
   214 #
       
   215 sub freespace
       
   216 {
       
   217     my $drive = shift;  # Typically 'D:' (including the colon!) or '\\Builds01\DevBuilds'
       
   218     my $free = undef;   # Free bytes on drive
       
   219     if (defined $drive)
       
   220     {
       
   221         open FDIR, 'DIR /-c ' . $drive. '\* |';
       
   222         while (<FDIR>)
       
   223         {
       
   224         	if ($_ =~ /\s+(\d+) bytes free/) { $free=$1;}
       
   225         }
       
   226     }
       
   227     return $free;
       
   228 }
       
   229 
       
   230 # checkCWlicensing
       
   231 #
       
   232 # Inputs
       
   233 # None. Environment variables must come from the Windows environment (via global hash %ENV)
       
   234 #
       
   235 # Outputs
       
   236 # Pushes warning texts onto global arrays
       
   237 # (Licensing problems are always treated as warnings because new compiler versions
       
   238 # tend to create apparent errors and it takes a finite time to update this script.)
       
   239 #
       
   240 sub checkCWlicensing
       
   241 {   # Environment variables: LM_LICENSE_FILE and/or NOKIA_LICENSE_FILE
       
   242     my @licensefiles;
       
   243     if (defined $ENV{'MWVER'})
       
   244     {
       
   245          if($ENV{'MWVER'} gt '3.0')
       
   246          {
       
   247             ####???? print "No CodeWarrior licence required!";   For debugging
       
   248             return;
       
   249          }
       
   250     }
       
   251     if (defined $ENV{'LM_LICENSE_FILE'})
       
   252     {
       
   253         push @licensefiles, split /;/, $ENV{'LM_LICENSE_FILE'};
       
   254     }
       
   255     if (defined $ENV{'NOKIA_LICENSE_FILE'})
       
   256     {
       
   257         push @licensefiles, split /;/, $ENV{'NOKIA_LICENSE_FILE'};
       
   258     }
       
   259     unless (@licensefiles)
       
   260     {   # Environment variable(s) not set up
       
   261         push @Warnings, 'Neither LM_LICENSE_FILE nor NOKIA_LICENSE_FILE defined!';
       
   262         return;
       
   263     }
       
   264     foreach my $licensefile (@licensefiles)
       
   265     {
       
   266         if (-e $licensefile)
       
   267         {   # File exists. So open and parse
       
   268             if (parseCWlicensefile($licensefile))
       
   269                 { return; }     # If parsing subroutine returns TRUE, do not look for any more files
       
   270         }
       
   271         else
       
   272         {
       
   273             push @Warnings, "Environment specifies file $licensefile but not found!";
       
   274         }
       
   275     }   # End foreach()
       
   276     push @Warnings, "No valid CodeWarrior license found!";
       
   277 }
       
   278 
       
   279 # parseCWlicensefile
       
   280 #
       
   281 # Inputs
       
   282 # Filename
       
   283 #
       
   284 # Outputs
       
   285 # Pushes error/warning texts onto global arrays
       
   286 # Returns TRUE if relevant license information found. FALSE means "Try another file."
       
   287 #
       
   288 sub parseCWlicensefile
       
   289 {
       
   290     my $fname = shift;
       
   291     my $return = 0; # Default to FALSE - "Try another file."
       
   292     unless (open (LFILE, "$fname"))
       
   293         {
       
   294         push @Warnings, "License file ($fname) cannot be opened!";
       
   295         return $return;     # "Try another file."
       
   296         }
       
   297     my $wholeline;  # Used to assemble continuation lines into one entry
       
   298     while(my $line = <LFILE>)
       
   299         {
       
   300         chomp $line;
       
   301         $line =~ s/^\s*//;     # Remove leading spaces
       
   302         $wholeline .= $line;
       
   303         if ($wholeline =~ s/\\$//) { next; }    # Trailing backslash means entry continues on next line
       
   304         if ($wholeline =~ m/^FEATURE.+symbian/i) # FEATURE is CW usage (not ARM !?)
       
   305             {
       
   306             if ($wholeline =~ m/permanent/i)
       
   307                 {        
       
   308                 $return = 1;    # Licence OK. "Do not try another file."
       
   309                 last;
       
   310                 }
       
   311             if ($wholeline =~ m/(\d{1,2}-\w{3}-\d{2,4})/i)
       
   312                 {
       
   313                 my ($date2) = Date::Manip::ParseDate($1);
       
   314                 unless (defined $date2)
       
   315                     {
       
   316                     push @Warnings, "Failed to parse CodeWarrior license expiry date! (License file $fname)";
       
   317                     last;   # "Try another file."
       
   318                     }
       
   319                 my $expirytext = Date::Manip::UnixDate($date2,"%Y/%m/%d");
       
   320                 my $delta = Date::Manip::DateCalc("today",$date2);
       
   321                 my $Dd = Date::Manip::Delta_Format($delta,'0',"%dt");
       
   322                 if ($Dd < 1)
       
   323                     {
       
   324                     push @Warnings, "CodeWarrior license expired on $expirytext! (License file $fname)";
       
   325                     }
       
   326                 elsif ($Dd < 7)
       
   327                     {
       
   328                     push @Warnings, "CodeWarrior license expires on $expirytext! (License file $fname)";
       
   329                     }
       
   330                 $return = 1;    # Licence expiry date parsed. "Do not try another file."
       
   331                 last;
       
   332                 }
       
   333             }
       
   334         $wholeline = '';
       
   335         }   # End while()
       
   336     close LFILE;
       
   337     return $return;
       
   338 }
       
   339 
       
   340 # checkARMlicensing
       
   341 #
       
   342 # Inputs
       
   343 # None. Environment variables must come from the Windows environment (via global hash %ENV)
       
   344 #
       
   345 # Outputs
       
   346 # Pushes warning texts onto global arrays
       
   347 # (Licensing problems are always treated as warnings because new compiler versions
       
   348 # tend to create apparent errors and it takes a finite time to update this script.)
       
   349 #
       
   350 sub checkARMlicensing
       
   351 {   # Environment variables: LM_LICENSE_FILE and/or ARMLMD_LICENSE_FILE
       
   352     my @licensefiles;
       
   353     if (defined $ENV{'LM_LICENSE_FILE'})
       
   354     {
       
   355         push @licensefiles, split /;/, $ENV{'LM_LICENSE_FILE'};
       
   356     }
       
   357     if (defined $ENV{'ARMLMD_LICENSE_FILE'})
       
   358     {
       
   359         push @licensefiles, split /;/, $ENV{'ARMLMD_LICENSE_FILE'};
       
   360     }
       
   361     unless (@licensefiles)
       
   362     {   # Environment variable(s) not set up
       
   363         push @Warnings, 'Neither LM_LICENSE_FILE nor ARMLMD_LICENSE_FILE defined!';
       
   364         return;
       
   365     }
       
   366     my $iLicenceFound = 0;
       
   367     foreach my $licensefile (@licensefiles)
       
   368     {
       
   369         if($licensefile =~ m/^(\d+)\@([-\w\.]+)$/)
       
   370         {
       
   371             if(VerifySocket($2,$1))
       
   372                 { $iLicenceFound = 1; next; }
       
   373             push @Warnings, "Apparent licence server cannot be accessed. (Host=$2 Port=$1)!";
       
   374         }
       
   375         elsif (-e $licensefile)
       
   376         {   # File exists. So open and parse
       
   377             if (parseARMlicensefile($licensefile))
       
   378                 { $iLicenceFound = 1; next; }
       
   379         }
       
   380         else
       
   381         {
       
   382             push @Warnings, "Environment specifies file $licensefile but not found!";
       
   383         }
       
   384     }   # End foreach()
       
   385     unless ($iLicenceFound)
       
   386         { push @Warnings, "No valid ARM license found!"; }
       
   387 }
       
   388 
       
   389 # parseARMlicensefile
       
   390 #
       
   391 # Inputs
       
   392 # Filename
       
   393 #
       
   394 # Outputs
       
   395 # Pushes error/warning texts onto global arrays
       
   396 # Returns TRUE if relevant license information found. FALSE means "Try another file."
       
   397 #
       
   398 sub parseARMlicensefile
       
   399 {
       
   400     my $fname = shift;
       
   401     my $return = 0; # Default to FALSE - "Try another file."
       
   402     unless (open (LFILE, "$fname"))
       
   403         {
       
   404         push @Warnings, "License file ($fname) cannot be opened!";
       
   405         return $return;     # "Try another file."
       
   406         }
       
   407     my $wholeline;  # Used to assemble continuation lines into one entry
       
   408     while(my $line = <LFILE>)
       
   409         {
       
   410         chomp $line;
       
   411         $line =~ s/^\s*//;     # Remove leading spaces
       
   412         $wholeline .= $line;
       
   413         if ($wholeline =~ s/\\$//) { next; }    # Trailing backslash means entry continues on next line
       
   414         if ($wholeline =~ m/^INCREMENT.+symbian/i) # INCREMENT is ARM usage (not CW !?)
       
   415             {
       
   416             if ($wholeline =~ m/permanent/i)
       
   417                 {        
       
   418                 $return = 1;    # Licence OK. "Do not try another file."
       
   419                 last;
       
   420                 }
       
   421             if ($wholeline =~ m/(\d{1,2}-\w{3}-\d{2,4})/i)
       
   422                 {
       
   423                 my ($date2) = Date::Manip::ParseDate($1);
       
   424                 unless (defined $date2)
       
   425                     {
       
   426                     push @Warnings, "Failed to parse ARM license expiry date! (License file $fname)";
       
   427                     last;   # "Try another file."
       
   428                     }
       
   429                 my $expirytext = Date::Manip::UnixDate($date2,"%Y/%m/%d");
       
   430                 my $delta = Date::Manip::DateCalc("today",$date2);
       
   431                 my $Dd = Date::Manip::Delta_Format($delta,'0',"%dt");
       
   432                 if ($Dd < 1)
       
   433                     {
       
   434                     push @Warnings, "ARM license expired on $expirytext! (License file $fname)";
       
   435                     }
       
   436                 elsif ($Dd < 7)
       
   437                     {
       
   438                     push @Warnings, "ARM license expires on $expirytext! (License file $fname)";
       
   439                     }
       
   440                 $return = 1;    # Licence expiry date parsed. "Do not try another file."
       
   441                 last;
       
   442                 }
       
   443             }
       
   444         $wholeline = '';
       
   445         }   # End while()
       
   446     close LFILE;
       
   447     return $return;
       
   448 }
       
   449 
       
   450 # VerifySocket
       
   451 #
       
   452 # Verify that the specified host+port exists and that a socket can be opened
       
   453 #
       
   454 # Input: Hostname, Port number
       
   455 #
       
   456 # Return: TRUE if socket can be opened
       
   457 #
       
   458 sub VerifySocket
       
   459 {
       
   460     my $iHost = shift;
       
   461     my $iPort = shift;
       
   462     my $iSocket;
       
   463 
       
   464     # Attempt to create a socket connection
       
   465     $iSocket = IO::Socket::INET->new(PeerAddr => $iHost,
       
   466                                 PeerPort => $iPort,
       
   467                                 Proto    => "tcp",
       
   468                                 Type     => SOCK_STREAM);
       
   469                                
       
   470     unless ($iSocket) { return 0; } # FALSE = Failure
       
   471     close($iSocket);
       
   472     return 1;   # TRUE = Success
       
   473 }
       
   474 
       
   475 
       
   476 package SubHandlers;
       
   477 our @gXMLdata;       # Stores data as read from XML file. Is accessed by PreBldChecks::XMLEnvironment() only
       
   478 
       
   479 # SetEnv
       
   480 #
       
   481 # Description
       
   482 # This subroutine handles the callback from the XML parser for the SetEnv tag in the XML file.
       
   483 # Multiple instances allowed
       
   484 # In the Build System context, each call to this subroutine corresponds to one environment variable.
       
   485 #
       
   486 # Inputs
       
   487 # Reference to an instance of XML::Parser::Expat
       
   488 # The name of the element ('SetEnv')
       
   489 # A list of alternating attribute names and their values.
       
   490 #
       
   491 # Outputs
       
   492 # Adds data directly to global array @gXMLdata
       
   493 #
       
   494 sub SetEnv
       
   495 {
       
   496     shift;   # Hashref (instance of XML::Parser::Expat)
       
   497     shift;   # Always 'SetEnv'
       
   498 
       
   499     # Read the attributes of the tag into a hash
       
   500     my %iAttribs = @_;
       
   501 
       
   502     # Add this hash (representing a single tag) to the array of SetEnv tags from this file
       
   503     push @gXMLdata, \%iAttribs;
       
   504 }
       
   505 
       
   506 1;
       
   507 
       
   508 __END__
       
   509