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 |
|