602
|
1 |
#!/bin/perl -w
|
|
2 |
|
|
3 |
# Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
# All rights reserved.
|
|
5 |
# This component and the accompanying materials are made available
|
|
6 |
# under the terms of the License "Eclipse Public License v1.0"
|
|
7 |
# which accompanies this distribution, and is available
|
|
8 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
9 |
#
|
|
10 |
# Initial Contributors:
|
|
11 |
# Nokia Corporation - initial contribution.
|
|
12 |
#
|
|
13 |
# Contributors:
|
|
14 |
#
|
|
15 |
# Description:
|
|
16 |
# distillsrc.pm - compiles a list of source used in .mrp files, and deletes
|
|
17 |
# any unused source
|
|
18 |
#
|
|
19 |
#
|
|
20 |
|
|
21 |
package CDistillSrc;
|
|
22 |
|
|
23 |
use strict;
|
|
24 |
use File::Spec;
|
|
25 |
use File::Path;
|
|
26 |
use File::Basename;
|
|
27 |
use FindBin;
|
|
28 |
use lib $FindBin::Bin;
|
|
29 |
use ReadMrp;
|
|
30 |
|
|
31 |
use lib File::Spec->catdir($FindBin::Bin, '..', 'makecbr');
|
|
32 |
use CConfig;
|
|
33 |
|
|
34 |
|
|
35 |
|
|
36 |
# Constructor
|
|
37 |
#
|
|
38 |
# Parameters:
|
|
39 |
#
|
|
40 |
# $aSrcRoot : The root from which all src statements are based
|
|
41 |
# $aSrcPath : The path under aSrcRoot to the source tree to be processed
|
|
42 |
# $aSrcPrefix : An optional prefix which can be stripped from all src statements
|
|
43 |
# $aPlatform : e.g 'beech' - used to locate the platform specific product directory
|
|
44 |
#
|
|
45 |
# Returns: The object (or undef if there was a problem)
|
|
46 |
#
|
|
47 |
sub New($$$$)
|
|
48 |
{
|
|
49 |
my $proto = shift;
|
|
50 |
my ($aSrcRoot, $aSrcPath, $aSrcPrefix, $aPlatform, $aCheckCase) = @_;
|
|
51 |
|
|
52 |
my $class = ref($proto) || $proto;
|
|
53 |
|
|
54 |
my $self = {};
|
|
55 |
bless($self, $class);
|
|
56 |
|
|
57 |
my $error = 0;
|
|
58 |
|
|
59 |
if (!defined($aSrcRoot))
|
|
60 |
{
|
|
61 |
print "ERROR: RealTimeBuild: A srcroot must be given, to specify where all 'source' declarations originate from\n";
|
|
62 |
$error = 1;
|
|
63 |
}
|
|
64 |
|
|
65 |
if (!defined($aSrcPath))
|
|
66 |
{
|
|
67 |
print "ERROR: RealTimeBuild: A srcpath must be given, to specify which source under the srcroot is to be filtered. Use '\\' to filter the entire srcroot\n";
|
|
68 |
$error = 1;
|
|
69 |
}
|
|
70 |
|
|
71 |
if (!defined($aPlatform))
|
|
72 |
{
|
|
73 |
print "ERROR: RealTimeBuild: A platform must be given, to locate the product directory\n";
|
|
74 |
$error = 1;
|
|
75 |
}
|
|
76 |
|
|
77 |
if ($error)
|
|
78 |
{
|
|
79 |
print "\n";
|
|
80 |
}
|
|
81 |
else
|
|
82 |
{
|
|
83 |
if ($aSrcPath =~ /\.\./)
|
|
84 |
{
|
|
85 |
print "ERROR: RealTimeBuild: The source path must be relative to the srcroot, and must not contain '..'\n";
|
|
86 |
$error = 1;
|
|
87 |
}
|
|
88 |
|
|
89 |
$self->iSrcRoot($aSrcRoot);
|
|
90 |
$self->iSrcPath($aSrcPath);
|
|
91 |
$self->iSrcPrefix($aSrcPrefix);
|
|
92 |
$self->iPlatform($aPlatform);
|
|
93 |
$self->iSrcItems({});
|
|
94 |
$self->iCheckCase(!!$aCheckCase);
|
|
95 |
|
|
96 |
$self->AddSrcItem("os/buildtools/toolsandutils/productionbldtools/unref/orphan/cedprd/SuppKit", "non-shipped");
|
|
97 |
$self->AddSrcItem("os/buildtools/toolsandutils/productionbldtools/unref/orphan/cedprd/tools", "non-shipped");
|
|
98 |
$self->AddSrcItem("os/buildtools/toolsandutils/productionbldtools/unref/orphan/cedprd/DevKit", "non-shipped");
|
|
99 |
$self->AddSrcItem("os/buildtools/toolsandutils/productionbldtools", "non-shipped");
|
|
100 |
}
|
|
101 |
|
|
102 |
if ($error)
|
|
103 |
{
|
|
104 |
$self = undef;
|
|
105 |
}
|
|
106 |
|
|
107 |
return $self;
|
|
108 |
}
|
|
109 |
|
|
110 |
# Object data
|
|
111 |
#
|
|
112 |
sub iSrcRoot()
|
|
113 |
{
|
|
114 |
my $self = shift;
|
|
115 |
if (@_) { $self->{iSRCROOT} = shift; }
|
|
116 |
return $self->{iSRCROOT};
|
|
117 |
}
|
|
118 |
|
|
119 |
sub iSrcPath()
|
|
120 |
{
|
|
121 |
my $self = shift;
|
|
122 |
if (@_) { $self->{iSRCPATH} = shift; }
|
|
123 |
return $self->{iSRCPATH};
|
|
124 |
}
|
|
125 |
|
|
126 |
sub iSrcPrefix()
|
|
127 |
{
|
|
128 |
my $self = shift;
|
|
129 |
if (@_) { $self->{iSRCPREFIX} = shift; }
|
|
130 |
return $self->{iSRCPREFIX};
|
|
131 |
}
|
|
132 |
|
|
133 |
sub iPlatform()
|
|
134 |
{
|
|
135 |
my $self = shift;
|
|
136 |
if (@_) { $self->{iPLATFORM} = shift; }
|
|
137 |
return $self->{iPLATFORM};
|
|
138 |
}
|
|
139 |
|
|
140 |
sub iSrcItems()
|
|
141 |
{
|
|
142 |
my $self = shift;
|
|
143 |
if (@_) { $self->{iSRCITEMS} = shift; }
|
|
144 |
return $self->{iSRCITEMS};
|
|
145 |
}
|
|
146 |
|
|
147 |
sub iCheckCase()
|
|
148 |
{
|
|
149 |
my $self = shift;
|
|
150 |
if (@_) { $self->{iCHECKCASE} = shift; }
|
|
151 |
return $self->{iCHECKCASE};
|
|
152 |
}
|
|
153 |
|
|
154 |
sub iCorrectedCase()
|
|
155 |
{
|
|
156 |
my $self = shift;
|
|
157 |
if (@_) { $self->{iCORRECTEDCASE} = shift; }
|
|
158 |
return $self->{iCORRECTEDCASE};
|
|
159 |
}
|
|
160 |
|
|
161 |
# LoadMrps - Records the source lines out of all .mrp files
|
|
162 |
#
|
|
163 |
# Parameters:
|
|
164 |
# $aConfig - optional configuration file, as used by makecbr
|
|
165 |
# $aLists - optional component lists, as used by makecbr
|
|
166 |
# $aMrps - optional .mrp files
|
|
167 |
#
|
|
168 |
# Returns: True, if the load was successful. False otherwise
|
|
169 |
#
|
|
170 |
sub LoadMrps($$$)
|
|
171 |
{
|
|
172 |
my $self = shift;
|
|
173 |
my ($aConfig, $aLists, $aMrps) = @_;
|
|
174 |
# Load in config file
|
|
175 |
|
|
176 |
my @lists = @$aLists;
|
|
177 |
my @mrps;
|
|
178 |
foreach my $mrp (@$aMrps){
|
|
179 |
{
|
|
180 |
push @mrps, [$mrp, ''];
|
|
181 |
}
|
|
182 |
}
|
|
183 |
my @configMrps = ();
|
|
184 |
if (defined($aConfig))
|
|
185 |
{
|
|
186 |
my @configs = $self->_LoadConfig($aConfig);
|
|
187 |
|
|
188 |
# Add mrps and lists (after planting them in srcroot)
|
|
189 |
push @lists, map($self->_PlantFile($_), @{$configs[0]});
|
|
190 |
@configMrps = map($self->_PlantFile($_), @{$configs[1]});
|
|
191 |
foreach my $mrp (@configMrps)
|
|
192 |
{
|
|
193 |
push @mrps, [$mrp, ''];
|
|
194 |
}
|
|
195 |
}
|
|
196 |
|
|
197 |
# Load in mrp lists
|
|
198 |
foreach my $file (@lists)
|
|
199 |
{
|
|
200 |
if (open (MRPLIST, $file))
|
|
201 |
{
|
|
202 |
foreach my $line (<MRPLIST>)
|
|
203 |
{
|
|
204 |
chomp $line;
|
|
205 |
$line =~ s/#.*$//; # Remove comments
|
|
206 |
$line =~ s/^\s*//; # Remove extraneous spaces
|
|
207 |
$line =~ s/\s*$//;
|
|
208 |
|
|
209 |
if ($line ne "")
|
|
210 |
{
|
|
211 |
my @parms = split(/\s+/, $line);
|
|
212 |
|
|
213 |
if (scalar(@parms) != 2)
|
|
214 |
{
|
|
215 |
warn "ERROR: RealTimeBuild: Entries in component list '$file' should be of the form 'name mrp_location'. Problem in line: $line\n";
|
|
216 |
next;
|
|
217 |
}
|
|
218 |
else
|
|
219 |
{
|
|
220 |
# Ignore *nosource* entries
|
|
221 |
next if ($parms[1] eq '*nosource*');
|
|
222 |
|
|
223 |
push @mrps, [$self->_PlantFile($parms[1]), $parms[0]];
|
|
224 |
}
|
|
225 |
}
|
|
226 |
}
|
|
227 |
close MRPLIST or warn "ERROR: RealTimeBuild: Couldn't close '$file' : $!\n";
|
|
228 |
}
|
|
229 |
else
|
|
230 |
{
|
|
231 |
warn "Couldn't open '$file' : $!\n";
|
|
232 |
}
|
|
233 |
}
|
|
234 |
|
|
235 |
# Load all .mrp files
|
|
236 |
if (scalar(@mrps) == 0)
|
|
237 |
{
|
|
238 |
die "ERROR: RealTimeBuild: No .mrp files were specified\n";
|
|
239 |
}
|
|
240 |
|
|
241 |
my $loaded = 1;
|
|
242 |
|
|
243 |
foreach my $mrp (@mrps)
|
|
244 |
{
|
|
245 |
# Get path of mrp file (from here)
|
|
246 |
my ($name, $path) = fileparse($mrp->[0]);
|
|
247 |
# Convert to path from source root
|
|
248 |
if (!($self->_RemoveBaseFromPath($self->iSrcRoot(), \$path)))
|
|
249 |
{
|
|
250 |
warn "ERROR: Mrp file $mrp->[0] isn't under the source root (".$self->iSrcRoot().")\n";
|
|
251 |
next;
|
|
252 |
}
|
|
253 |
|
|
254 |
my $mrpobj;
|
|
255 |
|
|
256 |
# To indicate the correct case and where the .mrp file comes from if failed to check letter case
|
|
257 |
if (!($self->_CheckCase($mrp->[0]))) {
|
|
258 |
my $mrp_error_source = "optional component list(by -f) or optional .mrp list(by -m)";
|
|
259 |
foreach my $myName (@configMrps) {
|
|
260 |
if ($myName eq $mrp->[0]) {
|
|
261 |
$mrp_error_source = "config file '".$aConfig."'";
|
|
262 |
last;
|
|
263 |
}
|
|
264 |
}
|
|
265 |
print "WARNING: Case of '".$mrp->[0]."' supplied in ".$mrp_error_source." does not match the file system. Should be ".$self->iCorrectedCase()."\n";
|
|
266 |
}
|
|
267 |
|
|
268 |
if (!eval { $mrpobj = New ReadMrp($mrp->[0]) })
|
|
269 |
{
|
|
270 |
$loaded = 0;
|
|
271 |
my $message = $@;
|
|
272 |
$message =~ s/^(ERROR:\s*)?/ERROR: RealTimeBuild: /i;
|
|
273 |
print $message;
|
|
274 |
}
|
|
275 |
else
|
|
276 |
{
|
|
277 |
my $selfowned = 0;
|
|
278 |
my $mrpComponentName = $mrpobj->GetComponent();
|
|
279 |
if( ($mrp->[1] ne '') && (lc($mrp->[1]) ne lc($mrpComponentName)))
|
|
280 |
{
|
|
281 |
print "ERROR: RealTimeBuild: Component name \'$mrp->[1]\' does not match \'$mrpComponentName\' in $mrp->[0]\n";
|
|
282 |
}
|
|
283 |
foreach my $srcitem (@{$mrpobj->GetSrcItems()})
|
|
284 |
{
|
|
285 |
if ($srcitem =~ /^[\/\\]/)
|
|
286 |
{
|
|
287 |
# Remove source prefix
|
|
288 |
$srcitem = $self->_StripFile($srcitem);
|
|
289 |
}
|
|
290 |
else
|
|
291 |
{
|
|
292 |
# Relative source item
|
|
293 |
$srcitem = File::Spec->catdir($path, $srcitem);
|
|
294 |
}
|
|
295 |
|
|
296 |
my $rootedmrp = $path.$name;
|
|
297 |
if ($self->_RemoveBaseFromPath($srcitem, \$rootedmrp))
|
|
298 |
{
|
|
299 |
$selfowned = 1;
|
|
300 |
}
|
|
301 |
|
|
302 |
$self->AddSrcItem($srcitem, $mrpComponentName);
|
|
303 |
}
|
|
304 |
if ($self->iCheckCase())
|
|
305 |
{
|
|
306 |
foreach my $binexpitem (@{$mrpobj->GetBinExpItems()})
|
|
307 |
{
|
|
308 |
# Check lower case
|
|
309 |
if ($binexpitem =~ /[A-Z]/)
|
|
310 |
{
|
|
311 |
print "REMARK: [$mrpComponentName] Binary/export file $binexpitem should be lower case\n";
|
|
312 |
}
|
|
313 |
}
|
|
314 |
}
|
|
315 |
|
|
316 |
if (!$selfowned)
|
|
317 |
{
|
|
318 |
print "REMARK: .mrp file '$mrp->[0]' does not include itself as source\n";
|
|
319 |
}
|
|
320 |
}
|
|
321 |
}
|
|
322 |
return $loaded;
|
|
323 |
}
|
|
324 |
|
|
325 |
# AddSrcItem - Records a source file, usually taken from an .mrp file
|
|
326 |
#
|
|
327 |
# Parameters:
|
|
328 |
# $aItem - the source file name
|
|
329 |
# $aComponent - the name of the component which claimed the file
|
|
330 |
#
|
|
331 |
# Returns: None
|
|
332 |
# Dies: Not normally; only if the source hash data structure gets corrupted
|
|
333 |
sub AddSrcItem($$)
|
|
334 |
{
|
|
335 |
my $self = shift;
|
|
336 |
my ($aItem, $aComponent) = @_;
|
|
337 |
|
|
338 |
my $item = $aItem;
|
|
339 |
|
|
340 |
# Worth checking that the file exists
|
|
341 |
my $truePath = File::Spec->catdir($self->iSrcRoot(), $item);
|
|
342 |
if (($item !~ /^\\component_defs/i) && (!-e $truePath))
|
|
343 |
{
|
|
344 |
print "ERROR: RealTimeBuild: '$aComponent' owns $item, but that path doesn't exist\n";
|
|
345 |
$item = ""; # No point adding this path to the tree
|
|
346 |
}
|
|
347 |
else
|
|
348 |
{
|
|
349 |
# Check case consistency
|
|
350 |
$self->_CheckCase($truePath) or print "WARNING: [$aComponent] Case of '".$truePath."' does not match the file system. Should be ".$self->iCorrectedCase()."\n";
|
|
351 |
}
|
|
352 |
|
|
353 |
$item =~ s/^[\/\\]*//; # Remove preceding slashes
|
|
354 |
|
|
355 |
my @path = split(/[\/\\]+/,$item);
|
|
356 |
|
|
357 |
my $dir = $self->iSrcItems();
|
|
358 |
while ((scalar @path) > 0)
|
|
359 |
{
|
|
360 |
my $subdir = lc(shift @path);
|
|
361 |
|
|
362 |
if (scalar(@path) == 0)
|
|
363 |
{
|
|
364 |
# Just enter the final path segment
|
|
365 |
if (exists($dir->{$subdir}))
|
|
366 |
{
|
|
367 |
# Someone already owns at least part of this path
|
|
368 |
if (!ref($dir->{$subdir}))
|
|
369 |
{
|
|
370 |
# Someone owns the whole of this path
|
|
371 |
my $conflict = $dir->{$subdir};
|
|
372 |
|
|
373 |
print "REMARK: $aComponent and $conflict both own $item\n";
|
|
374 |
}
|
|
375 |
else
|
|
376 |
{
|
|
377 |
if (ref($dir->{$subdir}) ne "HASH")
|
|
378 |
{
|
|
379 |
die "ERROR: Source hash is corrupted\n";
|
|
380 |
}
|
|
381 |
else
|
|
382 |
{
|
|
383 |
# Someone owns a child of this path
|
|
384 |
my $childtree = $dir->{$subdir};
|
|
385 |
|
|
386 |
my @conflicts = $self->_GetTreeComps($childtree);
|
|
387 |
print "REMARK: $aComponent owns $item, which is already owned by the following component(s): ".join(", ",@conflicts)."\n";
|
|
388 |
}
|
|
389 |
}
|
|
390 |
}
|
|
391 |
$dir->{$subdir} = $aComponent;
|
|
392 |
}
|
|
393 |
else
|
|
394 |
{
|
|
395 |
# Need to enter another subdirectory
|
|
396 |
|
|
397 |
if (exists($dir->{$subdir}))
|
|
398 |
{
|
|
399 |
if (ref($dir->{$subdir}))
|
|
400 |
{
|
|
401 |
# Someone already has - just do a quick integrity check
|
|
402 |
|
|
403 |
if (ref($dir->{$subdir}) ne "HASH")
|
|
404 |
{
|
|
405 |
die "ERROR: Source hash is corrupted\n";
|
|
406 |
}
|
|
407 |
}
|
|
408 |
else
|
|
409 |
{
|
|
410 |
# The path from this point on is already owned by a component
|
|
411 |
my $conflict = $dir->{$subdir};
|
|
412 |
|
|
413 |
print "REMARK: $aComponent and $conflict both own $item\n";
|
|
414 |
last;
|
|
415 |
}
|
|
416 |
}
|
|
417 |
else
|
|
418 |
{
|
|
419 |
$dir->{$subdir} = {};
|
|
420 |
}
|
|
421 |
}
|
|
422 |
|
|
423 |
$dir = $dir->{$subdir};
|
|
424 |
}
|
|
425 |
}
|
|
426 |
|
|
427 |
# DistillSrc - Compare the recorded source lines against the source path. Delete anything which doesn't match.
|
|
428 |
#
|
|
429 |
# Parameters:
|
|
430 |
# $aDummy - A flag - non-zero means don't actually delete
|
|
431 |
#
|
|
432 |
# Returns: None
|
|
433 |
sub DistillSrc($$)
|
|
434 |
{
|
|
435 |
my $self = shift;
|
|
436 |
my ($aDummy) = @_;
|
|
437 |
|
|
438 |
my $tree = $self->iSrcItems();
|
|
439 |
my $path = File::Spec->catdir($self->iSrcRoot(), $self->iSrcPath());
|
|
440 |
|
|
441 |
$path=~s/[\/\\]+/\\/; # Remove multiple slashes
|
|
442 |
|
|
443 |
# Pop the srcpath off the front of the tree
|
|
444 |
my @path = split(/[\/\\]/,$self->iSrcPath());
|
|
445 |
|
|
446 |
foreach my $dir (@path)
|
|
447 |
{
|
|
448 |
if ($dir eq ".")
|
|
449 |
{
|
|
450 |
next;
|
|
451 |
}
|
|
452 |
elsif (exists($tree->{lc($dir)}))
|
|
453 |
{
|
|
454 |
$tree = $tree->{lc($dir)};
|
|
455 |
|
|
456 |
if (!ref($tree))
|
|
457 |
{
|
|
458 |
# Some component owns all of the srcpath
|
|
459 |
last;
|
|
460 |
}
|
|
461 |
}
|
|
462 |
else
|
|
463 |
{
|
|
464 |
# No mrp files claimed any of the source
|
|
465 |
$tree = undef;
|
|
466 |
last;
|
|
467 |
}
|
|
468 |
}
|
|
469 |
|
|
470 |
# Now recurse into the tree and delete files
|
|
471 |
if (defined($tree))
|
|
472 |
{
|
|
473 |
if (ref($tree))
|
|
474 |
{
|
|
475 |
$self->_DistillTree($tree, $path, $aDummy);
|
|
476 |
}
|
|
477 |
else
|
|
478 |
{
|
|
479 |
print "REMARK: All source owned by component '$tree'; no action\n";
|
|
480 |
}
|
|
481 |
}
|
|
482 |
else
|
|
483 |
{
|
|
484 |
print "WARNING: No .mrp files claim any source; removing $path\n";
|
|
485 |
$self->_DeletePath($path, $aDummy);
|
|
486 |
}
|
|
487 |
}
|
|
488 |
|
|
489 |
# Print - Display the source tree
|
|
490 |
#
|
|
491 |
# Parameters:
|
|
492 |
# $aDepth - The number of levels of the tree to show. 0 = all levels
|
|
493 |
#
|
|
494 |
# Returns: None
|
|
495 |
sub Print($$)
|
|
496 |
{
|
|
497 |
my $self = shift;
|
|
498 |
|
|
499 |
my ($aDepth) = @_;
|
|
500 |
|
|
501 |
$self->_PrintTree("", $self->iSrcItems(), $aDepth);
|
|
502 |
}
|
|
503 |
|
|
504 |
# *** Private methods ***
|
|
505 |
# ***
|
|
506 |
|
|
507 |
# _LoadConfig - (private) Reads a configuration file, as used by makecbr
|
|
508 |
#
|
|
509 |
# Parameters:
|
|
510 |
# $aConfig - filename of the configuration file
|
|
511 |
#
|
|
512 |
# Returns:
|
|
513 |
# (files, mrps) - where files and mrps are listrefs containing component lists and
|
|
514 |
# mrp files respectively
|
|
515 |
#
|
|
516 |
sub _LoadConfig($)
|
|
517 |
{
|
|
518 |
my $self = shift;
|
|
519 |
my ($aConfig) = @_;
|
|
520 |
|
|
521 |
my @files = ();
|
|
522 |
my @mrps = ();
|
|
523 |
|
|
524 |
my $config = New CConfig($aConfig);
|
|
525 |
|
|
526 |
if (!defined $config)
|
|
527 |
{
|
|
528 |
die "Couldn't load config file '$aConfig'\n";
|
|
529 |
}
|
|
530 |
|
|
531 |
# Extract the interesting items into our lists
|
|
532 |
push @mrps, $config->Get("gt+techview baseline mrp location");
|
|
533 |
push @mrps, $config->Get("gt only baseline mrp location");
|
|
534 |
push @files, $config->Get("techview component list");
|
|
535 |
push @files, $config->Get("gt component list");
|
|
536 |
|
|
537 |
# Remove any items we couldn't find
|
|
538 |
@mrps = grep(defined($_), @mrps);
|
|
539 |
@files = grep(defined($_), @files);
|
|
540 |
|
|
541 |
return (\@files, \@mrps);
|
|
542 |
}
|
|
543 |
|
|
544 |
# _StripFile - (private) Remover of src prefix. Also maps product directories
|
|
545 |
#
|
|
546 |
# Parameters:
|
|
547 |
# $aFile - Filename to process
|
|
548 |
#
|
|
549 |
# Returns: The processed filename
|
|
550 |
#
|
|
551 |
sub _StripFile($)
|
|
552 |
{
|
|
553 |
my $self = shift;
|
|
554 |
my ($aFile) = @_;
|
|
555 |
|
|
556 |
my $file = $aFile;
|
|
557 |
|
|
558 |
# Map the product dirs
|
|
559 |
my $platform = $self->iPlatform();
|
|
560 |
$file =~ s#^[\/\\]?product[\/\\]#/sf/os/unref/orphan/cedprd/#i;
|
|
561 |
|
|
562 |
# Remove the prefix
|
|
563 |
my $prefix = $self->iSrcPrefix();
|
|
564 |
|
|
565 |
if (defined $prefix)
|
|
566 |
{
|
|
567 |
my $mapped = $file; # Keep a copy in case we can't remove the prefix
|
|
568 |
|
|
569 |
if (!$self->_RemoveBaseFromPath($prefix, \$file))
|
|
570 |
{
|
|
571 |
$file = $mapped;
|
|
572 |
}
|
|
573 |
}
|
|
574 |
|
|
575 |
return $file;
|
|
576 |
}
|
|
577 |
|
|
578 |
# _PlantFile - (private) Add src root to file. Also take off src prefix
|
|
579 |
#
|
|
580 |
# Parameters:
|
|
581 |
# $aFile - Filename to process
|
|
582 |
#
|
|
583 |
# Returns: The processed filename
|
|
584 |
#
|
|
585 |
sub _PlantFile($)
|
|
586 |
{
|
|
587 |
my $self = shift;
|
|
588 |
my ($aFile) = @_;
|
|
589 |
|
|
590 |
my $file = $aFile;
|
|
591 |
|
|
592 |
# Remove the prefix
|
|
593 |
$file = $self->_StripFile($file);
|
|
594 |
|
|
595 |
# Plant the file in the src root
|
|
596 |
$file = File::Spec->catdir($self->iSrcRoot(), $file);
|
|
597 |
|
|
598 |
# Ensure all slashes are normalised to a single backslash
|
|
599 |
$file =~ s/[\/\\]+/\\/;
|
|
600 |
|
|
601 |
return $file;
|
|
602 |
}
|
|
603 |
|
|
604 |
# _RemoveBaseFromPath - (private) Remove a base path from the root of a filename.
|
|
605 |
#
|
|
606 |
# Parameters:
|
|
607 |
# $aBase - The base path to remove
|
|
608 |
# $$aFile - Filename to process (scalar reference)
|
|
609 |
#
|
|
610 |
# Returns: True if the file was under the base path, false otherwise
|
|
611 |
# $$aFile may be corrupted if the return is false
|
|
612 |
sub _RemoveBaseFromPath($)
|
|
613 |
{
|
|
614 |
my $self = shift;
|
|
615 |
my ($aBase, $aFile) = @_;
|
|
616 |
|
|
617 |
my $base = $aBase;
|
|
618 |
$base =~ s/^[\/\\]*//; # Remove extra slashes
|
|
619 |
$base =~ s/[\/\\]*$//;
|
|
620 |
|
|
621 |
my @base = split(/[\/\\]+/, $base);
|
|
622 |
|
|
623 |
$$aFile =~ s/^[\/\\]*//; # Remove preceding slashes
|
|
624 |
|
|
625 |
my $matched = 1;
|
|
626 |
my $filedir;
|
|
627 |
|
|
628 |
foreach my $dir (@base)
|
|
629 |
{
|
|
630 |
if ($$aFile =~ /[\/\\]/)
|
|
631 |
{
|
|
632 |
# Split off the bottom dir
|
|
633 |
$$aFile =~ /([^\/\\]*)[\/\\]+(.*)$/;
|
|
634 |
($filedir, $$aFile) = ($1, $2, $3);
|
|
635 |
}
|
|
636 |
else
|
|
637 |
{
|
|
638 |
# Special case - no more dirs
|
|
639 |
$filedir = $$aFile;
|
|
640 |
$$aFile = "";
|
|
641 |
}
|
|
642 |
if (lc($filedir) ne lc($dir))
|
|
643 |
{
|
|
644 |
# Base doesn't match
|
|
645 |
$matched = 0;
|
|
646 |
last;
|
|
647 |
}
|
|
648 |
}
|
|
649 |
|
|
650 |
return $matched;
|
|
651 |
}
|
|
652 |
|
|
653 |
# _CheckCase - (private) Given a literal filename, compares the case of the
|
|
654 |
# file on the filesystem against the filename i.e. it
|
|
655 |
# can be used to enforce case sensitivity
|
|
656 |
#
|
|
657 |
# Parameters:
|
|
658 |
# $aFilename - The literal filename
|
|
659 |
#
|
|
660 |
# Returns: True if the file matches the supplied case.
|
|
661 |
# True if the file doesn't exist at all (user is expected to check that separately)
|
|
662 |
# True if case checking has been disabled.
|
|
663 |
# False otherwise (if the file exists but under a differing case).
|
|
664 |
#
|
|
665 |
# If false, the correctly cased name is present through $self->iCorrectedCase()
|
|
666 |
sub _CheckCase($)
|
|
667 |
{
|
|
668 |
my $self = shift;
|
|
669 |
my ($aFile) = @_;
|
|
670 |
|
|
671 |
return 1 if !($self->iCheckCase()); # checking disabled
|
|
672 |
return 1 if ($^O !~ /win32/i); # only works on Windows anyway
|
|
673 |
|
|
674 |
return 1 if (!-e $aFile); # file not found (under case-insensitive checking)
|
|
675 |
|
|
676 |
$self->iCorrectedCase(Win32::GetLongPathName($aFile));
|
|
677 |
return ($aFile eq $self->iCorrectedCase());
|
|
678 |
}
|
|
679 |
|
|
680 |
# _DistillTree - (private) Given a src tree and a dir, clean out any unowned files
|
|
681 |
#
|
|
682 |
# Parameters:
|
|
683 |
# %$aTree - The source tree (hash ref containing nested hash refs and string leaves)
|
|
684 |
# $aDir - The directory to compare against
|
|
685 |
# $aDummy - A flag - non-zero means don't do the actual deletion
|
|
686 |
#
|
|
687 |
# Returns: A flag - non-zero if there were any owned files present
|
|
688 |
sub _DistillTree($$$)
|
|
689 |
{
|
|
690 |
my $self = shift;
|
|
691 |
my ($aTree, $aDir, $aDummy) = @_;
|
|
692 |
|
|
693 |
|
|
694 |
my $keptsome = 0;
|
|
695 |
|
|
696 |
if (opendir(DIR, $aDir))
|
|
697 |
{
|
|
698 |
my $dir = $aDir;
|
|
699 |
$dir =~ s/[\/\\]*$//; # Remove trailing / from dir
|
|
700 |
|
|
701 |
foreach my $entry (readdir(DIR))
|
|
702 |
{
|
|
703 |
my $path = $dir."\\".$entry;
|
|
704 |
|
|
705 |
if ($entry =~ /^\.\.?$/)
|
|
706 |
{
|
|
707 |
next;
|
|
708 |
}
|
|
709 |
elsif (exists $aTree->{lc($entry)})
|
|
710 |
{
|
|
711 |
my $treeentry = $aTree->{lc($entry)};
|
|
712 |
if (ref($treeentry) eq "HASH")
|
|
713 |
{
|
|
714 |
# Part of this path is owned
|
|
715 |
if (-d $path)
|
|
716 |
{
|
|
717 |
# Recurse into path
|
|
718 |
my $keep = $self->_DistillTree($treeentry, $path, $aDummy);
|
|
719 |
if ($keep)
|
|
720 |
{
|
|
721 |
$keptsome = 1;
|
|
722 |
}
|
|
723 |
else
|
|
724 |
{
|
|
725 |
# Correction; none of this path was owned
|
|
726 |
$self->_DeletePath($path, $aDummy);
|
|
727 |
}
|
|
728 |
}
|
|
729 |
elsif (-f $path)
|
|
730 |
{
|
|
731 |
my @comps = $self->_GetTreeComps($treeentry);
|
|
732 |
print "ERROR: RealTimeBuild: $path is a file, yet is used as a directory in components: ".join(", ",@comps)."\n";
|
|
733 |
}
|
|
734 |
else
|
|
735 |
{
|
|
736 |
print "ERROR: $path has disappeared while it was being examined\n";
|
|
737 |
}
|
|
738 |
}
|
|
739 |
elsif (!ref($treeentry))
|
|
740 |
{
|
|
741 |
# This path is completely owned
|
|
742 |
$keptsome = 1;
|
|
743 |
next;
|
|
744 |
}
|
|
745 |
else
|
|
746 |
{
|
|
747 |
die "ERROR: Source hash is corrupted\n";
|
|
748 |
}
|
|
749 |
}
|
|
750 |
else
|
|
751 |
{
|
|
752 |
$self->_DeletePath($path, $aDummy);
|
|
753 |
}
|
|
754 |
}
|
|
755 |
|
|
756 |
closedir(DIR);
|
|
757 |
}
|
|
758 |
else
|
|
759 |
{
|
|
760 |
warn "ERROR: RealTimeBuild: Couldn't open directory '$aDir' for reading\n";
|
|
761 |
}
|
|
762 |
|
|
763 |
return $keptsome;
|
|
764 |
}
|
|
765 |
|
|
766 |
# _GetTreeComps - (private) Get all the leaves out of a tree (or component
|
|
767 |
# names out of a source tree)
|
|
768 |
# Parameters:
|
|
769 |
# %$aTree - The source tree (hash ref containing nested hash refs and string leaves)
|
|
770 |
#
|
|
771 |
# Returns: A list of strings found at the leaves (or component names)
|
|
772 |
sub _GetTreeComps($)
|
|
773 |
{
|
|
774 |
my $self = shift;
|
|
775 |
my ($aTree) = @_;
|
|
776 |
|
|
777 |
my @comps = ();
|
|
778 |
|
|
779 |
foreach my $entry (keys(%$aTree))
|
|
780 |
{
|
|
781 |
if (ref($aTree->{$entry}) eq "HASH")
|
|
782 |
{
|
|
783 |
push @comps, $self->_GetTreeComps($aTree->{$entry});
|
|
784 |
}
|
|
785 |
elsif (!ref($aTree->{$entry}))
|
|
786 |
{
|
|
787 |
push @comps, $aTree->{$entry};
|
|
788 |
}
|
|
789 |
else
|
|
790 |
{
|
|
791 |
die "ERROR: Source hash is corrupted\n";
|
|
792 |
}
|
|
793 |
}
|
|
794 |
|
|
795 |
return @comps;
|
|
796 |
}
|
|
797 |
|
|
798 |
# _DeletePath - (private) Safe path deletion (file or dir)
|
|
799 |
#
|
|
800 |
# $aPath - The path to delet
|
|
801 |
# $aDummy - A flag - non-zero means don't actually delete
|
|
802 |
#
|
|
803 |
# Returns: None. Prints warnings if deletion fails. Dies only in exceptional circumstances
|
|
804 |
sub _DeletePath($$)
|
|
805 |
{
|
|
806 |
my $self = shift;
|
|
807 |
|
|
808 |
my ($aPath, $aDummy) = @_;
|
|
809 |
|
|
810 |
if (-d $aPath)
|
|
811 |
{
|
|
812 |
if ($aDummy)
|
|
813 |
{
|
|
814 |
print "DUMMY: Directory $aPath is not specified in any .mrp file\n";
|
|
815 |
}
|
|
816 |
else
|
|
817 |
{
|
|
818 |
print "REMARK: Deleting directory $aPath; ";
|
|
819 |
my $files = rmtree($aPath);
|
|
820 |
if ($files)
|
|
821 |
{
|
|
822 |
print "$files items removed\n";
|
|
823 |
}
|
|
824 |
else
|
|
825 |
{
|
|
826 |
print "\nWARNING: Problem removing directory $aPath\n";
|
|
827 |
}
|
|
828 |
}
|
|
829 |
}
|
|
830 |
elsif (-f $aPath)
|
|
831 |
{
|
|
832 |
if ($aDummy)
|
|
833 |
{
|
|
834 |
print "DUMMY: File $aPath is not specified in any .mrp file\n";
|
|
835 |
}
|
|
836 |
else
|
|
837 |
{
|
|
838 |
unless($aPath =~ /distribution.policy.s60/i)
|
|
839 |
{
|
|
840 |
print "REMARK: Deleting file $aPath\n";
|
|
841 |
unlink $aPath or print "WARNING: Problem deleting file $aPath\n";
|
|
842 |
}
|
|
843 |
}
|
|
844 |
}
|
|
845 |
else
|
|
846 |
{
|
|
847 |
warn "ERROR: Can't delete path $aPath; not a file or directory\n";
|
|
848 |
}
|
|
849 |
}
|
|
850 |
|
|
851 |
# _PrintTree - Display a subset of the source tree
|
|
852 |
#
|
|
853 |
# Parameters:
|
|
854 |
# $aPrefix - The string to prefix all paths
|
|
855 |
# $aDepth - The number of levels of the tree to show. 0 = all levels
|
|
856 |
#
|
|
857 |
# Returns: None
|
|
858 |
sub _PrintTree($$$)
|
|
859 |
{
|
|
860 |
my $self = shift;
|
|
861 |
|
|
862 |
my ($aPrefix, $aTree, $aDepth) = @_;
|
|
863 |
|
|
864 |
my $prefix = "";
|
|
865 |
|
|
866 |
if ($aPrefix ne "")
|
|
867 |
{
|
|
868 |
$prefix = $aPrefix."\\";
|
|
869 |
}
|
|
870 |
|
|
871 |
foreach my $key (sort(keys(%$aTree)))
|
|
872 |
{
|
|
873 |
if (ref($aTree->{$key}))
|
|
874 |
{
|
|
875 |
if ($aDepth!=1)
|
|
876 |
{
|
|
877 |
my $newprefix = $prefix.$key;
|
|
878 |
|
|
879 |
if ($key eq "")
|
|
880 |
{
|
|
881 |
$newprefix.="{empty}";
|
|
882 |
}
|
|
883 |
|
|
884 |
$self->_PrintTree($newprefix, $aTree->{$key}, $aDepth-1);
|
|
885 |
}
|
|
886 |
else
|
|
887 |
{
|
|
888 |
print $prefix.$key."\\...\n";
|
|
889 |
}
|
|
890 |
}
|
|
891 |
else
|
|
892 |
{
|
|
893 |
print $prefix.$key." = ".$aTree->{$key}."\n";
|
|
894 |
}
|
|
895 |
}
|
|
896 |
}
|
|
897 |
|
|
898 |
1;
|