|
1 # Copyright (c) 2000-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 the License "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 |
|
15 |
|
16 package MrpData; |
|
17 |
|
18 use strict; |
|
19 use base qw(Symbian::CBR::MRPInterface); |
|
20 use File::Find; |
|
21 use File::Copy; |
|
22 use File::Basename; |
|
23 use File::Spec; |
|
24 use Utils; |
|
25 use Cwd; |
|
26 use Symbian::CBR::MRP::Reader; |
|
27 use IniData; |
|
28 |
|
29 use Carp; |
|
30 |
|
31 use constant MAX_PATH_LENGTH => 245; #If a file name has a path > MAX_PATH_LENGTH an error will be produced. |
|
32 |
|
33 |
|
34 |
|
35 use File::Path; |
|
36 use XML::Simple; |
|
37 use POSIX qw(strftime); |
|
38 use Data::Dumper; |
|
39 |
|
40 |
|
41 our $cache = {}; # Persistent (private) cache |
|
42 |
|
43 sub New { |
|
44 my $pkg = shift; |
|
45 my $self = {}; |
|
46 bless $self, $pkg; |
|
47 $self->{mrpName} = shift; |
|
48 $self->{ver} = shift; |
|
49 $self->{intVer} = shift; |
|
50 $self->{iniData} = shift || IniData->New(); |
|
51 $self->{verbose} = shift || 0; |
|
52 $self->{fixMissingLibs} = shift; |
|
53 $self->ExpandMrpName(); |
|
54 |
|
55 # This will be used by the IPR stuff, so that it can popultate the MrpData object without circular stuff |
|
56 my $doNotRead = shift; |
|
57 |
|
58 #remove the / from mrpname |
|
59 $self->{mrpName} =~ s/^[\\\/]//; |
|
60 |
|
61 # Lowercase the MRP name so that the case is consistent when checking the cache |
|
62 my $lcMrpName = lc ($self->{mrpName}); |
|
63 |
|
64 if ($cache->{$lcMrpName}) { |
|
65 $cache->{$lcMrpName}->{ver} = $self->{ver} if ($self->{ver}); |
|
66 $cache->{$lcMrpName}->{intVer} = $self->{intVer} if ($self->{intVer}); |
|
67 return $cache->{$lcMrpName}; |
|
68 } |
|
69 |
|
70 $cache->{$lcMrpName} = $self; |
|
71 |
|
72 if (!$doNotRead) { |
|
73 $self->ReadMrp(); |
|
74 } |
|
75 |
|
76 return $self; |
|
77 } |
|
78 |
|
79 sub Populated { |
|
80 my $self = shift; |
|
81 |
|
82 return $self->{populated}; |
|
83 } |
|
84 |
|
85 |
|
86 sub ExpandMrpName { |
|
87 my $self = shift; |
|
88 |
|
89 unless ($self->{mrpName} =~ /.mrp$/i) { |
|
90 $self->{mrpName} .= '.mrp'; |
|
91 } |
|
92 } |
|
93 |
|
94 sub Component { |
|
95 my $self = shift; |
|
96 unless (exists $self->{comp}) { |
|
97 die "Error: Component name not found in mrp\n"; |
|
98 } |
|
99 return $self->{comp}; |
|
100 } |
|
101 |
|
102 sub MrpName { |
|
103 my $self = shift; |
|
104 return $self->{mrpName}; |
|
105 } |
|
106 |
|
107 sub ExternalVersion { |
|
108 my $self = shift; |
|
109 return $self->{ver}; |
|
110 } |
|
111 |
|
112 sub InternalVersion { |
|
113 my $self = shift; |
|
114 return $self->{intVer}; |
|
115 } |
|
116 |
|
117 sub NotesSource { |
|
118 my $self = shift; |
|
119 unless (exists $self->{notes_src}) { |
|
120 die "Error: Notes source not found in mrp for $self->{comp}\n"; |
|
121 } |
|
122 return $self->{notes_src}; |
|
123 } |
|
124 |
|
125 sub ClassifySource { |
|
126 my $self = shift; |
|
127 return if defined $self->{src}; |
|
128 |
|
129 foreach my $item (keys %{$self->{srcitems}}) { |
|
130 if (-d Utils::PrependSourceRoot($item)) { |
|
131 $self->HandleSourceDir($item); |
|
132 } |
|
133 elsif (-f Utils::PrependSourceRoot($item)) { |
|
134 $self->HandleSourceFile($item); |
|
135 } |
|
136 else { |
|
137 die "Error: \"$item\" is not a file or directory in $self->{mrpName}\n"; |
|
138 } |
|
139 } |
|
140 } |
|
141 |
|
142 sub SourceCategories { |
|
143 my $self = shift; |
|
144 $self->ClassifySource(); |
|
145 if (defined $self->{src}) { |
|
146 my @categories = keys %{$self->{src}}; |
|
147 return \@categories; |
|
148 } |
|
149 return []; |
|
150 } |
|
151 |
|
152 sub Source { |
|
153 my $self = shift; |
|
154 my $category = uc(shift); |
|
155 $self->ClassifySource(); |
|
156 unless (defined $category) { |
|
157 $category = 'unfiltered'; |
|
158 } |
|
159 if (defined $self->{src}->{$category}) { |
|
160 return $self->{src}->{$category}; |
|
161 } |
|
162 return []; |
|
163 } |
|
164 |
|
165 sub SourceFilterErrors { |
|
166 my $self = shift; |
|
167 $self->ClassifySource(); |
|
168 if (defined $self->{sourceFilterErrors}) { |
|
169 return $self->{sourceFilterErrors}; |
|
170 } |
|
171 return []; |
|
172 } |
|
173 |
|
174 sub BinaryCategories { |
|
175 my $self = shift; |
|
176 |
|
177 $self->ProcessBinaries(); |
|
178 |
|
179 if ($self->{bins}) { |
|
180 my @categories = sort keys %{$self->{bins}}; |
|
181 return \@categories; |
|
182 } |
|
183 return []; |
|
184 } |
|
185 |
|
186 sub Binaries { |
|
187 my $self = shift; |
|
188 my $category = shift; |
|
189 |
|
190 $self->ProcessBinaries(); |
|
191 |
|
192 my @binList = (); |
|
193 if ($category) { |
|
194 die unless (exists $self->{bins}->{$category}); |
|
195 foreach my $thisBin (sort keys %{$self->{bins}->{$category}}) { |
|
196 push (@binList, $self->{bins}->{$category}->{$thisBin}); |
|
197 } |
|
198 } |
|
199 else { |
|
200 foreach my $thisCategory (@{$self->BinaryCategories()}) { |
|
201 push (@binList, @{$self->Binaries($thisCategory)}); |
|
202 } |
|
203 } |
|
204 return \@binList; |
|
205 } |
|
206 |
|
207 sub ExportCategories { |
|
208 my $self = shift; |
|
209 if ($self->{iniData}->CategoriseExports()) { |
|
210 $self->ProcessExports(); |
|
211 if ($self->{exports}) { |
|
212 my @categories = sort keys %{$self->{exports}}; |
|
213 return \@categories; |
|
214 } |
|
215 } |
|
216 return []; |
|
217 } |
|
218 |
|
219 sub Exports { |
|
220 my $self = shift; |
|
221 my $category = uc(shift); |
|
222 |
|
223 $self->ProcessExports(); |
|
224 |
|
225 my @exportList = (); |
|
226 if ($self->{iniData}->CategoriseExports()) { |
|
227 if ($category) { |
|
228 die unless (exists $self->{exports}->{$category}); |
|
229 push (@exportList, @{$self->{exports}->{$category}}); |
|
230 } |
|
231 else { |
|
232 foreach my $thisCategory (@{$self->ExportCategories()}) { |
|
233 push (@exportList, @{$self->Exports($thisCategory)}); |
|
234 } |
|
235 } |
|
236 } |
|
237 elsif ($category) { |
|
238 die; # There are never any export categories if export categorisation is not enabled. Caller didn't call ExportCategories prior to this. |
|
239 } |
|
240 return \@exportList; |
|
241 } |
|
242 |
|
243 |
|
244 sub ClassifyAutomaticExports { |
|
245 # Classify exports that were specified using the 'exports' keyword. |
|
246 # |
|
247 # This is a bit ugly. The problem's root is that it's not possible to ask the build tools where exports originated |
|
248 # from. This information is needed to be able to categorise exports. To get it, the release tools therefore have |
|
249 # to go 'under the hood' of the build tools. Yuk! |
|
250 # |
|
251 # Implementation choices were a) Parse bld.inf files, and b) Parse the generated export makefiles. Option (b) was |
|
252 # chosen because bld.infs are notoriously difficult to robustly parse. |
|
253 |
|
254 my $self = shift; |
|
255 if (exists $self->{exports}->{automatic}) { # Only perform the classification if we haven't already done it. |
|
256 foreach my $thisAbldPath (@{$self->{exports}->{abldPaths}}) { |
|
257 $thisAbldPath = Utils::PrependSourceRoot($thisAbldPath); |
|
258 # Scan the makefile looking for the exports we're expecting (from invoking 'abld -w exports' in HandleExports). |
|
259 |
|
260 my $exportMakeFile; |
|
261 my $testExportMakeFile; |
|
262 $self->ExportMakeFile($thisAbldPath, \$exportMakeFile, \$testExportMakeFile); |
|
263 |
|
264 if ($exportMakeFile){ |
|
265 $self->ProcessExportMakeFile($exportMakeFile, $thisAbldPath); |
|
266 |
|
267 } |
|
268 if ($testExportMakeFile){ |
|
269 $self->ProcessExportMakeFile($testExportMakeFile, $thisAbldPath); |
|
270 } |
|
271 } |
|
272 |
|
273 } |
|
274 |
|
275 if (scalar(keys %{$self->{exports}->{automatic}}) > 0) { |
|
276 foreach my $unprocessed_export (keys %{$self->{exports}->{automatic}}) |
|
277 { |
|
278 print "UNPROCESSED EXPORT: $unprocessed_export\n"; |
|
279 } |
|
280 |
|
281 die "Error: Problem extracting export IPR categories for \"$self->{mrpName}\"\n"; |
|
282 } |
|
283 |
|
284 delete $self->{exports}->{automatic}; |
|
285 delete $self->{exports}->{abldPaths}; |
|
286 } |
|
287 |
|
288 sub ProcessExportMakeFile { |
|
289 my $self = shift; |
|
290 my $exportMakeFile = shift; |
|
291 my $abldPath = shift; |
|
292 my $errors = 0; |
|
293 open (MAKEFILE, $exportMakeFile) or die "Error: Couldn't open \"$exportMakeFile\": $!\n"; |
|
294 while (my $line = <MAKEFILE>) { |
|
295 $line =~ s/\\ / /g; # Get rid of escaped spaces. |
|
296 if ($line =~ /^(.*)\s+:\s+(.*)/) { |
|
297 # Found a possibility - need to see if it's one of the exports we're looking for. |
|
298 my $destination = $1; |
|
299 my $source = $2; |
|
300 if (Utils::WithinEpocRoot($destination)) { |
|
301 $destination = Utils::RemoveEpocRoot($destination); |
|
302 } |
|
303 if (exists $self->{exports}->{automatic}->{lc($destination)}) { |
|
304 $source = Utils::RemoveSourceRoot($source); |
|
305 # Add to exports to be processed - source and destination |
|
306 push @{$self->{exportsToBeProcessed}}, {source => $source, |
|
307 destination => $destination, |
|
308 abldPath => $abldPath}; |
|
309 |
|
310 delete $self->{exports}->{automatic}->{lc($destination)}; |
|
311 } |
|
312 } |
|
313 elsif ($line =~ /unzip\s+-u\s+-o\s+(.*)\s+-d\s+\"(.*)\"/) { |
|
314 # Looks like a zip file being exported - check contents. |
|
315 my $zipFileName = $1; |
|
316 my $destinationDir = $2; |
|
317 my $zipContents = Utils::ListZip($zipFileName); |
|
318 $zipFileName = Utils::RemoveSourceRoot($zipFileName); |
|
319 foreach my $thisExport (@$zipContents) { |
|
320 $thisExport = Utils::ConcatenateDirNames($destinationDir, $thisExport); |
|
321 if (Utils::WithinEpocRoot($thisExport)) { |
|
322 $thisExport = Utils::RemoveEpocRoot($thisExport); |
|
323 } |
|
324 if (exists $self->{exports}->{automatic}->{lc($thisExport)}) { |
|
325 # Add to exports to be processed - source and destination |
|
326 push @{$self->{exportsToBeProcessed}}, {source => $zipFileName, |
|
327 destination => $thisExport, |
|
328 abldPath => $abldPath}; |
|
329 |
|
330 delete $self->{exports}->{automatic}->{lc($thisExport)}; |
|
331 } |
|
332 } |
|
333 } |
|
334 } |
|
335 close (MAKEFILE); |
|
336 } |
|
337 |
|
338 sub ExportMakeFile { |
|
339 # Invoke 'bldmake bldfiles -v' to find the full path to the EXPORT.MAKE file. |
|
340 my $self = shift; |
|
341 my $abldPath = shift; |
|
342 my $exportMakeFileRef = shift; |
|
343 my $testExportMakeFileRef = shift; |
|
344 my $cwd = cwd(); |
|
345 my $last = 0; |
|
346 chdir $abldPath or die "Error: Couldn't change working directory to \"$abldPath\": $!\n"; |
|
347 open (BLDMAKE, 'bldmake bldfiles -v |') or die "Error: Couldn't run \"bldmake bldfiles -v |\" in \"abldPath\": $!\n"; |
|
348 my $exportMakeFile; |
|
349 my $testExportMakeFile; |
|
350 while (my $line = <BLDMAKE>) { |
|
351 if ($line =~ /Creating \"(.*EXPORT.MAKE)\"/) { |
|
352 $exportMakeFile = $1; |
|
353 if ($last == 1){ # found both EXPORT.MAKE and EXPORTTEST.MAKE |
|
354 last; |
|
355 } |
|
356 $last = 1; |
|
357 } |
|
358 elsif ($line =~ /Creating \"(.*EXPORTTEST.MAKE)\"/) { |
|
359 $testExportMakeFile = $1; |
|
360 if ($last == 1){ # found both EXPORT.MAKE and EXPORTTEST.MAKE |
|
361 last; |
|
362 } |
|
363 $last = 1; |
|
364 } |
|
365 } |
|
366 close (BLDMAKE); |
|
367 chdir $cwd or die "Error: Couldn't change working directory to \"$cwd\": $!\n"; |
|
368 unless ($exportMakeFile || $testExportMakeFile) { |
|
369 die "Error: Unable to find \"EXPORT.MAKE\" or \"EXPORTTEST.MAKE\" for \"$abldPath\"\n"; |
|
370 } |
|
371 $$exportMakeFileRef = $exportMakeFile; |
|
372 $$testExportMakeFileRef = $testExportMakeFile; |
|
373 } |
|
374 |
|
375 sub ClassifyManualExports { |
|
376 my $self = shift; |
|
377 if (exists $self->{exports}->{manual}) { # Only perform the classification if we haven't already done it. |
|
378 foreach my $thisSource (keys %{$self->{exports}->{manual}}) { |
|
379 push @{$self->{exportsToBeProcessed}}, {source => $thisSource, |
|
380 destination => $self->{exports}->{manual}->{$thisSource}}; |
|
381 } |
|
382 delete $self->{exports}->{manual}; |
|
383 } |
|
384 } |
|
385 |
|
386 sub ExportInfoForCat { |
|
387 my $self = shift; |
|
388 my $category = uc(shift); |
|
389 |
|
390 $self->ProcessExports(); |
|
391 |
|
392 return $self->{exportinfo}->{$category}; |
|
393 } |
|
394 |
|
395 sub ExportSourceFileInfoForCat { |
|
396 my $self = shift; |
|
397 my $category = uc(shift); |
|
398 my $exportfile = shift; |
|
399 |
|
400 # In AddExport $category is called $class and $exportfile is $destination |
|
401 return $self->{exportinfo}->{$category}->{$exportfile}; |
|
402 } |
|
403 |
|
404 sub AddExport { |
|
405 my $self = shift; |
|
406 my $source = shift; |
|
407 my $destination = shift; |
|
408 my $successfullyAdded = 0; |
|
409 |
|
410 my ($class) = Utils::ClassifyPath($self->{iniData}, $source, $self->{verbose}, 0, $self->Component()); |
|
411 $class = uc($class); |
|
412 |
|
413 if ($class) { |
|
414 $successfullyAdded = 1; |
|
415 push (@{$self->{exports}->{$class}}, $destination); |
|
416 } |
|
417 else { |
|
418 print "Error: Can't find IPR category for export \"$destination\" in \"$self->{mrpName}\" |
|
419 It should correspond to source file \"$source\"\n"; |
|
420 } |
|
421 |
|
422 # Need to record the src paths. |
|
423 $self->{exportinfo}->{$class}->{$destination} = $source; |
|
424 |
|
425 return $successfullyAdded; |
|
426 } |
|
427 |
|
428 sub BinariesAndExports { |
|
429 my $self = shift; |
|
430 # Exports need to be processed first. If exports are not to be categorised then |
|
431 # they are treated as binary files. |
|
432 my $list = $self->Exports(); |
|
433 push (@$list, @{$self->Binaries()}); |
|
434 return $list; |
|
435 } |
|
436 |
|
437 sub SourceItems { |
|
438 my $self = shift; |
|
439 return $self->{srcitems}; |
|
440 } |
|
441 |
|
442 sub ReadMrp { |
|
443 my $self = shift; |
|
444 my $mrpName = $self->{mrpName}; |
|
445 my $cwd = cwd(); |
|
446 # If there are mappings and the source root is \\, perform mappings on filename. Otherwise prepend source root. |
|
447 if($self->{iniData}->HasMappings() && Utils::SourceRoot() eq "\\") { |
|
448 $mrpName = $self->{iniData}->PerformMapOnFileName($mrpName); |
|
449 } |
|
450 else{ |
|
451 $mrpName = Utils::PrependSourceRoot($mrpName); |
|
452 } |
|
453 |
|
454 my $mrpDir = dirname($mrpName); |
|
455 |
|
456 chdir($mrpDir) or die "Error: Couldn't change working directory to \"$mrpDir\": $!\n"; |
|
457 |
|
458 my $reader = Symbian::CBR::MRP::Reader->instance(); |
|
459 $reader->SetVerbose() if ($self->{verbose}); |
|
460 |
|
461 $reader->ReadFile($mrpName, 'MRPDATA'); |
|
462 |
|
463 chdir($cwd) or die "Error: Couldn't change working directory back to \"$cwd\": $!\n"; |
|
464 if ($@) { |
|
465 die $@; |
|
466 } |
|
467 } |
|
468 |
|
469 |
|
470 sub HandleSourceFile { |
|
471 my $self = shift; |
|
472 my $srcFile = shift; |
|
473 |
|
474 my $logErrors = !$self->{iniData}->IgnoreSourceFilterErrors(); |
|
475 my ($cat, $errors) = Utils::ClassifyPath($self->{iniData}, $srcFile, $self->{verbose}, $logErrors, $self->Component()); |
|
476 |
|
477 if ($self->{verbose}) { |
|
478 print "Handling source file $srcFile...\n"; |
|
479 } |
|
480 |
|
481 push @{$self->{sourceFilterErrors}}, @$errors if @$errors; |
|
482 push @{$self->{src}->{uc($cat)}}, $srcFile; |
|
483 } |
|
484 |
|
485 sub HandleSourceDir { |
|
486 my $self = shift; |
|
487 my $srcDir = Utils::PrependSourceRoot(shift); |
|
488 |
|
489 if ($self->{verbose}) { |
|
490 print "Filtering source directory $srcDir into categories...\n"; |
|
491 } |
|
492 |
|
493 # Create function to handle files in a directory ($File::Find::dir) |
|
494 # Takes: List of items (files and dirs) in the directory |
|
495 my $dirhandler = sub { |
|
496 my @entries = @_; |
|
497 my $hasdistpol = scalar(grep(lc($_) eq "distribution.policy", @entries)); |
|
498 |
|
499 @entries = grep(lc($_) ne "distribution.policy", @entries); # remove distribution.policy entries |
|
500 |
|
501 foreach my $entry (@entries) { |
|
502 if (Utils::CheckForUnicodeCharacters($entry)) { |
|
503 die "Error: \"$File::Find::dir\\$entry\" contains unicode characters, which are incompatible with the CBR Tools. This file can not be included in this release.\n"; |
|
504 } |
|
505 } |
|
506 |
|
507 my @files = grep(-f File::Spec->catfile($File::Find::dir,$_), @entries); |
|
508 |
|
509 # Remove the abld entries from the source |
|
510 $self->RemoveAbldFromSource($File::Find::dir, \@files); |
|
511 |
|
512 if (scalar(@files) > 0) { |
|
513 |
|
514 # Tag all the entries in this directory with that category |
|
515 foreach my $entry (@files) { |
|
516 next if $entry =~ /^\.\.?$/; # Skip . and .. |
|
517 my $entry = File::Spec->catfile($File::Find::dir, $entry); |
|
518 Utils::TidyFileName(\$entry); |
|
519 |
|
520 $entry = Utils::RemoveSourceRoot($entry); # remove source root path or it will be added twice! |
|
521 my ($category, $errors) = Utils::ClassifyPath($self->{iniData}, $entry, $self->{verbose}, $self->{iniData}->IgnoreSourceFilterErrors(), $self->Component()); |
|
522 push @{$self->{sourceFilterErrors}}, @$errors; # There will be no errors in @$errors if IgnoreSourceFilterErrors was set |
|
523 |
|
524 # (Optionally) guard against unclassified source |
|
525 if (lc($category) eq "x" and $self->{iniData}->DisallowUnclassifiedSource()) { |
|
526 die "Error: \"$File::Find::dir\" contains unclassified source code\n"; |
|
527 } |
|
528 |
|
529 push @{$self->{src}->{uc($category)}}, $entry; |
|
530 } |
|
531 } else { |
|
532 # There are no files to categorise here |
|
533 if (($hasdistpol) and (!($self->{iniData}->IgnoreSourceFilterErrors()))) { |
|
534 push @{$self->{sourceFilterErrors}}, "Note: unnecessary policy file in $File::Find::dir\n"; |
|
535 } |
|
536 } |
|
537 |
|
538 # Return full list of entries to continue scan |
|
539 return @entries; |
|
540 }; |
|
541 |
|
542 # Traverse the directory tree in $srcDir calling &$dirhandler on all directories |
|
543 find({"wanted"=>sub{}, "preprocess"=>$dirhandler, "no_chdir" => 1}, $srcDir); |
|
544 } |
|
545 |
|
546 sub RemoveAbldFromSource { |
|
547 my $self = shift; |
|
548 my $dir = shift; |
|
549 my $files = shift; |
|
550 |
|
551 $dir = File::Spec->canonpath($dir); |
|
552 |
|
553 foreach my $entry (@{$self->{binaryStatements}}, @{$self->{exportsStatements}}) { |
|
554 if ($entry->{abldPath} eq $dir) { |
|
555 @$files = grep $_ !~ /abld.bat/i, @$files; |
|
556 return; |
|
557 } |
|
558 } |
|
559 } |
|
560 |
|
561 sub HandleBinDirOrFile { |
|
562 my $self = shift; |
|
563 my $remove = shift; |
|
564 my $category = shift; |
|
565 my $file = shift; |
|
566 my $successRef = shift; |
|
567 |
|
568 if (-d $file) { |
|
569 $self->HandleBinDir($remove, $category, $file, $successRef); |
|
570 } |
|
571 elsif ($file) { |
|
572 $self->HandleBinFile($remove, $category, $file, $successRef); |
|
573 } |
|
574 } |
|
575 |
|
576 sub HandleBinFile { |
|
577 my $self = shift; |
|
578 my $remove = shift; |
|
579 my $category = shift; |
|
580 my $file = Utils::RemoveEpocRoot(shift); |
|
581 my $successRef = shift; |
|
582 |
|
583 my $lcFile = lc($file); # Note, duplicate check is performed on lower case file name. Original case is preserved within the hash. |
|
584 Utils::TidyFileName(\$file); |
|
585 |
|
586 die "No category was provided" unless $category; |
|
587 |
|
588 if ($remove) { |
|
589 foreach my $thisClassification (keys %{$self->{bins}}) { |
|
590 if (exists $self->{bins}->{$thisClassification}->{$lcFile}) { |
|
591 if ($self->{verbose} > 1) { print "Excluding binary file \"$file\" from $thisClassification...\n"; } |
|
592 delete $self->{bins}->{$thisClassification}->{$lcFile}; |
|
593 $$successRef = 1; |
|
594 } |
|
595 } |
|
596 } |
|
597 else { |
|
598 unless ($self->IsDuplicateBin($file)) { |
|
599 if ($self->{verbose} > 1) { print "Adding binary file \"$file\" to category $category...\n"; } |
|
600 $self->{bins}->{$category}->{$lcFile} = $file; |
|
601 $$successRef = 1; |
|
602 } |
|
603 } |
|
604 |
|
605 } |
|
606 |
|
607 |
|
608 sub HandleBinDir { |
|
609 my $self = shift; |
|
610 my $remove = shift; |
|
611 my $category = shift; |
|
612 my $binDir = shift; |
|
613 my $successRef = shift; |
|
614 |
|
615 find($self->ProcessBinFile($remove, $category, $successRef), $binDir); |
|
616 } |
|
617 |
|
618 sub ProcessBinFile { |
|
619 my $self = shift; |
|
620 my $remove = shift; |
|
621 my $category = shift; |
|
622 my $successRef = shift; |
|
623 return sub { |
|
624 my $file = $File::Find::name; |
|
625 |
|
626 if (Utils::CheckForUnicodeCharacters($file)) { |
|
627 die "Error: \"$file\" contains unicode characters, which are incompatible with the CBR Tools. This file can not be included in this release.\n"; |
|
628 } |
|
629 |
|
630 if (-f $file) { |
|
631 Utils::TidyFileName(\$file); |
|
632 $self->HandleBinFile($remove, $category, $file, $successRef); |
|
633 } |
|
634 } |
|
635 } |
|
636 |
|
637 sub IsDuplicateBin { |
|
638 my $self = shift; |
|
639 my $fileName = shift; |
|
640 my $fileNameLc = lc ($fileName); |
|
641 |
|
642 my $duplicate = 0; |
|
643 foreach my $thisCategory (keys %{$self->{bins}}) { |
|
644 if (exists $self->{bins}->{$thisCategory}->{$fileNameLc}) { |
|
645 # This file has already been handled once, so it must be a duplicate. |
|
646 # Therefore move it to the 'unclassified' category to ensure it doesn't get released twice. |
|
647 if ($thisCategory ne 'unclassified') { |
|
648 if ($self->{verbose} > 1) { |
|
649 print "Moving binary file \"$fileName\" to from category $thisCategory to 'unclassified'...\n"; |
|
650 } |
|
651 $self->{bins}->{unclassified}->{$fileNameLc} = $fileName; |
|
652 delete $self->{bins}->{$thisCategory}->{$fileNameLc}; |
|
653 } |
|
654 $duplicate = 1; |
|
655 last; |
|
656 } |
|
657 } |
|
658 |
|
659 return $duplicate; |
|
660 } |
|
661 |
|
662 sub HandleBinSet { |
|
663 my $self = shift; |
|
664 my $remove = shift; |
|
665 my $test = shift; |
|
666 if ($test) { |
|
667 $test = 'test'; |
|
668 } |
|
669 else { |
|
670 $test = ''; |
|
671 } |
|
672 my $successRef = shift; |
|
673 my $abldPath = shift; |
|
674 $abldPath = SourceRootPath($abldPath); |
|
675 my $plat = shift; |
|
676 my $var = ''; |
|
677 if ($_[0] and $_[0] =~ /(u?(?:deb|rel))/i) { |
|
678 $var = shift; |
|
679 } |
|
680 my $mmp = shift; |
|
681 unless ($mmp) { |
|
682 $mmp = ''; |
|
683 } |
|
684 |
|
685 $self->ProcessCache($abldPath, $test) if (!exists($self->{abldcache}->{loaded}->{$abldPath})); |
|
686 |
|
687 my $plats = $self->ResolveAlias($abldPath, $plat); |
|
688 my $vars; |
|
689 foreach $plat (@$plats) { |
|
690 if ($var) { |
|
691 $vars = [$var]; |
|
692 } elsif ($plat =~ /^tools2?$/i) { |
|
693 # Hard-coded and nasty |
|
694 $vars = [ 'deb', 'rel' ]; |
|
695 } else { |
|
696 $vars = [ 'udeb', 'urel' ]; |
|
697 } |
|
698 foreach $var (@$vars) { |
|
699 push @{$self->{binsets}}, { |
|
700 path => Utils::RemoveSourceRoot($abldPath), |
|
701 plat => $plat, |
|
702 var => $var, |
|
703 mmp => $mmp, |
|
704 test => $test |
|
705 } unless ($remove); |
|
706 |
|
707 $self->ReadBinaries($abldPath, $test, $plat, $var, $mmp, $remove, $successRef); |
|
708 } |
|
709 } |
|
710 } |
|
711 |
|
712 |
|
713 sub ProcessCache { |
|
714 my $self = shift; |
|
715 my $abldPath = shift; |
|
716 my $test = shift; |
|
717 |
|
718 $self->CheckBuildSystem($abldPath) if(!$self->{buildSystem}); |
|
719 |
|
720 if($self->{buildSystem} == 2){ |
|
721 print "current build system is Raptor...\n" if ($self->{verbose}); |
|
722 $self->ProcessRaptorCache($abldPath, $test); |
|
723 } |
|
724 else{ |
|
725 print "current build system is Abld...\n" if ($self->{verbose}); |
|
726 $self->ProcessAbldCache($abldPath); |
|
727 } |
|
728 } |
|
729 |
|
730 #check which build system would be using |
|
731 sub CheckBuildSystem { |
|
732 my $self = shift; |
|
733 my $abldPath = shift; |
|
734 my $buildSystem = $self->{iniData}->BuildSystemVersion($self->{verbose}); |
|
735 |
|
736 if($buildSystem eq "1") { |
|
737 if ($self->AbldAvailable($abldPath)){ |
|
738 $self->{buildSystem} = 1; |
|
739 } |
|
740 else{ |
|
741 die "Abld build system isn't available.\n"; |
|
742 } |
|
743 } |
|
744 else{ |
|
745 if($buildSystem ne "2") { |
|
746 print "Warning: the value of build system is neither 1 nor 2 so we try to use Raptor.\n" if ($self->{verbose}); |
|
747 } |
|
748 |
|
749 if ($self->RaptorAvailable()){ |
|
750 $self->{buildSystem} = 2; |
|
751 } |
|
752 elsif($buildSystem ne "2") { |
|
753 print "Warning: Raptor is not available and we try to use Abld.\n" if ($self->{verbose}); |
|
754 |
|
755 if ($self->AbldAvailable($abldPath)){ |
|
756 $self->{buildSystem} = 1; |
|
757 } |
|
758 else{ |
|
759 die "Neither Abld nor Raptor is available.\n"; |
|
760 } |
|
761 } |
|
762 else{ |
|
763 die "Raptor build system is not available.\n"; |
|
764 } |
|
765 } |
|
766 } |
|
767 |
|
768 sub ProcessAbldCache { |
|
769 my $self = shift; |
|
770 my $abldPath = shift; |
|
771 if (exists $ENV{ABLDCACHE}) { |
|
772 $self->{abldcache}->{loaded}->{$abldPath}= 1; |
|
773 my $cachefile=File::Spec->catdir($ENV{ABLDCACHE},$abldPath,"cache"); |
|
774 if (-f $cachefile) { |
|
775 print "Reading ABLD Cache from $cachefile\n" if ($self->{verbose}); |
|
776 |
|
777 open(CACHE, $cachefile) or die "Couldn't open abld cache data file '$cachefile'\n"; |
|
778 my @cache = <CACHE>; |
|
779 close(CACHE); |
|
780 eval (join("",@cache)) or die "Error: Couldn't parse abld cache data in '$cachefile': $@\n"; |
|
781 } |
|
782 } |
|
783 } |
|
784 |
|
785 sub ProcessRaptorCache { |
|
786 my $self = shift; |
|
787 my $abldPath = shift; |
|
788 my $test = shift; |
|
789 |
|
790 my $cwd = cwd(); |
|
791 my $driver = $cwd; |
|
792 $driver =~ /^(.:)(.*)/; |
|
793 $driver = $1."\\raptorcache"; |
|
794 my $logfile = File::Spec->catdir($driver.$abldPath,"info.xml"); |
|
795 if(! -f $logfile){ |
|
796 my $makefile = File::Spec->catdir($driver.$abldPath,"Makefile"); |
|
797 print "execute SBS to create Raptor XML log file: $logfile\n" if($self->{verbose}); |
|
798 chdir $abldPath or die "Error: Couldn't change working directory to \"$abldPath\": $!\n"; |
|
799 my $cmd = $self->RaptorLogCmd($abldPath, $logfile, $makefile, $test); |
|
800 open (SBS, $cmd) or die "Error: Couldn't run \"$cmd\" in \"$abldPath\": $!\n"; |
|
801 my $foundLog; |
|
802 my $errmsg; |
|
803 while (my $line = <SBS>) { |
|
804 $errmsg = $1 if ($line =~ /sbs : errors: (\d+)/ and $1 > 0); |
|
805 $foundLog = 1 if ($line =~ /sbs: build log in (\w+)/); |
|
806 } |
|
807 close (SBS); |
|
808 |
|
809 if($errmsg){ |
|
810 my $trycount = 50; |
|
811 my $errtag = 0; |
|
812 while($trycount > 0){ |
|
813 print "try to run sbs again: $trycount\n"; |
|
814 open (SBS, $cmd) or die "Error: Couldn't run \"$cmd\" in \"$abldPath\": $!\n"; |
|
815 $errtag = 0; |
|
816 while (my $line = <SBS>) { |
|
817 if ($line =~ /sbs : errors: (\d+)/ and $1 > 0){ |
|
818 $errtag = 1; |
|
819 $trycount = $trycount - 1; |
|
820 } |
|
821 $foundLog = 1 if ($line =~ /sbs: build log in (\w+)/); |
|
822 } |
|
823 $trycount =0 if($errtag < 1); |
|
824 close (SBS); |
|
825 } |
|
826 if($errtag == 1 and $trycount == 0) { |
|
827 die "SBS Error: Couldn't run \"$cmd\" in \"$abldPath\"\n"; |
|
828 } |
|
829 } |
|
830 chdir $cwd or die "Error: Couldn't change working directory to \"$cwd\": $!\n"; |
|
831 unless ($foundLog) { |
|
832 die "Error: Unable to execute \"SBS\" in \"$abldPath\"\n"; |
|
833 } |
|
834 } |
|
835 |
|
836 $self->ParseRaptorXmlLog($logfile); |
|
837 $self->PrintCache() if($self->{verbose}); |
|
838 $self->{abldcache}->{loaded}->{$abldPath}= 1; |
|
839 print "cache is generated successfully\n" if($self->{verbose}); |
|
840 } |
|
841 |
|
842 sub RaptorLogCmd { |
|
843 my $self = shift; |
|
844 my $abldPath = shift; |
|
845 my $logfile = shift; |
|
846 my $makefile = shift; |
|
847 my $test = shift; |
|
848 if ($test) { |
|
849 $test = 'test'; |
|
850 } |
|
851 else { |
|
852 $test = ''; |
|
853 } |
|
854 |
|
855 my $plat = "all"; |
|
856 my $iniAll = $self->{iniData}->TargetPlatforms($plat); |
|
857 my $cmd = "SBS -b bld.inf -m $makefile -f $logfile -c default"; |
|
858 $cmd = $cmd." -c default.test" if ($test ne ''); |
|
859 foreach my $e (@$iniAll) { |
|
860 $cmd = $cmd." -c tools_rel -c tools_deb" if ($e eq "TOOLS"); |
|
861 $cmd = $cmd." -c tools2_rel -c tools2_deb" if ($e eq "TOOLS2"); |
|
862 $cmd = $cmd." -c armv5.smp" if ($e eq "ARMV5SMP"); |
|
863 } |
|
864 $cmd = $cmd." WHAT |"; |
|
865 print "Raptor command: $cmd\n"; |
|
866 return $cmd; |
|
867 } |
|
868 |
|
869 #check whether Abld build system is available |
|
870 sub AbldAvailable { |
|
871 my $self = shift; |
|
872 my $abldPath = shift; |
|
873 my $path = File::Spec->catdir($abldPath,""); |
|
874 my $foundPlats = 0; |
|
875 |
|
876 my $cwd = cwd(); |
|
877 chdir $abldPath or die "Error: Couldn't change working directory to \"$abldPath\": $!\n"; |
|
878 open (BLDMAKE, "bldmake bldfiles |") or die "Error: Couldn't run \"bldmake bldfiles\" in \"$abldPath\": $!\n"; |
|
879 while (my $line = <BLDMAKE>) { |
|
880 chomp $line; |
|
881 } |
|
882 close(BLDMAKE); |
|
883 |
|
884 open (ABLD, "abld help |") or die "Error: Couldn't run \"abld help\" in \"$abldPath\": $!\n"; |
|
885 while (my $line = <ABLD>) { |
|
886 chomp $line; |
|
887 $foundPlats = 1 if ($line =~ /project platforms:/); |
|
888 } |
|
889 close (ABLD); |
|
890 chdir $cwd or die "Error: Couldn't change working directory to \"$cwd\": $!\n"; |
|
891 |
|
892 return $foundPlats; |
|
893 } |
|
894 |
|
895 #check whether Raptor build system is available |
|
896 sub RaptorAvailable { |
|
897 my $self = shift; |
|
898 my $maxver = 0; |
|
899 my $midver = 0; |
|
900 my $minver = 0; |
|
901 |
|
902 return 0 if(!-f "\\epoc32\\data\\buildinfo.txt" and !-f "\\epoc32\\data\\kif.xml"); |
|
903 |
|
904 open (SBS, "sbs -version |") or die "Error: Couldn't run \"sbs -version\": $!\n"; |
|
905 while (my $line = <SBS>) { |
|
906 chomp $line; |
|
907 if ($line =~ /^sbs version (\d+)\.(\d+)\.(\d+)/){ |
|
908 $maxver = $1; |
|
909 $midver = $2; |
|
910 $minver = $3; |
|
911 } |
|
912 } |
|
913 close (SBS); |
|
914 if ($maxver == 0 and $midver == 0 and $minver == 0) { |
|
915 return 0; |
|
916 } |
|
917 elsif ($maxver < 2 or ($maxver == 2 and $midver < 7)) { |
|
918 die "Error: Raptor build system version must be 2.7.0 or higher.\n"; |
|
919 } |
|
920 return 1; |
|
921 } |
|
922 |
|
923 sub ParseRaptorXmlLog { |
|
924 my $self = shift; |
|
925 my $xmlfile = shift; |
|
926 |
|
927 my $xmldata; |
|
928 my $trycount = 20; |
|
929 |
|
930 while ($trycount > 0) { |
|
931 eval { |
|
932 $xmldata = XMLin($xmlfile); |
|
933 }; |
|
934 if ($@) { |
|
935 $trycount = $trycount - 1; |
|
936 print "Try to open raptor log file [$trycount]: $xmlfile\n"; |
|
937 } |
|
938 else{ |
|
939 $trycount = 0; |
|
940 } |
|
941 } |
|
942 |
|
943 my $whatLogElements = $self->WrapVarToArray($xmldata->{whatlog}); |
|
944 foreach my $whatLogElement (@$whatLogElements) { |
|
945 $self->ProcessWhatLogElement($whatLogElement); |
|
946 } |
|
947 |
|
948 foreach my $param (keys %{$self->{abldcache}->{exports}}) { |
|
949 foreach my $destination (keys %{$self->{abldcache}->{exports}->{$param}}) { |
|
950 push @{$self->{abldcache}->{$param}}, [$destination, $self->{abldcache}->{exports}->{$param}->{$destination}]; |
|
951 } |
|
952 } |
|
953 delete $self->{abldcache}->{exports}; |
|
954 |
|
955 foreach my $param (keys %{$self->{abldcache}->{builds}}) { |
|
956 foreach my $buildItem (keys %{$self->{abldcache}->{builds}->{$param}}) { |
|
957 push @{$self->{abldcache}->{$param}}, $buildItem; |
|
958 } |
|
959 } |
|
960 delete $self->{abldcache}->{builds}; |
|
961 |
|
962 foreach my $platform (keys %{$self->{abldcache}->{platforms}}) { |
|
963 push @{$self->{abldcache}->{plats}}, uc($platform); |
|
964 } |
|
965 delete $self->{abldcache}->{platforms}; |
|
966 } |
|
967 |
|
968 sub ProcessWhatLogElement { |
|
969 my $self = shift; |
|
970 my $aWhatLogElement = shift; |
|
971 |
|
972 my $bldinf = $aWhatLogElement->{bldinf}; |
|
973 my $bldinfDir = $bldinf; |
|
974 $bldinfDir =~ s/\//\\/g; |
|
975 $bldinfDir =~ /^.:(.+)\\(.*)/; |
|
976 $bldinfDir = $1; |
|
977 |
|
978 my $mmp = $aWhatLogElement->{mmp}; |
|
979 my $config = $aWhatLogElement->{config}; |
|
980 |
|
981 my $platform = ""; |
|
982 my $variant = ""; |
|
983 my $test; |
|
984 |
|
985 if ($config =~ /^(\w+)_(\w+)\.test/){ |
|
986 $platform = $1; |
|
987 $variant = $2; |
|
988 $test = "test"; |
|
989 } |
|
990 elsif ($config =~ /^(\w+)_(\w+)*/){ |
|
991 $platform = $1; |
|
992 $variant = $2; |
|
993 } |
|
994 |
|
995 if($aWhatLogElement->{export}){ |
|
996 my $exports = $self->WrapVarToArray($aWhatLogElement->{export}); |
|
997 foreach my $export (@$exports) { |
|
998 $self->StoreExportItem ($bldinfDir, $export->{source}, $export->{destination}, $test); |
|
999 } |
|
1000 } |
|
1001 if($aWhatLogElement->{archive}){ |
|
1002 my $archives = $self->WrapVarToArray($aWhatLogElement->{archive}); |
|
1003 foreach my $archive (@$archives){ |
|
1004 foreach my $member (@{$archive->{member}}) { |
|
1005 $self->StoreExportItem ($bldinfDir, $archive->{zipfile}, $member, $test); |
|
1006 } |
|
1007 } |
|
1008 } |
|
1009 if($aWhatLogElement->{build}){ |
|
1010 my $buildItems = $self->WrapVarToArray($aWhatLogElement->{build}); |
|
1011 foreach my $buildItem (@$buildItems) { |
|
1012 $self->StoreBuildItem ($bldinfDir, $buildItem, $platform, $variant, $test); |
|
1013 } |
|
1014 } |
|
1015 if($aWhatLogElement->{resource}){ |
|
1016 my $resources = $self->WrapVarToArray($aWhatLogElement->{resource}); |
|
1017 foreach my $buildItem (@$resources) { |
|
1018 if($buildItem =~ /[\\|\/]epoc32[\\|\/]release[\\|\/]winscw[\\|\/](urel|udeb)[\\|\/]/g){ |
|
1019 $variant = $1; |
|
1020 } |
|
1021 else{ |
|
1022 $variant = "ALL"; |
|
1023 } |
|
1024 $self->StoreBuildItem ($bldinfDir, $buildItem, $platform, $variant, $test); |
|
1025 } |
|
1026 } |
|
1027 if($aWhatLogElement->{bitmap}){ |
|
1028 my $bitmaps = $self->WrapVarToArray($aWhatLogElement->{bitmap}); |
|
1029 foreach my $buildItem (@$bitmaps) { |
|
1030 $self->StoreBuildItem ($bldinfDir, $buildItem, $platform, "ALL", $test); |
|
1031 } |
|
1032 } |
|
1033 if($aWhatLogElement->{stringtable}){ |
|
1034 my $stringTables = $self->WrapVarToArray($aWhatLogElement->{stringtable}); |
|
1035 foreach my $buildItem (@$stringTables) { |
|
1036 $self->StoreBuildItem ($bldinfDir, $buildItem, $platform, $variant, $test); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 $self->{abldcache}->{platforms}->{$platform} = 1 if($platform ne "ALL"); |
|
1041 |
|
1042 my $param = "$bldinfDir "; |
|
1043 $param = $param."test " if ($test); |
|
1044 $param = $param."export -what"; |
|
1045 if(!$self->{abldcache}->{$param}){ |
|
1046 pop @{$self->{abldcache}->{$param}}; |
|
1047 } |
|
1048 } |
|
1049 |
|
1050 sub StoreExportItem { |
|
1051 my $self = shift; |
|
1052 my $bldinfDir = shift; |
|
1053 my $aSource = shift; |
|
1054 my $aDestination =shift; |
|
1055 my $test = shift; |
|
1056 $aSource = $self->ReleasableItem($aSource); |
|
1057 $aDestination = $self->ReleasableItem($aDestination); |
|
1058 my $param = "$bldinfDir "; |
|
1059 $param = $param."test " if ($test); |
|
1060 $param = $param."export -what"; |
|
1061 $self->{abldcache}->{exports}->{$param}->{$aDestination} = $aSource; |
|
1062 } |
|
1063 |
|
1064 sub StoreBuildItem { |
|
1065 my $self = shift; |
|
1066 my $bldinfDir = shift; |
|
1067 my $aBuildItem = shift; |
|
1068 my $aPlatform = shift; |
|
1069 my $aVariant = shift; |
|
1070 my $test = shift; |
|
1071 |
|
1072 if($aPlatform ne "ALL" and $aVariant eq "ALL"){ |
|
1073 $self->StoreBuildItem($bldinfDir, $aBuildItem, $aPlatform, "urel", $test); |
|
1074 $self->StoreBuildItem($bldinfDir, $aBuildItem, $aPlatform, "udeb", $test); |
|
1075 } |
|
1076 else{ |
|
1077 $aBuildItem = $self->ReleasableItem($aBuildItem); |
|
1078 my $param = "$bldinfDir "; |
|
1079 $param = $param."test " if ($test); |
|
1080 $param = $param."target $aPlatform $aVariant -what"; |
|
1081 $self->{abldcache}->{builds}->{$param}->{$aBuildItem} = 1; |
|
1082 $self->{abldcache}->{platforms}->{$aPlatform} = 1 if($aPlatform ne "ALL"); |
|
1083 } |
|
1084 } |
|
1085 |
|
1086 sub ReleasableItem { |
|
1087 my $self = shift; |
|
1088 my $aBuildItem = shift; |
|
1089 $aBuildItem =~ s/\/\//\\/g; |
|
1090 $aBuildItem =~ s/\//\\/g; |
|
1091 $aBuildItem =~ s/\"//g; |
|
1092 $aBuildItem =~ /^.:(.+)/; |
|
1093 return $1; |
|
1094 } |
|
1095 |
|
1096 |
|
1097 sub WrapVarToArray { |
|
1098 my $self = shift; |
|
1099 my $var = shift; |
|
1100 my @result; |
|
1101 |
|
1102 if($var){ |
|
1103 if($var =~/^ARRAY*/){ |
|
1104 return $var; |
|
1105 } |
|
1106 else{ |
|
1107 push (@result, $var); |
|
1108 } |
|
1109 } |
|
1110 return \@result; |
|
1111 } |
|
1112 |
|
1113 sub PrintCache { |
|
1114 my $self = shift; |
|
1115 print "print cache content\n" if($self->{verbose}); |
|
1116 foreach my $item (keys %{$self->{abldcache}}) { |
|
1117 if($item ne "loaded"){ |
|
1118 print "\$self->{abldcache}->{\'$item\'} =\n"; |
|
1119 print " [\n"; |
|
1120 my $first = 1; |
|
1121 |
|
1122 foreach my $cachedata (@{$self->{abldcache}->{$item}}) { |
|
1123 print ",\n" if($first > 1); |
|
1124 $first = $first+1; |
|
1125 if($cachedata=~/^ARRAY*/){ |
|
1126 print " [\'@$cachedata[0]\', \'@$cachedata[1]\']"; |
|
1127 } |
|
1128 else{ |
|
1129 print " \'$cachedata\'"; |
|
1130 } |
|
1131 } |
|
1132 print "\n ];\n\n"; |
|
1133 } |
|
1134 } |
|
1135 } |
|
1136 |
|
1137 # Support for target alias file |
|
1138 # If the MRP specifies 'ALL' then the intersection of the |
|
1139 # definition of 'ALL' and the output of abld help is used |
|
1140 # as the platform list |
|
1141 sub ResolveAlias { |
|
1142 my $self = shift; |
|
1143 my $abldPath = shift; |
|
1144 my $plat = shift; |
|
1145 my @plats = (); |
|
1146 |
|
1147 if (lc $plat eq 'all' || $self->{iniData}->HasTargetPlatforms($plat)) { |
|
1148 if ($self->{iniData}->HasTargetPlatforms($plat)) { |
|
1149 if (lc $plat eq 'all') { |
|
1150 # ALL and HasTargetPlatforms() |
|
1151 # Do the set intersection with the output of abld help |
|
1152 my $iniAll = $self->{iniData}->TargetPlatforms($plat); |
|
1153 my $abldHelp = $self->GetPlatforms($abldPath); |
|
1154 my %count; |
|
1155 foreach my $e (@$iniAll) { |
|
1156 $count{$e} = 1; |
|
1157 } |
|
1158 foreach my $e (@$abldHelp) { |
|
1159 if (exists $count{$e} and $count{$e} == 1) { |
|
1160 push @plats, $e; |
|
1161 } |
|
1162 } |
|
1163 $self->RemoveIDEPlatforms(\@plats); |
|
1164 if ($self->{verbose} > 1) { |
|
1165 print "Intersection of \"ALL\" alias and abld help is \"@plats\"\n"; |
|
1166 } |
|
1167 } else { |
|
1168 # NOT ALL and HasTargetPlatforms() |
|
1169 # Use the list of platforms from the iniData and this alias |
|
1170 @plats = @{$self->{iniData}->TargetPlatforms($plat)}; |
|
1171 if ($self->{verbose} > 1) { |
|
1172 print "Resolution of \"$plat\" alias is \"@plats\"\n"; |
|
1173 } |
|
1174 } |
|
1175 } else { |
|
1176 # ALL and NOT HasTargetPlatforms() so just use |
|
1177 # the results of abld help |
|
1178 @plats = @{$self->GetPlatforms($abldPath)}; |
|
1179 $self->RemoveIDEPlatforms(\@plats); |
|
1180 if ($self->{verbose} > 1) { |
|
1181 print "Resolution of \"ALL\" alias from abld help is \"@plats\"\n"; |
|
1182 } |
|
1183 } |
|
1184 } else { |
|
1185 # NOT ALL and NOT HasTargetPlatforms() so use this as the platform |
|
1186 @plats = $plat; |
|
1187 if ($self->{verbose} > 1) { |
|
1188 print "Platform specified is \"@plats\"\n"; |
|
1189 } |
|
1190 } |
|
1191 return \@plats; |
|
1192 } |
|
1193 |
|
1194 sub RemoveIDEPlatforms { |
|
1195 my $self = shift; |
|
1196 my $plats = shift; |
|
1197 |
|
1198 # Ugly hard-coded yukkiness |
|
1199 @$plats = grep { !m/^cw_ide$/i && !m/^vc\d/i } @$plats; |
|
1200 } |
|
1201 |
|
1202 sub GetPlatforms { |
|
1203 my $self = shift; |
|
1204 my $bldInfDir = shift; |
|
1205 |
|
1206 if (exists $self->{abldcache}->{"plats"}) { |
|
1207 return $self->{abldcache}->{"plats"}; |
|
1208 } |
|
1209 $self->CallBldMakeIfNecessary($bldInfDir); |
|
1210 |
|
1211 TRYAGAIN: |
|
1212 my $foundPlats = 0; |
|
1213 my @plats; |
|
1214 my @errorLines; |
|
1215 |
|
1216 my @abldOutput = `($bldInfDir\\abld help | perl -pe "s/^/stdout: /") 2>&1`; # Adds 'stdout: ' to the beginning of each STDOUT line, nothing is added to output on STDERR. |
|
1217 |
|
1218 foreach my $line (@abldOutput) { |
|
1219 chomp $line; |
|
1220 |
|
1221 if ($line =~ s/^stdout: //) { # Output from STDOUT |
|
1222 if ($foundPlats) { |
|
1223 if ($self->{verbose}) { print "Found platforms: $line\n"; } |
|
1224 $line =~ s/^\s*//; # Strip off leading whitespace. |
|
1225 # Force platforms to upper case to match IniData::TargetPlatforms() |
|
1226 $line = uc $line; |
|
1227 @plats = split /\s+/, $line; |
|
1228 last; |
|
1229 } |
|
1230 if ($line =~ /project platforms:/) { |
|
1231 $foundPlats = 1; |
|
1232 } |
|
1233 } |
|
1234 |
|
1235 else { # Output from STDERR |
|
1236 if ($line =~ m/project bldmake directory.*does not exist/i) { |
|
1237 $self->CallBldMake($bldInfDir); |
|
1238 goto TRYAGAIN; |
|
1239 } |
|
1240 elsif ($line =~ /Can't find ABLD.PL on PATH/i) { |
|
1241 push @errorLines, "Error: Couldn't run $bldInfDir\\abld: $line\n"; |
|
1242 } |
|
1243 else { |
|
1244 push @errorLines, "$line\n"; |
|
1245 } |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 if (scalar @errorLines > 0) { |
|
1250 die @errorLines; |
|
1251 } |
|
1252 |
|
1253 die "Error: didn't find any platforms\n" unless $foundPlats; |
|
1254 |
|
1255 $self->{abldcache}->{"plats"} = \@plats; |
|
1256 |
|
1257 return \@plats; |
|
1258 } |
|
1259 |
|
1260 sub ReadBinaries { |
|
1261 my $self = shift; |
|
1262 my $abldPath = shift; |
|
1263 my $test = lc(shift); |
|
1264 my $plat = lc(shift); |
|
1265 my $var = lc(shift); |
|
1266 my $mmp = shift; |
|
1267 my $remove = shift; |
|
1268 my $successRef = shift; |
|
1269 my $command = "target"; |
|
1270 my $opts = "-what"; |
|
1271 $command = "$test $command" if $test; |
|
1272 $opts = "$mmp $opts" if $mmp; |
|
1273 if ($self->{verbose}) { print "Extracting target info from \"$abldPath\\abld.bat\" using \"$command $plat $var\"...\n"; } |
|
1274 |
|
1275 my $bins = $self->GatherAbldOutput($abldPath, $plat, $command, $var, $test, $opts); |
|
1276 my $category = 'unclassified'; |
|
1277 if ($self->{iniData}->CategoriseBinaries() and not $plat =~ /^tools2?$/i) { |
|
1278 $category = $plat . '_' . $var; |
|
1279 if ($test) { |
|
1280 $category = $test . '_' . $category; |
|
1281 } |
|
1282 } |
|
1283 |
|
1284 $self->AddBins($remove, $category, $bins, $successRef); |
|
1285 } |
|
1286 |
|
1287 sub HandleExports { |
|
1288 my $self = shift; |
|
1289 my $abldPath = shift; |
|
1290 my $test = shift; |
|
1291 |
|
1292 $test = $test?"test ":""; |
|
1293 |
|
1294 if ($self->{verbose}) { |
|
1295 print "Extracting ${test}export info from $abldPath\\abld.bat...\n"; |
|
1296 } |
|
1297 |
|
1298 my $exports = $self->GatherAbldOutput($abldPath, "", "${test}export", "", $test, "-what"); |
|
1299 if ($self->{iniData}->CategoriseExports()) { |
|
1300 foreach my $thisExport (@$exports) { |
|
1301 if ($self->{verbose} > 1) { print "Found export \"$thisExport\"...\n"; } |
|
1302 if (Utils::WithinEpocRoot($thisExport)) { |
|
1303 $thisExport = Utils::RemoveEpocRoot($thisExport); |
|
1304 } |
|
1305 else { |
|
1306 print "Warning: Exported file \"$thisExport\" is not within EPOCROOT\n"; |
|
1307 } |
|
1308 |
|
1309 # Note, the hash key is case lowered to ensure duplicates are rejected. |
|
1310 # The original case is preserved in the hash values. |
|
1311 my $thisExportLc = lc($thisExport); |
|
1312 Utils::TidyFileName(\$thisExportLc); |
|
1313 |
|
1314 # Note, the exports are not yet classified because this is done using the source code classifications. |
|
1315 # At this point we don't know if we've handled all the 'source' mrp keywords yet. Classification will |
|
1316 # occur when the exports are asked for. |
|
1317 $self->{exports}->{automatic}->{$thisExportLc} = $thisExport; |
|
1318 } |
|
1319 Utils::AbsolutePath(\$abldPath); |
|
1320 push (@{$self->{exports}->{abldPaths}}, Utils::RemoveSourceRoot($abldPath)); |
|
1321 } |
|
1322 else { |
|
1323 # Handle exports treating them as binary files. Note, for a short while this code was changed to handle |
|
1324 # exported directories (not just files). This functionality has been removed because bldmake doesn't |
|
1325 # appear to cope with exported directories (it concatenates all the files in the specified directory into |
|
1326 # a single file due to weird use of the 'copy' command). |
|
1327 foreach my $thisExport (@$exports) { |
|
1328 $self->HandleBinFile(0, 'unclassified', $thisExport); # 0 = don't remove. |
|
1329 } |
|
1330 } |
|
1331 } |
|
1332 |
|
1333 sub HandleExportFile { |
|
1334 my $self = shift; |
|
1335 my $source = shift; |
|
1336 my $destination = shift; |
|
1337 my $remove = shift; |
|
1338 |
|
1339 if ($self->{iniData}->CategoriseExports()) { |
|
1340 if ($remove) { |
|
1341 my $destinationLc = lc(Utils::RemoveEpocRoot($destination)); |
|
1342 Utils::TidyFileName(\$destinationLc); |
|
1343 if (exists $self->{exports}->{automatic}->{$destinationLc}) { |
|
1344 print "Excluding export \"$destination\"...\n" if ($self->{verbose}); |
|
1345 delete $self->{exports}->{automatic}->{$destinationLc}; |
|
1346 } else { |
|
1347 my $comp = $self->{comp} || "component name unknown"; |
|
1348 print "Warning: ($comp) -export_file: could not remove $destination, as it hadn't been added. Perhaps the lines in your MRP are in the wrong order, or you meant -binary?\n"; |
|
1349 } |
|
1350 } |
|
1351 else { |
|
1352 Utils::CheckExists($source); |
|
1353 Utils::CheckIsFile($source); |
|
1354 Utils::CheckExists($destination); |
|
1355 Utils::CheckIsFile($destination); |
|
1356 $self->{exports}->{manual}->{Utils::RemoveSourceRoot($source)} = Utils::RemoveEpocRoot($destination); |
|
1357 } |
|
1358 } |
|
1359 else { |
|
1360 $self->HandleBinFile($remove, 'unclassified', $destination); |
|
1361 } |
|
1362 } |
|
1363 |
|
1364 sub AddBins { |
|
1365 my $self = shift; |
|
1366 my $remove = shift; |
|
1367 my $category = shift; |
|
1368 my $bins = shift; |
|
1369 my $successRef = shift; |
|
1370 |
|
1371 foreach my $file (@$bins) { |
|
1372 $self->HandleBinDirOrFile($remove, $category, $file, $successRef); |
|
1373 } |
|
1374 } |
|
1375 |
|
1376 sub EnsureDoesNotExist { |
|
1377 my $self = shift; |
|
1378 |
|
1379 my $relDir = $self->{iniData}->PathData->LocalArchivePathForExistingOrNewComponent($self->{comp}, $self->{ver}); |
|
1380 if (-e $relDir) { |
|
1381 die "Error: $self->{comp} $self->{ver} already exists\n"; |
|
1382 } |
|
1383 } |
|
1384 |
|
1385 sub Validate { |
|
1386 my $self = shift; |
|
1387 my $warnNotError = shift; # produce warnings instead of errors for some messages |
|
1388 |
|
1389 return if $self->{validated}; |
|
1390 $self->{validated} = 1; |
|
1391 |
|
1392 $self->EnsureDoesNotExist; |
|
1393 |
|
1394 unless (defined $self->{comp}) { |
|
1395 die "Error: No 'component' keyword specified in $self->{mrpName}\n"; |
|
1396 } |
|
1397 |
|
1398 $self->NotesSource(); # will die if we can't find a notes_source tag |
|
1399 |
|
1400 my @errors; |
|
1401 my @warnings; |
|
1402 |
|
1403 foreach my $bin (@{$self->Binaries()}) { |
|
1404 my $file = Utils::PrependEpocRoot(lc($bin)); |
|
1405 |
|
1406 if (my $result = $self->CheckPathLength($file)) { |
|
1407 if ($warnNotError) { |
|
1408 push (@warnings, "Warning: $result\n"); |
|
1409 } else { |
|
1410 push (@errors, "Error: $result\n"); |
|
1411 } |
|
1412 } |
|
1413 |
|
1414 if ($self->{fixMissingLibs}) { |
|
1415 unless (-e $file) { |
|
1416 if ($file =~ /$ENV{EPOCROOT}epoc32\\release\\armi\\(\S+)\\(\S+\.lib)/) { |
|
1417 my $fileToCopy = "$ENV{EPOCROOT}epoc32\\release\\thumb\\$1\\$2"; |
|
1418 print "Copying $fileToCopy to $file...\n"; |
|
1419 copy ($fileToCopy, $file) or push (@errors, "Error: Problem copying \"$fileToCopy\" to \"$file\": $!\n"); |
|
1420 } |
|
1421 else { |
|
1422 push (@errors, "Error: \"$file\" does not exist\n"); |
|
1423 } |
|
1424 } |
|
1425 } |
|
1426 else { |
|
1427 unless (-e $file) { |
|
1428 push (@errors, "Error: \"$file\" does not exist\n"); |
|
1429 } |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 foreach my $thisCategory (@{$self->ExportCategories()}) { |
|
1434 foreach my $thisExport (@{$self->Exports($thisCategory)}) { |
|
1435 $thisExport = Utils::PrependEpocRoot($thisExport); |
|
1436 |
|
1437 if (my $result = $self->CheckPathLength($thisExport)) { |
|
1438 if ($warnNotError) { |
|
1439 push (@warnings, "Warning: $result\n"); |
|
1440 } else { |
|
1441 push (@errors, "Error: $result\n"); |
|
1442 } |
|
1443 } |
|
1444 |
|
1445 unless (-e $thisExport) { |
|
1446 push (@errors, "Error: \"$thisExport\" does not exist\n"); |
|
1447 } |
|
1448 } |
|
1449 } |
|
1450 |
|
1451 foreach my $thisSourceCategory (@{$self->SourceCategories()}) { |
|
1452 foreach my $thisSourceFile (@{$self->Source($thisSourceCategory)}) { |
|
1453 if (my $result = $self->CheckPathLength($thisSourceFile)) { |
|
1454 if ($warnNotError) { |
|
1455 push (@warnings, "Warning: $result\n"); |
|
1456 } else { |
|
1457 push (@errors, "Error: $result\n"); |
|
1458 } |
|
1459 } |
|
1460 } |
|
1461 } |
|
1462 |
|
1463 if (@warnings) { |
|
1464 print @warnings; |
|
1465 } |
|
1466 |
|
1467 if (@errors and $#errors != -1) { |
|
1468 if ($#errors == 0) { |
|
1469 die $errors[0]; |
|
1470 } |
|
1471 else { |
|
1472 print @errors; |
|
1473 my $firstError = $errors[0]; |
|
1474 chomp $firstError; |
|
1475 die "Multiple errors (first - $firstError)\n"; |
|
1476 } |
|
1477 } |
|
1478 } |
|
1479 |
|
1480 sub CallBldMakeIfNecessary { |
|
1481 my $self = shift; |
|
1482 my $abldPath = shift; |
|
1483 if (-e "$abldPath\\abld.bat") { |
|
1484 # Check to see if bld.inf has been modifed since bldmake was last run. |
|
1485 my $abldMTime = Utils::FileModifiedTime("$abldPath\\abld.bat"); |
|
1486 my $bldInfMTime = Utils::FileModifiedTime("$abldPath\\bld.inf"); |
|
1487 if ($bldInfMTime > $abldMTime) { |
|
1488 $self->CallBldMake($abldPath); |
|
1489 } |
|
1490 } |
|
1491 else { |
|
1492 $self->CallBldMake($abldPath); |
|
1493 } |
|
1494 } |
|
1495 |
|
1496 sub GatherAbldOutput { |
|
1497 my $self = shift; |
|
1498 my $abldPath = shift; |
|
1499 my $plat = shift; |
|
1500 my $abldCmnd = shift; |
|
1501 my $var = shift; |
|
1502 my $test = shift; |
|
1503 my $opts = shift; |
|
1504 my @output; |
|
1505 |
|
1506 my $abldParms = $abldCmnd; |
|
1507 $abldParms .= " $plat" if $plat; |
|
1508 $abldParms .= " $var" if $var; |
|
1509 $abldParms .= " $opts" if $opts; |
|
1510 |
|
1511 $abldPath=~s/\//\\/s; # Normalise all slashes to backslashes |
|
1512 |
|
1513 $self->ProcessCache($abldPath, $test) if (!exists($self->{abldcache}->{loaded}->{$abldPath})); |
|
1514 |
|
1515 if ($self->{abldcache}->{$abldPath." ".$abldParms}) { |
|
1516 # Why do we bother with a cache? |
|
1517 # Because you might see this in an MRP: |
|
1518 # binary \blah all |
|
1519 # -binary \blah mfrumpy |
|
1520 # The "all" will be expanded to multiple calls to GatherAbldOutput, if we've got CategoriseBinaries on |
|
1521 |
|
1522 # The codes below are added to make MakeCBR follow cachefiles created by Raptor |
|
1523 if($abldCmnd eq "export" and $opts eq "-what"){ |
|
1524 my $exports = $self->{abldcache}->{$abldPath." ".$abldParms}; |
|
1525 if(@$exports[0]){ |
|
1526 my $firstExportFile = @$exports[0]; |
|
1527 if($firstExportFile=~/^ARRAY*/){ |
|
1528 foreach my $thisExport (@$exports) { |
|
1529 push (@output, @$thisExport[0]); |
|
1530 push @{$self->{exportsToBeProcessed}}, {source => @$thisExport[1], |
|
1531 destination => @$thisExport[0], |
|
1532 abldPath => Utils::PrependSourceRoot($abldPath)}; |
|
1533 } |
|
1534 $self->{raptorcache} = 1; |
|
1535 return \@output; |
|
1536 } |
|
1537 } |
|
1538 } |
|
1539 |
|
1540 return $self->{abldcache}->{$abldPath." ".$abldParms}; |
|
1541 } |
|
1542 |
|
1543 # Remove repeat guards - these stop CallBldMake and CallMakMake from being called |
|
1544 # forever if a fatal error occurs with a build script. |
|
1545 delete $self->{bldMakeCalled}; |
|
1546 delete $self->{"makMakeCalled_$plat"}; |
|
1547 |
|
1548 $self->CallBldMakeIfNecessary($abldPath); |
|
1549 |
|
1550 TRYAGAIN: |
|
1551 |
|
1552 my @errorLines; # Used to store the error |
|
1553 |
|
1554 my $cmd = "$abldPath\\abld $abldParms"; |
|
1555 print "Executing command: $cmd\n" if $self->{verbose} > 1; |
|
1556 |
|
1557 my @abldOutput = `($cmd | perl -pe "s/^/stdout: /") 2>&1`; |
|
1558 |
|
1559 foreach my $line (@abldOutput) { |
|
1560 chomp $line; |
|
1561 |
|
1562 if ($line =~ s/^stdout: //) { # Output from STDOUT |
|
1563 if ($self->{verbose} > 1) { print "ABLD: $line\n"; } |
|
1564 |
|
1565 if ($line =~ /(^(make|make\[\d+\]): .*)/) { |
|
1566 print "Warning: $1\n"; |
|
1567 } |
|
1568 elsif ($line =~ /given more than once in the same rule/) { |
|
1569 print "$line\n"; |
|
1570 } |
|
1571 elsif ($line =~ m/\.\./) { |
|
1572 my $oldpath = cwd(); |
|
1573 eval { |
|
1574 chdir($abldPath); |
|
1575 Utils::AbsoluteFileName(\$line); |
|
1576 }; |
|
1577 chdir($oldpath); |
|
1578 if ($@) { |
|
1579 print "Warning: could not convert path \"$line\" to an absolute path because: $@\n"; |
|
1580 # Do nothing. We just can't convert it to an absolute path. We'll push it onto the |
|
1581 # output anyway because in some circumstances it will work out OK. |
|
1582 } |
|
1583 push (@output, $line); |
|
1584 } else { |
|
1585 # Lines without .. we don't bother making absolute, because it involves 4 chdir operations |
|
1586 # so is a bit heavyweight. |
|
1587 push (@output, $line); |
|
1588 } |
|
1589 } |
|
1590 |
|
1591 else { # Output from STDERR |
|
1592 if ($self->{verbose} > 1) { print "ABLD: $line\n"; } |
|
1593 |
|
1594 # Catch errors that look like the makefile isn't present. |
|
1595 # Note, different versions of the build tools produce different things, so the regular expression below is a bit evil. |
|
1596 if ($line =~ /^(U1052|make\[1\]: (?i:\Q$ENV{EPOCROOT}\EEPOC32\\BUILD\\.*): No such file or directory|make: \*\*\* \[.*\] Error 2)$/) { |
|
1597 |
|
1598 # Makefile not present, so generate it. |
|
1599 |
|
1600 $self->CallMakMake($abldPath, $plat, $test); |
|
1601 |
|
1602 goto TRYAGAIN; |
|
1603 } |
|
1604 elsif ($line =~ /^ABLD ERROR: Project Bldmake directory .* does not exist$/ |
|
1605 or $line =~ /^ABLD ERROR: .* not yet created$/ |
|
1606 or $line =~ /abld\.bat does not exist/) { |
|
1607 |
|
1608 #BldMake needs to be run. |
|
1609 $self->CallBldMake($abldPath); |
|
1610 goto TRYAGAIN; |
|
1611 } |
|
1612 elsif ($line =~ /^This project does not support platform/) { |
|
1613 push @errorLines, "Error: Platform \"$plat\" not supported\n"; |
|
1614 } |
|
1615 elsif ($line =~ /^MISSING:/) { |
|
1616 print "$line\n"; |
|
1617 } |
|
1618 elsif ($line =~ /Can't find ABLD.PL on PATH/i) { |
|
1619 push @errorLines, "Error: Couldn't run abld $abldParms: $line\n"; |
|
1620 } |
|
1621 else { |
|
1622 push @errorLines, "$line\n"; |
|
1623 } |
|
1624 } |
|
1625 } |
|
1626 |
|
1627 if (scalar @errorLines > 0) { |
|
1628 die @errorLines; |
|
1629 } |
|
1630 |
|
1631 $self->{abldcache}->{$abldPath." ".$abldParms} = \@output; |
|
1632 |
|
1633 return \@output; |
|
1634 } |
|
1635 |
|
1636 sub CallBldMake { |
|
1637 my $self = shift; |
|
1638 my $abldPath = shift; |
|
1639 |
|
1640 if (exists $self->{bldMakeCalled}) { |
|
1641 die "Error: Problem calling bldmake in \"$abldPath\"\n"; |
|
1642 } |
|
1643 else { |
|
1644 $self->{bldMakeCalled} = 1; |
|
1645 } |
|
1646 |
|
1647 if ($self->{verbose}) { |
|
1648 print "Calling bldmake in $abldPath...\n"; |
|
1649 } |
|
1650 my $cwd = cwd(); |
|
1651 chdir $abldPath or die "Error: Couldn't change working directory to $abldPath: $!\n"; |
|
1652 system "bldmake bldfiles"; |
|
1653 chdir $cwd; |
|
1654 die "Error: \"bldmake bldfiles\" failed in \"$abldPath\" (exit status $?)\n" if ($?); |
|
1655 } |
|
1656 |
|
1657 sub CallMakMake { |
|
1658 my $self = shift; |
|
1659 my $abldPath = shift; |
|
1660 my $plat = shift; |
|
1661 my $test = shift; |
|
1662 |
|
1663 my $repeatGuard = "makMakeCalled_$plat"; |
|
1664 if ($test) { |
|
1665 $test = 'test'; |
|
1666 $repeatGuard .= '_test'; |
|
1667 } |
|
1668 else { |
|
1669 $test = ''; |
|
1670 } |
|
1671 |
|
1672 if (exists $self->{$repeatGuard}) { |
|
1673 if ($test) { |
|
1674 die "Error: Problem generating makefile for $test $plat in \"$abldPath\"\n"; |
|
1675 } |
|
1676 else { |
|
1677 die "Error: Problem generating makefile for $plat in \"$abldPath\"\n"; |
|
1678 } |
|
1679 } |
|
1680 else { |
|
1681 $self->{$repeatGuard} = 1; |
|
1682 } |
|
1683 |
|
1684 if ($self->{verbose}) { |
|
1685 if ($test) { |
|
1686 print "Generating makefile for $test $plat...\n"; |
|
1687 } |
|
1688 else { |
|
1689 print "Generating makefile for $plat...\n"; |
|
1690 } |
|
1691 } |
|
1692 system "$abldPath\\abld $test makefile $plat > NUL"; |
|
1693 } |
|
1694 |
|
1695 sub BinSets { |
|
1696 my $self = shift; |
|
1697 |
|
1698 $self->ProcessBinaries(); |
|
1699 |
|
1700 return $self->{binsets}; |
|
1701 } |
|
1702 |
|
1703 sub SourceRootPath { |
|
1704 my $fileName = shift; |
|
1705 if (Utils::IsAbsolute($fileName)) { |
|
1706 $fileName = Utils::PrependSourceRoot($fileName); |
|
1707 } |
|
1708 else { |
|
1709 Utils::AbsoluteFileName(\$fileName); |
|
1710 } |
|
1711 Utils::CheckWithinSourceRoot($fileName); |
|
1712 $fileName =~ s/\\.$//; |
|
1713 return $fileName; |
|
1714 } |
|
1715 |
|
1716 sub WarnRedundantMRPLine { |
|
1717 my $self = shift; |
|
1718 my $remove = shift; |
|
1719 my $line = shift; |
|
1720 my $comp = $self->{comp} || "component name unknown"; |
|
1721 my $sign = ""; |
|
1722 my $action = "add"; |
|
1723 |
|
1724 if($remove) { |
|
1725 $action = "remove"; |
|
1726 } |
|
1727 print "Remark: ($comp) The MRP line \"$line\" does not $action any files. Therefore is this line necessary?\n"; |
|
1728 } |
|
1729 |
|
1730 sub CheckPathLength { |
|
1731 my $self = shift; |
|
1732 my $path = shift; |
|
1733 |
|
1734 if (length ($path) > MAX_PATH_LENGTH) { |
|
1735 return "The component \"$self->{comp}\" is pending release and contains a path which is " . length($path) . " characters long and will prevent the component from being released: \"$path\"." |
|
1736 } |
|
1737 |
|
1738 return 0; |
|
1739 } |
|
1740 |
|
1741 sub SetIPR { |
|
1742 my $self = shift; |
|
1743 my $category = shift; |
|
1744 my $path = shift || 'default'; |
|
1745 my $exportRestricted = (shift) ? 1 : 0; |
|
1746 |
|
1747 if (!$category || shift) { |
|
1748 # caller(0))[3] gives the package and the method called, e.g. MrpData::SetIPR |
|
1749 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n"; |
|
1750 } |
|
1751 |
|
1752 $path = File::Spec->canonpath($path); # Normalise the path |
|
1753 |
|
1754 # remove trailing slashes |
|
1755 $path =~ s/[\\\/]$//; |
|
1756 |
|
1757 if ($path ne 'default') { |
|
1758 $path = SourceRootPath($path); |
|
1759 } |
|
1760 |
|
1761 if($self->{iniData}->HasMappings()){ |
|
1762 $path = $self->{iniData}->PerformMapOnFileName($path); |
|
1763 } |
|
1764 |
|
1765 $path = Utils::RemoveSourceRoot($path) if ($path ne 'default'); |
|
1766 |
|
1767 if (exists $self->{unresolvedIPR}->{$path}) { |
|
1768 return 0; |
|
1769 } |
|
1770 |
|
1771 $self->{unresolvedIPR}->{$path} = { |
|
1772 category => uc($category), |
|
1773 exportRestricted => $exportRestricted}; |
|
1774 |
|
1775 return 1; |
|
1776 } |
|
1777 |
|
1778 sub SetComponent { |
|
1779 my $self = shift; |
|
1780 my $operand = shift; |
|
1781 |
|
1782 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n" if (shift); |
|
1783 |
|
1784 if (exists $self->{comp}) { |
|
1785 return 0; |
|
1786 } |
|
1787 |
|
1788 $self->{comp} = $operand; |
|
1789 |
|
1790 return 1; |
|
1791 } |
|
1792 |
|
1793 sub SetNotesSource { |
|
1794 my $self = shift; |
|
1795 my $operand = shift; |
|
1796 |
|
1797 if (!$operand || shift) { |
|
1798 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n"; |
|
1799 } |
|
1800 |
|
1801 if (exists $self->{notes_src}) { |
|
1802 return 0; |
|
1803 } |
|
1804 |
|
1805 $operand = File::Spec->canonpath($operand); # Normalise the path |
|
1806 |
|
1807 $operand = SourceRootPath($operand); |
|
1808 |
|
1809 if($self->{iniData}->HasMappings()){ |
|
1810 $operand = $self->{iniData}->PerformMapOnFileName($operand); |
|
1811 } |
|
1812 |
|
1813 Utils::CheckExists($operand); |
|
1814 Utils::CheckIsFile($operand); |
|
1815 $self->{notes_src} = Utils::RemoveSourceRoot($operand); |
|
1816 |
|
1817 return 1; |
|
1818 } |
|
1819 |
|
1820 sub SetSource { |
|
1821 my $self = shift; |
|
1822 my $operand = shift; |
|
1823 |
|
1824 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n" if (shift); |
|
1825 |
|
1826 if ($operand =~ /distribution\.policy$/i) { |
|
1827 print "\nREMARK: Distribution Policy file included as source in \"$self->{mrpName}\"\n"; |
|
1828 return 1; |
|
1829 } |
|
1830 |
|
1831 $operand = File::Spec->canonpath($operand); # Normalise the path |
|
1832 |
|
1833 #remove trailing slashes |
|
1834 $operand =~ s/[\\\/]$//; |
|
1835 |
|
1836 $operand = SourceRootPath($operand); |
|
1837 |
|
1838 if($self->{iniData}->HasMappings()){ |
|
1839 $operand = $self->{iniData}->PerformMapOnFileName($operand); |
|
1840 } |
|
1841 |
|
1842 Utils::CheckExists($operand); |
|
1843 $self->{srcitems}->{Utils::RemoveSourceRoot($operand)} = 1; |
|
1844 # No longer classify the source. We do this on-demand later. |
|
1845 |
|
1846 return 1; |
|
1847 } |
|
1848 |
|
1849 sub SetBinary { |
|
1850 my $self = shift; |
|
1851 my @words = @{shift()}; |
|
1852 my $test = (shift) ? 1 : 0; |
|
1853 my $remove = (shift) ? 1 : 0; |
|
1854 |
|
1855 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n" if (shift); |
|
1856 |
|
1857 my $path = shift @words; |
|
1858 |
|
1859 $path = File::Spec->canonpath($path); # Normalise the path |
|
1860 |
|
1861 # tranfer to absolute path |
|
1862 $path = SourceRootPath($path); |
|
1863 |
|
1864 if (scalar @words) { |
|
1865 if($self->{iniData}->HasMappings()){ |
|
1866 $path = $self->{iniData}->PerformMapOnFileName($path); |
|
1867 } |
|
1868 } |
|
1869 |
|
1870 push @{$self->{binaryStatements}}, { |
|
1871 abldPath => $path, |
|
1872 test => $test, |
|
1873 remove => $remove, |
|
1874 words => [@words]}; |
|
1875 } |
|
1876 |
|
1877 sub SetExports { |
|
1878 my $self = shift; |
|
1879 my $abldPath = shift; |
|
1880 my $test = (shift) ? 1 : 0; |
|
1881 my $dependantComponent = shift; |
|
1882 |
|
1883 if (!$abldPath || shift) { |
|
1884 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n"; |
|
1885 } |
|
1886 |
|
1887 if ($dependantComponent) { |
|
1888 push (@{$self->{_dependantComponents}->{$dependantComponent}}, $abldPath); |
|
1889 } |
|
1890 |
|
1891 $abldPath = File::Spec->canonpath($abldPath); # Normalise the path |
|
1892 |
|
1893 $abldPath = SourceRootPath($abldPath); |
|
1894 |
|
1895 if($self->{iniData}->HasMappings()){ |
|
1896 $abldPath = $self->{iniData}->PerformMapOnFileName($abldPath); |
|
1897 } |
|
1898 |
|
1899 Utils::CheckExists($abldPath); |
|
1900 |
|
1901 push @{$self->{exportsStatements}}, { abldPath => $abldPath, |
|
1902 test => $test}; |
|
1903 } |
|
1904 |
|
1905 sub SetExportFile { |
|
1906 my $self = shift; |
|
1907 my $source = shift; |
|
1908 my $destination = shift; |
|
1909 my $remove = (shift) ? 1 : 0; |
|
1910 my $dependantComponent = shift; |
|
1911 |
|
1912 croak "Invalid number of arguments passed to " . (caller(0))[3] . "\n" if (shift); |
|
1913 |
|
1914 unless ($source and $destination) { |
|
1915 croak "Error: Incorrect syntax to 'export_file' keyword in \"$self->{mrpName}\"\n"; |
|
1916 } |
|
1917 |
|
1918 if ($dependantComponent) { |
|
1919 push (@{$self->{_dependantComponents}->{$dependantComponent}}, $source); |
|
1920 } |
|
1921 |
|
1922 $source = File::Spec->canonpath($source); # Normalise the path |
|
1923 $destination = File::Spec->canonpath($destination); |
|
1924 |
|
1925 $source = SourceRootPath($source); |
|
1926 |
|
1927 if($self->{iniData}->HasMappings()){ |
|
1928 $source = $self->{iniData}->PerformMapOnFileName($source); |
|
1929 $destination = $self->{iniData}->PerformMapOnFileName($destination); |
|
1930 } |
|
1931 |
|
1932 $destination = Utils::PrependEpocRoot($destination); |
|
1933 |
|
1934 push @{$self->{unprocessedExportFiles}}, { source => $source, |
|
1935 destination => $destination, |
|
1936 remove => $remove}; |
|
1937 } |
|
1938 |
|
1939 sub GetIPRInformation { |
|
1940 my $self = shift; |
|
1941 |
|
1942 if (exists $self->{IPR}) { |
|
1943 return $self->{IPR}; |
|
1944 } |
|
1945 else { |
|
1946 return {}; |
|
1947 } |
|
1948 } |
|
1949 |
|
1950 sub GetExportComponentDependencies { |
|
1951 my $self = shift; |
|
1952 |
|
1953 if (defined $self->{_dependantComponents}) { |
|
1954 return (keys %{$self->{_dependantComponents}}); # Return an array of the dependencies |
|
1955 } |
|
1956 |
|
1957 return undef; |
|
1958 } |
|
1959 |
|
1960 sub ValidateParsing { |
|
1961 my $self = shift; |
|
1962 |
|
1963 # This flag stops the reader from trying to populate the object more than once |
|
1964 $self->{populated} = 1; |
|
1965 |
|
1966 if (exists $self->{srcitems} && !exists $self->{unresolvedIPR}) { |
|
1967 # If no IPR information exists in the MRP file then we set the IPR category |
|
1968 # for each source item to undef. This is so that incorrect IPR information is |
|
1969 # not returned. A flag is also set to indicate that IPR information exists. The |
|
1970 # flag will be used to ensure other parts other parts of validation should will |
|
1971 # not be performed (e.g. validating exports). |
|
1972 |
|
1973 $self->{noIprInformation} = 1; |
|
1974 |
|
1975 foreach my $sourceItem (keys %{$self->{srcitems}}) { |
|
1976 $self->{IPR}->{$sourceItem} = { |
|
1977 category => undef, |
|
1978 exportRestricted => undef, |
|
1979 }; |
|
1980 } |
|
1981 } |
|
1982 else { |
|
1983 # Reconcile the IPR information here so that any warnings are produced sooner... |
|
1984 # IPR information can only be included if it matches a source line in the MRP file |
|
1985 # All other IPR lines will be ignored. The reconciliation is done here as IPR |
|
1986 # lines may appear before source lines in the MRP file. |
|
1987 |
|
1988 if (!defined $self->{srcitems} && exists $self->{unresolvedIPR}->{default}) { |
|
1989 carp "Warning: The default IPR entry does not apply to any source statements in \"$self->{mrpName}\"\n"; |
|
1990 } |
|
1991 |
|
1992 # Match IPR against source statement by using the length... |
|
1993 foreach my $sourceItem (keys %{$self->{srcitems}}) { |
|
1994 # The sort below sorts by longest line first, not shortest line first. Note $b <=> $a, not $a <=> $b... |
|
1995 # This allows us to match the most relevant line first, based on longest length/best match |
|
1996 foreach my $iprItem (sort {length($b) <=> length($a)} keys %{$self->{unresolvedIPR}}) { |
|
1997 next if ($iprItem eq 'default'); |
|
1998 # If the source item contains the IPR path then it is a match |
|
1999 if ($sourceItem =~ m/^\Q$iprItem\E([\\\/]|$)/i) { |
|
2000 $self->{IPR}->{$sourceItem} = $self->{unresolvedIPR}->{$iprItem}; |
|
2001 |
|
2002 last; |
|
2003 } |
|
2004 } |
|
2005 |
|
2006 # If it didn't match an IPR then we assign the default |
|
2007 if (!exists $self->{IPR}->{$sourceItem}) { |
|
2008 $self->{IPR}->{$sourceItem} = $self->{unresolvedIPR}->{default}; |
|
2009 } |
|
2010 } |
|
2011 |
|
2012 delete $self->{unresolvedIPR}->{default}; |
|
2013 |
|
2014 # Find IPR entries which do live under a source folder... |
|
2015 foreach my $iprItem (keys %{$self->{unresolvedIPR}}) { |
|
2016 next if (exists $self->{IPR}->{$iprItem}); |
|
2017 |
|
2018 foreach my $sourceItem (keys %{$self->{srcitems}}) { |
|
2019 if ($iprItem =~ /^\Q$sourceItem\E/i) { |
|
2020 $self->{IPR}->{$iprItem} = $self->{unresolvedIPR}->{$iprItem}; |
|
2021 last; |
|
2022 } |
|
2023 } |
|
2024 |
|
2025 if (!grep /\Q$iprItem\E/i, (keys %{$self->{IPR}})) { |
|
2026 # Otherwise this IPR statement does not apply to this MRP file... |
|
2027 carp "Warning: The IPR entry for \"$iprItem\" does not apply to any source statements in \"$self->{mrpName}\"\n"; |
|
2028 } |
|
2029 } |
|
2030 } |
|
2031 |
|
2032 delete $self->{unresolvedIPR}; |
|
2033 } |
|
2034 |
|
2035 |
|
2036 sub ProcessExports { |
|
2037 my $self = shift; |
|
2038 my $confirmExportIprInformation = shift; |
|
2039 |
|
2040 return if ($self->{exportsProcessed}); |
|
2041 |
|
2042 $self->{exportsProcessed} = 1; |
|
2043 |
|
2044 foreach my $export (@{$self->{exportsStatements}}) { |
|
2045 $self->HandleExports($export->{abldPath}, $export->{test}); |
|
2046 } |
|
2047 |
|
2048 foreach my $exportFile (@{$self->{unprocessedExportFiles}}) { |
|
2049 if($self->{raptorcache}){ |
|
2050 my $isHandle = 0; |
|
2051 foreach my $export (@{$self->{exportsToBeProcessed}}) { |
|
2052 if($export->{source} eq $exportFile->{source}){ |
|
2053 if (exists $self->{exports}->{automatic}->{lc(Utils::RemoveEpocRoot($export->{destination}))}) { |
|
2054 $self->HandleExportFile($export->{source}, $export->{destination}, $exportFile->{remove}); |
|
2055 $isHandle = 1; |
|
2056 } |
|
2057 } |
|
2058 } |
|
2059 if($isHandle == 0){ |
|
2060 foreach my $export (@{$self->{exportsToBeProcessed}}) { |
|
2061 if(lc($export->{destination}) eq lc($exportFile->{destination})){ |
|
2062 foreach my $tempExport (@{$self->{exportsToBeProcessed}}) { |
|
2063 if($export->{source} eq $tempExport->{source}){ |
|
2064 if (exists $self->{exports}->{automatic}->{lc(Utils::RemoveEpocRoot($tempExport->{destination}))}) { |
|
2065 $self->HandleExportFile($tempExport->{source}, $tempExport->{destination}, $exportFile->{remove}); |
|
2066 } |
|
2067 } |
|
2068 } |
|
2069 } |
|
2070 } |
|
2071 } |
|
2072 } |
|
2073 else{ |
|
2074 $self->HandleExportFile($exportFile->{source}, $exportFile->{destination}, $exportFile->{remove}); |
|
2075 } |
|
2076 } |
|
2077 |
|
2078 delete $self->{unprocessedExportFiles}; |
|
2079 |
|
2080 # If exports are to be classified, or the caller wants to confirm the IPR information for exports is correct... |
|
2081 if ($self->{iniData}->CategoriseExports() || $confirmExportIprInformation) { |
|
2082 $self->ClassifyManualExports(); |
|
2083 |
|
2084 # The codes below are changed to make MakeCBR follow cachefiles created by Raptor |
|
2085 if(!$self->{raptorcache}){ |
|
2086 $self->ClassifyAutomaticExports(); |
|
2087 } |
|
2088 else{ |
|
2089 my @tempExports; |
|
2090 foreach my $export (@{$self->{exportsToBeProcessed}}) { |
|
2091 if (exists $self->{exports}->{automatic}->{lc(Utils::RemoveEpocRoot($export->{destination}))}) { |
|
2092 push @tempExports, $export; |
|
2093 } |
|
2094 } |
|
2095 @{$self->{exportsToBeProcessed}} = @tempExports; |
|
2096 |
|
2097 delete $self->{exports}->{automatic}; |
|
2098 delete $self->{exports}->{abldPaths}; |
|
2099 } |
|
2100 delete $self->{raptorcache}; |
|
2101 |
|
2102 # If no IPR information exists in the MRP file then we do not validate the exports as we don't care about if |
|
2103 # we need dependant components |
|
2104 if (!$self->{noIprInformation}) { |
|
2105 # Check to see if the exports are owned by the component, or dependant components have been specified... |
|
2106 foreach my $export (@{$self->{exportsToBeProcessed}}) { |
|
2107 # check if the exports are included as source in this component |
|
2108 if (!grep keys %{$self->{srcitems}}, $export->{source}) { |
|
2109 # If not then check if another dependant component for the export has been specified |
|
2110 |
|
2111 # A dependant component is specified for either the export source or the exports abld path |
|
2112 my $whatToTest = 'source'; |
|
2113 $whatToTest = 'abldPath' if (exists $export->{abldPath}); |
|
2114 |
|
2115 my $dependencyExists = 0; |
|
2116 |
|
2117 foreach my $dependantComponent (keys %{$self->{_dependantComponents}}) { |
|
2118 if (grep /\Q$export->{$whatToTest}\E/i, (@{$self->{_dependantComponents}->{$dependantComponent}})) { |
|
2119 $dependencyExists = 1; |
|
2120 } |
|
2121 } |
|
2122 |
|
2123 if (!$dependencyExists) { |
|
2124 # If no dependency exists... |
|
2125 warn "Warning: ".$self->Component()." contains an export '". $export->{source} ."' which is not included as source for this component, and does not contain dependencies on another component\n"; |
|
2126 } |
|
2127 } |
|
2128 } |
|
2129 } |
|
2130 |
|
2131 # If we only processed exports to that we can confirm the IPR information, but |
|
2132 # we don't actually want to categorise exports then we delete them |
|
2133 if (!$self->{iniData}->CategoriseExports() && $confirmExportIprInformation) { |
|
2134 delete $self->{exportsToBeProcessed}; |
|
2135 } |
|
2136 } |
|
2137 |
|
2138 my $errors; |
|
2139 |
|
2140 foreach my $export (@{$self->{exportsToBeProcessed}}) { |
|
2141 if (!$self->AddExport($export->{source}, $self->RemoveRoot($export->{destination}))) { |
|
2142 $errors = 1; |
|
2143 } |
|
2144 } |
|
2145 if ($errors) { |
|
2146 die "Aborting due to above error(s)\n"; |
|
2147 } |
|
2148 |
|
2149 delete $self->{exportsToBeProcessed}; |
|
2150 |
|
2151 if ($self->{binariesProcessed}) { |
|
2152 # if binaries and exports have been processed then we delete the abldcach as |
|
2153 # it is no longer required and takes up a lot of memory |
|
2154 delete $self->{abldcache}; |
|
2155 } |
|
2156 } |
|
2157 |
|
2158 sub RemoveRoot { |
|
2159 my $self = shift; |
|
2160 my $path = shift; |
|
2161 return $1 if($path =~ /^\\(.+)/); |
|
2162 return $path; |
|
2163 } |
|
2164 |
|
2165 sub ProcessBinaries { |
|
2166 my $self = shift; |
|
2167 |
|
2168 return if ($self->{binariesProcessed}); |
|
2169 |
|
2170 $self->{binariesProcessed} = 1; |
|
2171 |
|
2172 foreach my $binary (@{$self->{binaryStatements}}) { |
|
2173 |
|
2174 my $success = 0; |
|
2175 |
|
2176 if (!scalar(@{$binary->{words}})) { |
|
2177 $binary->{abldPath} = Utils::PrependEpocRoot($binary->{abldPath}); |
|
2178 # Pass a reference of $success to HandleBinDirOrFile which can only be changed in HandleBinFile if the operation is successful. |
|
2179 $self->HandleBinDirOrFile($binary->{remove}, "unclassified", $binary->{abldPath}, \$success); |
|
2180 if ($success == 0 ) |
|
2181 { |
|
2182 my $line; |
|
2183 $line = 'test' if ($binary->{test}); |
|
2184 $line .= 'binary ' . join ' ', @{$binary->{words}}; |
|
2185 $self->WarnRedundantMRPLine($binary->{remove}, $line); |
|
2186 } |
|
2187 } |
|
2188 else { |
|
2189 # Pass a reference of $success to HandleBinSet which can only be changed in HandleBinFile if the operation is successful. |
|
2190 $self->HandleBinSet($binary->{remove}, $binary->{test}, \$success, $binary->{abldPath}, @{$binary->{words}}); |
|
2191 if ($success == 0 ) |
|
2192 { |
|
2193 my $line; |
|
2194 $line = 'test' if ($binary->{test}); |
|
2195 $line .= 'binary ' . join ' ', @{$binary->{words}}; |
|
2196 $self->WarnRedundantMRPLine($binary->{remove}, $line); |
|
2197 } |
|
2198 } |
|
2199 } |
|
2200 |
|
2201 if ($self->{exportsProcessed}) { |
|
2202 # if binaries and exports have been processed then we delete the abldcache as |
|
2203 # it is no longer required and takes up a lot of memory |
|
2204 delete $self->{abldcache}; |
|
2205 } |
|
2206 } |
|
2207 |
|
2208 |
|
2209 1; |
|
2210 |
|
2211 __END__ |
|
2212 |
|
2213 =head1 NAME |
|
2214 |
|
2215 MrpData.pm - Provides an interface to the contents of a component's MakeRel project (mrp) file. |
|
2216 |
|
2217 =head1 DESCRIPTION |
|
2218 |
|
2219 Once a C<MrpData> object has been created using the C<New> method, the remaining methods can be used to access the F<.mrp> data. |
|
2220 |
|
2221 =head1 INTERFACE |
|
2222 |
|
2223 =head2 New |
|
2224 |
|
2225 Expects to be passed the name of the mrp file. This doesn't necessarily have to have a F<.mrp> extension. The parser supports the following keyword / value pairs: |
|
2226 |
|
2227 component <component_name> |
|
2228 source <source_file|source_directory> |
|
2229 binary [<abld_path> <platform> [<variant> <program>]] | [<binary_file>] | [<binary_directory>] |
|
2230 -binary [<abld_path> <platform> [<variant> <program>]] | [<binary_file>] | [<binary_directory>] |
|
2231 testbinary <abld_path> <platform> [<variant> <program>] |
|
2232 -testbinary <abld_path> <platform> [<variant> <program>] |
|
2233 exports <abld_path> |
|
2234 notes_source <release_notes_source_path> |
|
2235 ipr [<export-restricted>] type [<directory>] |
|
2236 |
|
2237 =head2 Component |
|
2238 |
|
2239 Returns a string containing the name of the component. |
|
2240 |
|
2241 =head2 MrpName |
|
2242 |
|
2243 Returns a string containing the full path name of the component's F<mrp> file. |
|
2244 |
|
2245 =head2 ExternalVersion |
|
2246 |
|
2247 Returns a string containing the external version of the component to be released. |
|
2248 |
|
2249 =head2 InternalVersion |
|
2250 |
|
2251 Returns a string containing the internal version of the component to be released. |
|
2252 |
|
2253 =head2 SourceCategories |
|
2254 |
|
2255 Returns a reference to a list of source IPR categories present in the component. Each of these may be used as an input to C<Source>. These categories are defined in 'distribution.policy' files. |
|
2256 |
|
2257 =head2 Source |
|
2258 |
|
2259 Expects to be passed a scalar containing the required source category. Returns a reference to a list of source files corresponding to the specified category for this component. |
|
2260 |
|
2261 =head2 SourceItems |
|
2262 |
|
2263 Expects no arguments. Returns a list of the operands of all the "source" statements found in the MRP file. This is then stored in the RelData file and is later used by validation to work out which director(y|ies) to check for added files. |
|
2264 |
|
2265 =head2 BinaryCategories |
|
2266 |
|
2267 Returns a reference to a list of binary categories present in the component. Each of these may be used as an input to C<Binaries>. The binary categories are determined by the structure of the F<mrp> file. For example, the statement C<binary \mycomp thumb urel> will result in the associated binaries being classified and C<thumb_urel>. The statement C<testbinary \mycomp arm4> will generate two categories - C<test_arm4_udeb> and C<test_arm4_urel>. Any binary files or directories that are explictly referenced (e.g. C<binary \epoc32\myfile.txt> or C<binary \epoc32\mydir>) are categorised as C<unclassified>. Also, any binary files that are found to be common between any two categories and re-categorised as C<unclassified>. This is to ensure that each binary F<zip> file contains a unique set of files. |
|
2268 |
|
2269 If the C<categorise_binaries> keyword has not been specified in the user's F<reltools.ini> file, this interface will always return a reference to a list with a single entry in it - C<unclassified>. |
|
2270 |
|
2271 =head2 Binaries |
|
2272 |
|
2273 Returns a reference to a list of binary files for this component. May optionally be passed a scalar containing the required binary category, in which case it returns a list of just the binaries in the specified category. Dies if the requested category is not present. |
|
2274 |
|
2275 =head2 ExportCategories |
|
2276 |
|
2277 Returns a reference to a list of export categories present in the component. If the C<categorise_exports> keyword has not been specified in the user's F<reltools.ini> file, this list will contain a single entry - C<unclassified>. Otherwise, each exported file will be categorised according to the rules used for categorising source code. The returned list will in this case contain the set of exported source categories present in the component. Elements in this list may be used as inputs to the method below (C<Exports>). |
|
2278 |
|
2279 =head2 Exports |
|
2280 |
|
2281 Returns a reference to a list of exported file for this component. May optionally be passed a scalar containing the required export category, in which case it returns a list of just the exports in the specified category. Dies if the requested category is not present. |
|
2282 |
|
2283 =head2 ExportInfoForCat |
|
2284 |
|
2285 Expects a category to be passed. Returns the exportinfo for the category. |
|
2286 |
|
2287 =head2 BinariesAndExports |
|
2288 |
|
2289 Returns a reference to a list of all the binaries and exports of this component. Note, unlike the methods C<Binaries> and C<Exports>, this method does not allow a category to be specified. This is because binaries are categorised according to build type and exports are categorised according to source intellectual property rights rules. They two types of categorisation are incompatible. |
|
2290 |
|
2291 =head2 NotesSource |
|
2292 |
|
2293 Returns a string containing the path and name of the release notes source file for this component. |
|
2294 |
|
2295 =head2 BinSets |
|
2296 |
|
2297 Returns a reference to an array of hashes, representing each "binary <path> <platform> <variant>" line. The hashes have these fields: path, plat, var, mmp (often ''), and test (a Boolean). This method is used by C<MakeRel> and C<MakeEnv> to build the component before release. |
|
2298 |
|
2299 =head2 EnsureDoesNotExist |
|
2300 |
|
2301 Checks that the version given does not already exist in an archive. |
|
2302 |
|
2303 =head2 Validate |
|
2304 |
|
2305 Checks that all the files shown in the MRP do actually exist. |
|
2306 |
|
2307 =head2 ClassifyAutomaticExports |
|
2308 |
|
2309 Classify exports that were specified using the 'exports' or 'testexports' keyword in the mrp file. |
|
2310 |
|
2311 =head2 ProcessExportMakeFile |
|
2312 |
|
2313 Expect EXPORT.MAKE/EXPORTTEST.MAKE file, classify exports that were specified using the 'exports'/'testexports' keyword in the mrp file. |
|
2314 |
|
2315 =head2 WarnRedundantMRPLine |
|
2316 |
|
2317 Output warnings about redundant MRP lines (full redundancy). |
|
2318 |
|
2319 =head2 GetIPRInformation() |
|
2320 |
|
2321 Returns a hash containing the IPR information for the component. |
|
2322 |
|
2323 The format is the returned data is a hash: |
|
2324 |
|
2325 Path = ( |
|
2326 category = char, |
|
2327 exportRestricted = boolean |
|
2328 ) |
|
2329 |
|
2330 =head2 SetBinary(@arguments, test, remove) |
|
2331 |
|
2332 Sets the binary information. @arguments is an array containing the arguments |
|
2333 from the MRP line, in the order in which they appeared. |
|
2334 |
|
2335 =head2 SetComponent(componentName) |
|
2336 |
|
2337 Sets the name of the component to componentName. |
|
2338 |
|
2339 =head2 SetExportFile(source, destination, remove, dependantComponent) |
|
2340 |
|
2341 Sets the export file information. The source and destination arguments are both |
|
2342 required, if they are not specified a fatal error will be produced. The source |
|
2343 file will also be checked to see if it exists and that it has not already been |
|
2344 specified as an export file. |
|
2345 |
|
2346 If the export file is not included as source for the current MRP component then |
|
2347 the dependant component will also need to be specified. |
|
2348 |
|
2349 =head2 SetExports(path, test, dependantComponent) |
|
2350 |
|
2351 Sets the location of the bld.inf from where the export information can be derived. |
|
2352 The location will be checked to see if it exists and that it has not already been |
|
2353 specified. |
|
2354 |
|
2355 If the exports are not included as source for the current MRP component then |
|
2356 the dependant component will also need to be specified. |
|
2357 |
|
2358 =head2 SetIPR(category, path, exportRestricted) |
|
2359 |
|
2360 Sets the IPR information for the component. If no path is specified then the |
|
2361 IPR category is set to be the default category for the component. The |
|
2362 exportRestricted argument is boolean. |
|
2363 |
|
2364 If the same path is specified more than once a fatal error will be produced. |
|
2365 |
|
2366 =head2 SetNotesSource(noteSourcePath) |
|
2367 |
|
2368 Sets the notes source to the notesSourcePath specified. If the notes source has |
|
2369 already been set, or the path does not exist, a fatal error will be produced. |
|
2370 |
|
2371 =head2 SetSource(sourcePath) |
|
2372 |
|
2373 Adds the sourcePath to the list of included source entries for the component. |
|
2374 If the source path does not exist or the path has already been added then a |
|
2375 fatal error will be produced. |
|
2376 |
|
2377 =head2 ValidateParsing() |
|
2378 |
|
2379 This method needs to be called once the parser has finished setting all the |
|
2380 information. Currently this method reconciles IPR statements against the |
|
2381 components source, and also checks that required dependant components have |
|
2382 been set. |
|
2383 |
|
2384 If this method is not run then IPR information will be unavailable. |
|
2385 |
|
2386 =head2 GetExportComponentDependencies() |
|
2387 |
|
2388 Returns an array containing the any components which the current component has |
|
2389 dependencies on. |
|
2390 |
|
2391 =head2 Populated() |
|
2392 |
|
2393 The MRP file is parsed by a reader, which then populates this MRP object. The |
|
2394 Populated method returns a boolean value indicating if the object has been |
|
2395 populated. |
|
2396 |
|
2397 =head1 KNOWN BUGS |
|
2398 |
|
2399 None. |
|
2400 |
|
2401 =head1 COPYRIGHT |
|
2402 |
|
2403 Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2404 All rights reserved. |
|
2405 This component and the accompanying materials are made available |
|
2406 under the terms of the License "Eclipse Public License v1.0" |
|
2407 which accompanies this distribution, and is available |
|
2408 at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
2409 |
|
2410 Initial Contributors: |
|
2411 Nokia Corporation - initial contribution. |
|
2412 |
|
2413 Contributors: |
|
2414 |
|
2415 Description: |
|
2416 |
|
2417 |
|
2418 =cut |