|
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 EnvDb; |
|
17 |
|
18 use strict; |
|
19 use MLDBM::Sync; # this gets the default, SDBM_File |
|
20 use MLDBM qw(DB_File Storable); # use Storable for serializing |
|
21 use MLDBM qw(MLDBM::Sync::SDBM_File); # use extended SDBM_File, handles values > 1024 bytes |
|
22 use Fcntl qw(:DEFAULT); # import symbols O_CREAT & O_RDWR for use with DBMs |
|
23 use Cwd; |
|
24 use File::Find; |
|
25 use File::Copy; |
|
26 use File::Basename; |
|
27 use File::Path; |
|
28 use File::Spec; |
|
29 use Fcntl; |
|
30 use MrpData; |
|
31 use RelData; |
|
32 use DirHandle; # we're recursing in CrossCheckSourceDirectory, so this is slightly nicer than DIRHANDLEs |
|
33 # (though not actually necessary, as it happens) |
|
34 use Utils; |
|
35 use CatData; |
|
36 use Carp; |
|
37 use Symbian::CBR::Component::Manifest; |
|
38 |
|
39 # |
|
40 # Constants. |
|
41 # |
|
42 |
|
43 use constant DB_NAME => "\\epoc32\\relinfo\\envdb"; |
|
44 use constant STATUS_CLEAN => 0; |
|
45 use constant STATUS_DIRTY => 1; |
|
46 use constant STATUS_PENDING_RELEASE => 2; |
|
47 use constant STATUS_INFORMATION_ONLY => 5; |
|
48 use constant STATUS_NOT_INSTALLED => 3; |
|
49 use constant STATUS_DIRTY_SOURCE => 4; |
|
50 use constant STATUS_STRING_PASSED => "clean"; |
|
51 use constant STATUS_STRING_FAILED => "dirty"; |
|
52 use constant STATUS_STRING_MISSING => "missing"; |
|
53 use constant STATUS_STRING_PENDING_RELEASE => "pending release"; |
|
54 use constant STATUS_STRING_NOT_INSTALLED => "not installed"; |
|
55 use constant STATUS_STRING_DIRTY_SOURCE => "binaries clean, source dirty"; |
|
56 use constant STATUS_STRING_INFORMATION_ONLY => "Information only"; |
|
57 use constant SCAN_PROGRESS_TUNER => 50; |
|
58 use constant ACCEPTABLE_EVALID_FAILURES => "abld.bat"; # this is a regexp - use | to add more items. It is case-insensitive. |
|
59 |
|
60 # |
|
61 # Public. |
|
62 # |
|
63 |
|
64 sub Open { |
|
65 my $pkg = shift; |
|
66 my $iniData = shift; |
|
67 my $verbose = shift; |
|
68 |
|
69 # Check that the environment is not on an illegal volume - INC105548 |
|
70 Utils::CheckIllegalVolume($iniData); |
|
71 |
|
72 my $dbName = Utils::PrependEpocRoot(DB_NAME); |
|
73 my $dbDir = dirname($dbName); |
|
74 unless (-e $dbDir) { |
|
75 Utils::MakeDir($dbDir); |
|
76 } |
|
77 my $db; |
|
78 { |
|
79 local $^W = 0; |
|
80 tie (%{$db}, 'MLDBM::Sync', $dbName, O_CREAT|O_RDWR, 0666) || die "Couldn't open database DB_NAME: $!\n"; |
|
81 } |
|
82 |
|
83 my $self = {iniData => $iniData, |
|
84 db => $db, |
|
85 mrpcache => {}, |
|
86 verbose => ($verbose || 0)}; |
|
87 bless $self, $pkg; |
|
88 return $self; |
|
89 } |
|
90 |
|
91 sub Close { |
|
92 my $self = shift; |
|
93 untie %{$self}; |
|
94 } |
|
95 |
|
96 sub ComponentExistsInDatabase { |
|
97 my $self = shift; |
|
98 my $comp = shift; |
|
99 |
|
100 return 1 if (exists $self->{db}->{$comp}); |
|
101 } |
|
102 |
|
103 sub Version { |
|
104 my $self = shift; |
|
105 my $comp = shift; |
|
106 my $includeInformationOnlyEntries = shift; |
|
107 |
|
108 $comp = lc($comp); # Note, component names are always stored in lower case. |
|
109 my $entry = $self->{db}->{$comp}; |
|
110 |
|
111 if (defined $entry) { |
|
112 if (!$includeInformationOnlyEntries && $entry->{status} eq STATUS_INFORMATION_ONLY) { |
|
113 # Some callers are not interested in information only entries |
|
114 return undef; |
|
115 } |
|
116 |
|
117 return $entry->{ver}; |
|
118 } |
|
119 return undef; |
|
120 } |
|
121 |
|
122 sub VersionInfo { |
|
123 my $self = shift; |
|
124 my $includeInformationOnlyEntries = shift; |
|
125 |
|
126 my $versionInfo; |
|
127 foreach my $thisKey (keys %{$self->{db}}) { |
|
128 if (!$includeInformationOnlyEntries) { |
|
129 # Some callers are not interested in information only entries |
|
130 next if ($self->{db}->{$thisKey}->{status} eq STATUS_INFORMATION_ONLY); |
|
131 } |
|
132 |
|
133 $versionInfo->{$thisKey} = $self->{db}->{$thisKey}->{ver}; |
|
134 } |
|
135 return $versionInfo; |
|
136 } |
|
137 |
|
138 sub SetVersion { |
|
139 my $self = shift; |
|
140 my $comp = lc(shift); |
|
141 my $ver = shift; |
|
142 |
|
143 my $entry = $self->{db}->{$comp}; |
|
144 if (defined $ver) { |
|
145 if (defined $entry->{ver} and $entry->{status} != STATUS_PENDING_RELEASE) { |
|
146 $self->DeleteSignature($comp, $entry->{ver}); |
|
147 } |
|
148 $entry->{ver} = $ver; |
|
149 |
|
150 # Write entry to database. |
|
151 $self->{db}->{$comp} = $entry; |
|
152 } |
|
153 else { |
|
154 # undefined version, so remove entry from database (if it was present). |
|
155 if (defined $entry) { |
|
156 delete $self->{db}->{$comp} |
|
157 } |
|
158 } |
|
159 } |
|
160 |
|
161 sub InternalVersion { |
|
162 my $self = shift; |
|
163 my $comp = shift; |
|
164 $comp = lc($comp); # Note, component names are always stored in lower case. |
|
165 my $entry = $self->{db}->{$comp}; |
|
166 if (defined $entry) { |
|
167 return $entry->{intVer}; |
|
168 } |
|
169 return undef; |
|
170 } |
|
171 |
|
172 sub SetInternalVersion { |
|
173 my $self = shift; |
|
174 my $comp = lc(shift); |
|
175 my $intVer = shift; |
|
176 |
|
177 my $entry = $self->{db}->{$comp}; |
|
178 unless (defined $entry) { |
|
179 die "Error: $comp not found in environment database\n"; |
|
180 } |
|
181 $entry->{intVer} = $intVer; |
|
182 |
|
183 # Write entry to database. |
|
184 $self->{db}->{$comp} = $entry; |
|
185 } |
|
186 |
|
187 sub Status { |
|
188 my $self = shift; |
|
189 my $comp = lc(shift); |
|
190 |
|
191 my $entry = $self->{db}->{$comp}; |
|
192 unless (defined $entry) { |
|
193 die "Error: $comp not found in environment database\n"; |
|
194 } |
|
195 |
|
196 return $entry->{status}; |
|
197 } |
|
198 |
|
199 sub SetStatus { |
|
200 my $self = shift; |
|
201 my $comp = lc(shift); |
|
202 my $status = shift; |
|
203 |
|
204 my $entry = $self->{db}->{$comp}; |
|
205 unless (defined $entry) { |
|
206 die "Error: $comp not found in environment database\n"; |
|
207 } |
|
208 $entry->{status} = $status; |
|
209 |
|
210 # Write entry to database. |
|
211 $self->{db}->{$comp} = $entry; |
|
212 } |
|
213 |
|
214 sub StatusString { |
|
215 my $status = shift; |
|
216 if ($status == STATUS_CLEAN) { |
|
217 return STATUS_STRING_PASSED; |
|
218 } |
|
219 elsif ($status == STATUS_DIRTY) { |
|
220 return STATUS_STRING_FAILED; |
|
221 } |
|
222 elsif ($status == STATUS_PENDING_RELEASE) { |
|
223 return STATUS_STRING_PENDING_RELEASE; |
|
224 } |
|
225 elsif ($status == STATUS_DIRTY_SOURCE) { |
|
226 return STATUS_STRING_DIRTY_SOURCE; |
|
227 } |
|
228 elsif ($status == STATUS_INFORMATION_ONLY) { |
|
229 return STATUS_STRING_INFORMATION_ONLY; |
|
230 } |
|
231 } |
|
232 |
|
233 sub CheckCompName { |
|
234 my $self = shift; |
|
235 my $comp = shift; |
|
236 die "Error: Component name can't begin with .(dot) \"$comp\".\n" if ($comp =~ m/^\./); |
|
237 } |
|
238 |
|
239 sub MrpName { |
|
240 my $self = shift; |
|
241 my $comp = lc(shift); |
|
242 |
|
243 my $entry = $self->{db}->{$comp}; |
|
244 unless (defined $entry) { |
|
245 die "Error: $comp not found in environment database\n"; |
|
246 } |
|
247 |
|
248 return $entry->{mrpName}; |
|
249 } |
|
250 |
|
251 sub SetMrpName { |
|
252 my $self = shift; |
|
253 my $comp = lc(shift); |
|
254 my $mrpName = shift; |
|
255 |
|
256 my $entry = $self->{db}->{$comp}; |
|
257 unless (defined $entry) { |
|
258 die "Error: $comp not found in environment database\n"; |
|
259 } |
|
260 |
|
261 $entry->{mrpName} = $mrpName; |
|
262 |
|
263 # Write entry to database. |
|
264 $self->{db}->{$comp} = $entry; |
|
265 } |
|
266 |
|
267 sub ComponentsPendingRelease { |
|
268 my $self = shift; |
|
269 my %comps; |
|
270 foreach my $thisComp (keys %{$self->{db}}) { |
|
271 my $thisEntry = $self->{db}->{$thisComp}; |
|
272 if ($thisEntry->{status} == STATUS_PENDING_RELEASE) { |
|
273 $comps{$thisComp} = {mrpName => $thisEntry->{mrpName}, |
|
274 ver => $thisEntry->{ver}, |
|
275 intVer => $thisEntry->{intVer}}; |
|
276 } |
|
277 } |
|
278 return \%comps; |
|
279 } |
|
280 |
|
281 sub GenerateSignature { |
|
282 my $self = shift; |
|
283 my $comp = lc (shift); |
|
284 my $ver = shift; |
|
285 my $sigName = SignatureName($comp, $ver); |
|
286 open (SIG, ">$sigName") or die "Error: Couldn't open $sigName: $!\n"; |
|
287 foreach my $thisBinZip (@{$self->RelevantBinaryZips($comp, $ver)}) { |
|
288 foreach my $file (@{Utils::ListZip($thisBinZip, 1)}) { |
|
289 my $fileER = Utils::PrependEpocRoot($file); |
|
290 if (-f $fileER) { |
|
291 (my $mTime, my $size) = Utils::FileModifiedTimeAndSize($fileER); |
|
292 unless (defined $size) { |
|
293 die "Error: Problem reading stats of \"$fileER\"\n"; |
|
294 } |
|
295 if ($self->{verbose} > 1) { |
|
296 print "Adding signature entry for \"$file\"\n"; |
|
297 print "\tmTime: $mTime (", scalar gmtime($mTime), "\n"; |
|
298 print "\tsize: $size\n"; |
|
299 } |
|
300 print SIG "$file\t$mTime\t$size\n"; |
|
301 } |
|
302 else { |
|
303 print "Warning: Unexpected entry in \"$thisBinZip\": \"$file\"\n $comp $ver could be corrupt or tampered with\n"; |
|
304 } |
|
305 } |
|
306 } |
|
307 close (SIG); |
|
308 } |
|
309 |
|
310 sub GenerateFakeSignature { |
|
311 # As GenerateSignature, except the mtime and size of each file is set to zero. |
|
312 # This is intended to be used when validating against an external baseline. |
|
313 my $self = shift; |
|
314 my $comp = lc (shift); |
|
315 my $ver = shift; |
|
316 my $sigName = SignatureName($comp, $ver); |
|
317 open (SIG, ">$sigName") or die "Error: Couldn't open $sigName: $!\n"; |
|
318 foreach my $thisBinZip (@{$self->RelevantBinaryZips($comp, $ver)}) { |
|
319 foreach my $file (@{Utils::ListZip($thisBinZip)}) { |
|
320 print SIG "$file\t0\t0\n"; |
|
321 } |
|
322 } |
|
323 close (SIG); |
|
324 } |
|
325 |
|
326 sub GenerateEmptySignature { |
|
327 my $self = shift; |
|
328 my $comp = lc (shift); |
|
329 my $ver = shift; |
|
330 my $sigName = SignatureName($comp, $ver); |
|
331 open (SIG, ">$sigName") or die "Error: Couldn't open $sigName: $!\n"; |
|
332 close (SIG); |
|
333 } |
|
334 |
|
335 sub RemoveComponent { |
|
336 my $self = shift; |
|
337 my $comp = lc(shift); |
|
338 |
|
339 # Read database entry. |
|
340 my $entry = $self->{db}->{$comp}; |
|
341 |
|
342 if (defined $entry) { |
|
343 # Remove installed binaries. |
|
344 if ($self->{verbose}) { print "Removing binaries from $comp $entry->{ver}...\n"; } |
|
345 $self->DeleteFilesInSignature($comp, $entry->{ver}); |
|
346 $self->DeleteSignature($comp, $entry->{ver}); |
|
347 |
|
348 # Remove the database entry. |
|
349 delete $self->{db}->{$comp}; |
|
350 } |
|
351 else { |
|
352 print "$comp not currently installed, aborting removal of binaries\n"; |
|
353 } |
|
354 } |
|
355 |
|
356 sub RefreshComponent { |
|
357 my $self = shift; |
|
358 my $comp = lc(shift); |
|
359 my $overwrite = shift; |
|
360 |
|
361 # Read database entry. |
|
362 my $entry = $self->{db}->{$comp}; |
|
363 |
|
364 if (!defined $entry) { |
|
365 print "$comp not currently installed; aborting refreshing of binaries\n"; |
|
366 } elsif ($entry->{status} == STATUS_PENDING_RELEASE) { |
|
367 print "$comp is pending release and cannot be refreshed; use 'preprel' to remove it from your environment\n"; |
|
368 } else { |
|
369 my $ver = $entry->{ver}; |
|
370 |
|
371 my $relData = RelData->Open($self->{iniData}, $comp, $ver, $self->{verbose}); # Dies if release not in archive |
|
372 $relData->WarnIfReleaseTooNew(); |
|
373 |
|
374 print "Removing $comp $ver..\n"; |
|
375 if ($self->{verbose}) { print "Removing binaries from $comp $ver...\n"; } |
|
376 $self->DeleteFilesInSignature($comp, $entry->{ver}); |
|
377 |
|
378 print "Installing $comp $ver...\n"; |
|
379 $self->UnpackBinaries($comp, $ver, Utils::EpocRoot(), $overwrite); |
|
380 |
|
381 my $status = ($self->CheckComp($comp))[0]; |
|
382 if ($status == STATUS_DIRTY) { |
|
383 print "WARNING: Installed component does not match existing signature; updating signature\n"; |
|
384 $self->GenerateSignature($comp, $ver); |
|
385 } |
|
386 } |
|
387 } |
|
388 |
|
389 sub DeleteSource { |
|
390 my $self = shift; |
|
391 my $thisComp = shift; |
|
392 my $dryrun = shift; |
|
393 my $force = shift; |
|
394 |
|
395 my $ver = $self->Version($thisComp); |
|
396 |
|
397 if(!defined $ver) { |
|
398 die "ERROR: Unable to obtain version for $thisComp\n"; |
|
399 } |
|
400 |
|
401 my $reldata = RelData->Open($self->{iniData}, $thisComp, $ver, $self->{verbose}); |
|
402 |
|
403 my $srcitems = $reldata->SourceItems; |
|
404 foreach my $thisSrcItem (keys %$srcitems) { |
|
405 # If there are mappings and the source root is \\, perform mappings on filename. Otherwise prepend source root. |
|
406 if($self->{iniData}->HasMappings() && Utils::SourceRoot() eq "\\") { |
|
407 $thisSrcItem = $self->{iniData}->PerformMapOnFileName($thisSrcItem); |
|
408 } |
|
409 else{ |
|
410 $thisSrcItem = Utils::PrependSourceRoot($thisSrcItem); |
|
411 } |
|
412 |
|
413 if ($self->{verbose} || $dryrun) { |
|
414 my $dir = (-d $thisSrcItem)?" (directory)":""; |
|
415 my $exists = (-e $thisSrcItem)?"":" (doesn't exist)"; |
|
416 my $verb = $dryrun?"Would remove":"Removing"; |
|
417 print "$verb $thisSrcItem$dir$exists\n"; |
|
418 } |
|
419 { |
|
420 local $SIG{__WARN__} = sub { |
|
421 my $warn = shift; |
|
422 $warn =~ s/ at .*?EnvDb\.pm line \d+//; |
|
423 print STDERR "WARNING: $warn"; |
|
424 }; |
|
425 rmtree($thisSrcItem, 0, !$force) unless $dryrun; |
|
426 } |
|
427 my $directory = dirname($thisSrcItem); |
|
428 |
|
429 my @items = @{Utils::ReadDir($directory)}; |
|
430 |
|
431 if (scalar @items == 1 && $items[0] =~ /^distribution\.policy$/i) { |
|
432 unlink File::Spec->catdir($directory, shift @items) unless $dryrun; |
|
433 } |
|
434 |
|
435 if (-e $directory && (!scalar @items)) { # No items in dir or just a distribution.policy file in dir |
|
436 rmdir $directory or die "Error: Could not remove directory $directory: $!"; |
|
437 while (($directory = dirname($directory)) && -e $directory && !scalar @{Utils::ReadDir($directory)}) { |
|
438 rmdir $directory or die "Error: Could not remove directory $directory: $!"; |
|
439 } |
|
440 } |
|
441 } |
|
442 } |
|
443 |
|
444 sub CheckEnv { |
|
445 my $self = shift; |
|
446 my $displayProgress = shift; |
|
447 my $ignoreStandardIgnores = shift; |
|
448 my $warnNotError = shift; # When validating the MrpData, warnings will be produced |
|
449 # instead of errors when checking paths lengths DEF099673 |
|
450 |
|
451 unless (defined $displayProgress) { |
|
452 $displayProgress = 0; |
|
453 } |
|
454 unless (defined $ignoreStandardIgnores) { |
|
455 $ignoreStandardIgnores = 0; |
|
456 } |
|
457 |
|
458 my $overallStatus = STATUS_CLEAN; |
|
459 my @dirtyComps; |
|
460 |
|
461 if ($displayProgress) { |
|
462 print "Scanning environment"; |
|
463 } |
|
464 |
|
465 $self->InitIgnores($ignoreStandardIgnores); |
|
466 $self->ScanEnv($displayProgress); |
|
467 |
|
468 my @mrpData; |
|
469 my @errors; |
|
470 foreach my $thisComp (sort keys %{$self->{db}}) { |
|
471 (my $status, my $mrpData) = $self->CheckComp($thisComp, undef, $warnNotError); |
|
472 my $ver = $self->{db}->{$thisComp}->{ver}; |
|
473 if ($status == STATUS_DIRTY || $status == STATUS_DIRTY_SOURCE) { |
|
474 $overallStatus = STATUS_DIRTY; |
|
475 push (@dirtyComps, {comp => $thisComp, ver => $ver}); |
|
476 } |
|
477 elsif ($status == STATUS_PENDING_RELEASE) { |
|
478 unless ($overallStatus == STATUS_DIRTY) { |
|
479 $overallStatus = STATUS_PENDING_RELEASE; |
|
480 } |
|
481 if (defined $mrpData) { |
|
482 push @mrpData, $mrpData; |
|
483 } |
|
484 else { |
|
485 push @errors, "Error: Problem extracting mrp data from $thisComp\n"; |
|
486 } |
|
487 } |
|
488 if ($displayProgress and not $self->{verbose}) { |
|
489 print '.'; |
|
490 } |
|
491 } |
|
492 if ($displayProgress and not $self->{verbose}) { |
|
493 print "\n"; |
|
494 } |
|
495 |
|
496 if ($#errors >= 0) { |
|
497 chomp $errors[$#errors]; |
|
498 print @errors; |
|
499 die "\n"; |
|
500 } |
|
501 |
|
502 $self->RemoveBinsToIgnore(); |
|
503 |
|
504 my $unaccountedFiles = $self->UnaccountedEnvFiles(); |
|
505 if (scalar(@$unaccountedFiles) >= 1) { |
|
506 $overallStatus = STATUS_DIRTY; |
|
507 } |
|
508 |
|
509 my $duplicates = $self->Duplicates(\@mrpData); |
|
510 if (scalar(@$duplicates) >= 1) { |
|
511 $overallStatus = STATUS_DIRTY; |
|
512 } |
|
513 |
|
514 return ($overallStatus, \@mrpData, \@dirtyComps, $unaccountedFiles, $duplicates); |
|
515 } |
|
516 |
|
517 sub CheckComp { |
|
518 my $self = shift; |
|
519 my $comp = lc(shift); |
|
520 my $keepGoing = shift; |
|
521 my $warnNotError = shift; |
|
522 |
|
523 unless (defined $keepGoing) { |
|
524 $keepGoing = 1; |
|
525 } |
|
526 |
|
527 my $entry = $self->{db}->{$comp}; |
|
528 if (!defined $entry || $self->{db}->{$comp}->{status} == STATUS_INFORMATION_ONLY) { |
|
529 return (STATUS_NOT_INSTALLED); |
|
530 } |
|
531 my $oldstatus = $entry->{status}; |
|
532 my $ver = $entry->{ver}; |
|
533 die unless $ver; |
|
534 my $passed = 1; |
|
535 |
|
536 my $doCheck = sub { |
|
537 my $file = shift; |
|
538 my $sigMTime = shift; |
|
539 my $sigSize = shift; |
|
540 |
|
541 if (-e $file) { # Files might be installed in directories other than \epoc32, so do an explicit check. |
|
542 $self->CheckFileAgainstEnvScan($file); |
|
543 # Check the signature information against what is physically present in the environment. |
|
544 (my $actualMTime, my $actualSize) = Utils::FileModifiedTimeAndSize($file); |
|
545 if ($sigMTime != $actualMTime or $sigSize != $actualSize) { |
|
546 # File failed check. |
|
547 $passed = 0; |
|
548 if ($self->{verbose}) { |
|
549 print "$comp $ver $file failed check\n"; |
|
550 } |
|
551 if ($self->{verbose} > 1) { |
|
552 my $printableActualMTime = gmtime($actualMTime); |
|
553 my $printableSigMTime = gmtime($sigMTime); |
|
554 print "\tcurrent mtime: $printableActualMTime\n"; |
|
555 print "\tsignature mtime: $printableSigMTime\n"; |
|
556 print "\tcurrent size: $actualSize\n"; |
|
557 print "\tsignature size: $sigSize\n"; |
|
558 } |
|
559 unless ($keepGoing) { |
|
560 return 0; |
|
561 } |
|
562 } |
|
563 else { |
|
564 # File passed check. |
|
565 if ($self->{verbose} > 1) { |
|
566 print "$comp $ver $file passed\n"; |
|
567 } |
|
568 } |
|
569 } |
|
570 else { |
|
571 # File missing. |
|
572 $passed = 0; |
|
573 if ($self->{verbose}) { |
|
574 print "$comp $ver $file missing\n"; |
|
575 } |
|
576 unless ($keepGoing) { |
|
577 return 0; |
|
578 } |
|
579 } |
|
580 |
|
581 return 1; |
|
582 }; |
|
583 |
|
584 my $mrpData; |
|
585 die unless defined $entry->{status}; |
|
586 if ($entry->{status} == STATUS_PENDING_RELEASE) { |
|
587 eval { |
|
588 unless (defined $entry->{mrpName}) { |
|
589 die "Error: mrp name not specified for $comp\n"; |
|
590 } |
|
591 $mrpData = $self->GetMrpData($comp); |
|
592 $mrpData->Validate($warnNotError); |
|
593 foreach my $thisBin (@{$mrpData->BinariesAndExports()}) { |
|
594 $thisBin = Utils::PrependEpocRoot($thisBin); |
|
595 $self->CheckFileAgainstEnvScan($thisBin); |
|
596 } |
|
597 }; |
|
598 if ($@) { |
|
599 $mrpData = undef; # splat the MrpData in order to stop |
|
600 # the envinfo/cleanenv. |
|
601 # We need to do this because the only |
|
602 # way we have of returning an error is to |
|
603 # fail to return the MRP. |
|
604 if ($self->{verbose} == 0) { |
|
605 print "\n"; |
|
606 } |
|
607 print "$comp: $@"; |
|
608 } |
|
609 } |
|
610 else { |
|
611 ExecuteSignature(SignatureName($comp, $ver), $doCheck); |
|
612 |
|
613 if ($passed) { |
|
614 if ($oldstatus == STATUS_DIRTY) { |
|
615 $self->SetStatus($comp, STATUS_CLEAN); |
|
616 } else { |
|
617 # Here we return the original status from the environment database, |
|
618 # which is probably STATUS_CLEAN but might by STATUS_DIRTY_SOURCE |
|
619 $self->SetStatus($comp, $oldstatus); |
|
620 } |
|
621 } |
|
622 else { |
|
623 $self->SetStatus($comp, STATUS_DIRTY); |
|
624 } |
|
625 } |
|
626 |
|
627 return ($self->Status($comp), $mrpData); |
|
628 } |
|
629 |
|
630 sub ValidateEnv { |
|
631 my $self = shift; |
|
632 my $comp = lc(shift); |
|
633 my $ver = shift; |
|
634 my $validatesource = shift; |
|
635 my $fullbincheck = shift; |
|
636 |
|
637 my $validatingExternalEnv = 0; |
|
638 my $compsToValidate; |
|
639 if (defined $comp and defined $ver) { |
|
640 if (scalar (keys %{$self->{db}}) > 0) { |
|
641 die "Error: Can't validate against an external environment, because the current environment database is not empty\n"; |
|
642 } |
|
643 $validatingExternalEnv = 1; |
|
644 my $relData = RelData->Open($self->{iniData}, $comp, $ver, $self->{verbose}); |
|
645 $compsToValidate = $relData->Environment(); |
|
646 } |
|
647 else { |
|
648 # Use the current environment. |
|
649 foreach my $thisComp (sort keys %{$self->{db}}) { |
|
650 $compsToValidate->{$thisComp} = $self->{db}->{$thisComp}->{ver}; |
|
651 } |
|
652 } |
|
653 |
|
654 my @failedComps; |
|
655 foreach my $thisComp (sort keys %{$compsToValidate}) { |
|
656 my $thisVer = $compsToValidate->{$thisComp}; |
|
657 my $result = $self->ValidateComp($thisComp, $thisVer, 0, $validatesource, 0, $fullbincheck); |
|
658 if ($result == STATUS_DIRTY || $result == STATUS_DIRTY_SOURCE) { |
|
659 push (@failedComps, $thisComp); |
|
660 if ($validatingExternalEnv) { |
|
661 # Add an entry even of components that failed. This makes it easier for the user to specify what needs to be re-released. |
|
662 $self->SetVersion($thisComp, $thisVer); |
|
663 if ($result == STATUS_DIRTY) { |
|
664 $self->GenerateFakeSignature($thisComp, $thisVer); |
|
665 } elsif ($result == STATUS_DIRTY_SOURCE) { |
|
666 $self->GenerateSignature($thisComp, $thisVer); |
|
667 } |
|
668 $self->SetStatus($thisComp, $result); |
|
669 my $relData = RelData->Open($self->{iniData}, $thisComp, $thisVer, $self->{verbose}); |
|
670 $self->SetMrpName($thisComp, $relData->MrpName()); |
|
671 $self->SetInternalVersion($thisComp, $relData->InternalVersion()); |
|
672 } |
|
673 } |
|
674 } |
|
675 |
|
676 return \@failedComps; |
|
677 } |
|
678 |
|
679 sub ValidateCompOld { |
|
680 my $self = shift; |
|
681 my $comp = lc(shift); |
|
682 my $ver = shift; |
|
683 my $keepGoing = shift; |
|
684 my $validatesource = shift; |
|
685 my $keeptemp = shift; |
|
686 my $fullbincheck = shift; |
|
687 unless (defined $keepGoing) { |
|
688 $keepGoing = 1; |
|
689 } |
|
690 |
|
691 my $status = STATUS_CLEAN; |
|
692 die unless defined $ver; |
|
693 |
|
694 my $entry = $self->{db}->{$comp}; |
|
695 if (defined $entry and $entry->{status} == STATUS_PENDING_RELEASE) { |
|
696 if ($ver eq $entry->{ver}) { # allow validation against other versions even if we're pending release |
|
697 return STATUS_PENDING_RELEASE; |
|
698 } |
|
699 } |
|
700 |
|
701 my $relData = RelData->Open($self->{iniData}, $comp, $ver, $self->{verbose}); |
|
702 |
|
703 # Always validate binaries |
|
704 # I initially added an option to turn this off, but I decided that was overcomplexity |
|
705 # and I couldn't think of any use cases except tinkering with the release tools... |
|
706 print "Validating binaries $comp $ver...\n"; |
|
707 Utils::InitialiseTempDir($self->{iniData}); |
|
708 eval { |
|
709 # Get a temporary copy of the released binaries. |
|
710 my $tempDir = Utils::TempDir(); |
|
711 $self->UnpackBinaries($comp, $ver, $tempDir, 1); # 1 = overwrite |
|
712 |
|
713 # Call evalid to compare these with those installed in the environment. |
|
714 # We now validate everything in the temp dir, not just \epoc32, |
|
715 # because some components release binaries outside \epoc32. |
|
716 my $clean = $self->EvalidateDirectories($tempDir, Utils::PrependEpocRoot('.'), $keepGoing); |
|
717 $status = ($clean)?(STATUS_CLEAN):(STATUS_DIRTY); |
|
718 |
|
719 if ($clean and $fullbincheck) { |
|
720 # Ask the current mrp file for a list of binaries (using abld -what) |
|
721 my $mrpData; |
|
722 |
|
723 my $mrpPath = $relData->MrpName(); |
|
724 if($self->{iniData}->HasMappings() && Utils::SourceRoot() eq "\\") { |
|
725 $mrpPath = $self->{iniData}->PerformMapOnFileName($mrpPath); |
|
726 } |
|
727 else{ |
|
728 $mrpPath = Utils::PrependSourceRoot($mrpPath); |
|
729 } |
|
730 if (!-f $mrpPath) { |
|
731 print "Not checking for new binaries; MRP file not present\n"; |
|
732 } else { |
|
733 eval { |
|
734 $mrpData = New MrpData($relData->MrpName(), undef, undef, $self->{iniData}, $self->{verbose}); # undef = we're not preprel-ing it |
|
735 }; |
|
736 |
|
737 if (!defined($mrpData)) { |
|
738 my $error = $@; |
|
739 $error =~ s/\s*$//; |
|
740 print "Not checking for new binaries; $error\n"; |
|
741 } else { |
|
742 my @binaries = @{$mrpData->Binaries()}; |
|
743 push @binaries, @{$mrpData->Exports()}; |
|
744 |
|
745 # Get list of binaries in the temporary copy |
|
746 my %oldbinaries; |
|
747 |
|
748 my $sub = sub { # Subroutine to add files to %oldbinaries |
|
749 return if -d $_; # Check it's not a directory |
|
750 s/^\Q$tempDir\E[\/\\]?//; # Strip the temp dir path off |
|
751 s/\\/\//g; # Convert backslashes |
|
752 $oldbinaries{lc($_)}=1 unless (/^\.\.?$/) # Add to hash (unless it's .. or .) |
|
753 }; |
|
754 |
|
755 find( {wanted=>$sub, no_chdir=>1}, $tempDir); # Use no_chdir and s/.../ to get a full relative path. Second s/.../ converts backslashes to normal slashes |
|
756 foreach my $binary (@binaries) { |
|
757 $binary = lc($binary); |
|
758 $binary =~ s/\\/\//g; # Convert backslashes to normal slashes |
|
759 if (exists $oldbinaries{$binary}) { |
|
760 delete $oldbinaries{$binary}; |
|
761 } else { |
|
762 print "New binary file: $binary\n"; |
|
763 $status = STATUS_DIRTY; |
|
764 } |
|
765 } |
|
766 foreach my $oldbinary (keys(%oldbinaries)) { |
|
767 print "Binary file no longer built: $oldbinary\n"; |
|
768 $status = STATUS_DIRTY; |
|
769 } |
|
770 } |
|
771 } |
|
772 } |
|
773 }; |
|
774 |
|
775 if ($keeptemp) { |
|
776 print "Old release stored in \"".Utils::TempDir()."\"\n"; |
|
777 } else { |
|
778 Utils::RemoveTempDir(); |
|
779 } |
|
780 if ($@) { |
|
781 die $@; |
|
782 } |
|
783 |
|
784 # We need to check if the categories for exports has changed or not... |
|
785 if ($status == STATUS_CLEAN) { |
|
786 foreach my $thisBinZip (@{$self->RelevantBinaryZips($comp, $ver)}) { |
|
787 |
|
788 if($thisBinZip =~ /exports([a-z]).zip/i) { |
|
789 my $catInArchive = $1; |
|
790 # Open and read the corresponding exports category info file in the archive |
|
791 my $catData = CatData->Open($self->{iniData}, $comp, $ver, $catInArchive); |
|
792 my $catWriteInCatDataFile; |
|
793 |
|
794 # Obtain the category written the exports category info file, if unable to read skip check |
|
795 eval { |
|
796 $catWriteInCatDataFile = $catData->Category(); |
|
797 }; |
|
798 if ($@) { |
|
799 last; |
|
800 } |
|
801 # Check the categories match |
|
802 if($catInArchive !~ /^$catWriteInCatDataFile$/i){ |
|
803 die "ERROR: Mismatch in category found in exports$catInArchive.txt for $comp $ver\n"; |
|
804 } |
|
805 |
|
806 my $exportinfo = $catData->ExportInfo(); |
|
807 my $destinationDirBuffer; |
|
808 |
|
809 # Using the export infomation as read for the exports category info file check the category of the export file. |
|
810 foreach my $export (sort(keys %{$exportinfo})) { |
|
811 my $destinationDir; |
|
812 my $classifySourceFlag = 1; # Classify source using function ClassifySourceFile only if set as 1; |
|
813 my $destination = $catData->ExportSource($export); |
|
814 |
|
815 # Consider any mappings if defined |
|
816 if($self->{iniData}->HasMappings()){ |
|
817 $destination = $self->{iniData}->PerformMapOnFileName($destination); |
|
818 } |
|
819 |
|
820 if(defined $destinationDirBuffer){ |
|
821 ($destinationDir) = Utils::SplitFileName($destination); |
|
822 |
|
823 if($destinationDirBuffer =~ /^\Q$destinationDir\E$/i){ |
|
824 $classifySourceFlag = 0; |
|
825 } |
|
826 } |
|
827 |
|
828 my $absolute_path = Utils::PrependSourceRoot($destination); |
|
829 |
|
830 # validate only if source validation is requested or the source is present |
|
831 if($classifySourceFlag and ($validatesource or -e $absolute_path)){ |
|
832 # Obtain the category from the source destinaton extracted for the exports category info file |
|
833 my ($catInEnv, $errors) = Utils::ClassifyPath($self->{iniData}, $destination, 0, 0, $comp); # verbose = 0 and logErrors = 0 |
|
834 if ($catInEnv !~ /^$catInArchive$/i){ |
|
835 print "Change in category found (ENV) \"$catInEnv\" : (Archive) \"$catInArchive\" using $thisBinZip for file $export\n"; |
|
836 $status = STATUS_DIRTY; |
|
837 last; |
|
838 } |
|
839 |
|
840 $destinationDirBuffer = Utils::SplitFileName($destination); |
|
841 } |
|
842 } |
|
843 } |
|
844 } |
|
845 } |
|
846 |
|
847 # We only bother validating source if we've discovered the binaries are clean. |
|
848 # This implies that STATUS_DIRTY means the binaries are dirty, but the status of |
|
849 # the source code is undefined. |
|
850 if ($validatesource && $status == STATUS_CLEAN) { |
|
851 print "Validating source for $comp $ver...\n"; |
|
852 Utils::InitialiseTempDir($self->{iniData}); |
|
853 eval { |
|
854 # Get a temporary copy of the released source. |
|
855 my $tempDir = Utils::TempDir(); |
|
856 |
|
857 my $changeInCat = $self->UnpackSource($comp, $ver, $tempDir, 1, 0, 1); # 1 = overwrite, 0 = do not show progress, 1 = validate |
|
858 |
|
859 if($changeInCat){ |
|
860 print "Change in category found for $comp...\n"; |
|
861 $status = STATUS_DIRTY_SOURCE; |
|
862 } |
|
863 |
|
864 # The following code is the only place where a component can have its |
|
865 # status set to "dirty source code". This status was added when |
|
866 # the -s switch was added to ValidateEnv/Rel to validate source code. |
|
867 # It would have been simpler to just set a component to 'dirty' when |
|
868 # the source code was dirty, but this was not possible for the following |
|
869 # reason. When envinfo -f gathers the state information of a component |
|
870 # (or, for that matter, some other command checks the environment is clean) |
|
871 # this calls the CheckComp function. This ignores the status stored in |
|
872 # the environment database, and works it out afresh from the timestamps |
|
873 # on the individual files. Hence we needed to add a new status which |
|
874 # CheckComp would propagate through, so it can report the status |
|
875 # on envinfo. (Otherwise we would have to change CheckComp |
|
876 # so it also checked the status of each source code file eacb |
|
877 # time). |
|
878 # |
|
879 # It would be nice here to ensure we have all the source |
|
880 # installed, but I don't think there's a nice way of finding |
|
881 # out the directory that the source comes in. (Not without |
|
882 # unzipping the zip, and we might as well just evalidate it...) |
|
883 # |
|
884 # This grim \. thing is not homage to the Great Geek Website |
|
885 # It is because evalid gets grumpy if you give it either \ or '' |
|
886 # as an argument. The first time is because \\ isn't a valid |
|
887 # directory separator in Win32 (!!) and the second is because |
|
888 # Perl doesn't think '' is a valid directory (which is probably |
|
889 # fair enough). Rather than file a defect against Windows, |
|
890 # let's pass in slightly silly arguments to evalid. |
|
891 if ($status == STATUS_CLEAN) { |
|
892 print "Checking for changed or removed files\n" if ($self->{verbose}); |
|
893 my $clean = $self->EvalidateDirectories($tempDir, Utils::PrependSourceRoot('.'), $keepGoing); |
|
894 $status = STATUS_DIRTY_SOURCE unless ($clean); |
|
895 } |
|
896 # The above checks will only have found changed or removed files. |
|
897 # Files that have been added to the source won't be in the $tempDir, |
|
898 # so evalid won't pick them up and test them. So we have to |
|
899 # explicitly check for added files. |
|
900 # Only bother doing this if we haven't found problems already. |
|
901 if ($status == STATUS_CLEAN) { |
|
902 # Recurse through each directory in the temp dir, listing the |
|
903 # equivalent dir on the drive (i.e. the latest source). If there |
|
904 # are more files on the drive than in the source tree, source |
|
905 # is dirty. |
|
906 print "Checking for added files\n" if ($self->{verbose}); |
|
907 eval { |
|
908 $status = STATUS_DIRTY_SOURCE if ($self->CheckForAddedFiles($relData, $tempDir)); |
|
909 }; |
|
910 if ($@) { |
|
911 print "Warning: skipping the check for added files, for the component \"$comp\". All other source code validation checks passed. The reason is: $@"; |
|
912 } |
|
913 } |
|
914 }; |
|
915 Utils::RemoveTempDir(); |
|
916 if ($@) { |
|
917 die $@; |
|
918 } |
|
919 } |
|
920 |
|
921 if ($status == STATUS_CLEAN) { |
|
922 # Previously this SetVersion line was wrapped in an "if", so that |
|
923 # it didn't happen if $entry was defined - i.e. it was already in the |
|
924 # environment database. After discussion with Joe and James this behaviour |
|
925 # has been changed. |
|
926 $self->SetVersion($comp, $ver); |
|
927 $self->SetStatus($comp, $status); |
|
928 $self->GenerateSignature($comp, $ver); |
|
929 $self->SetMrpName($comp, $relData->MrpName()); |
|
930 $self->SetInternalVersion($comp, $relData->InternalVersion()); |
|
931 } |
|
932 elsif ($entry && $entry->{status} && |
|
933 $entry->{status} == STATUS_PENDING_RELEASE) { |
|
934 # Old status was pending release; so we don't do anything |
|
935 } |
|
936 elsif ($status == STATUS_DIRTY) { |
|
937 if (defined $entry) { |
|
938 # The component used to be in the environment database |
|
939 # We set its status in case it used to be STATUS_DIRTY_SOURCE |
|
940 # and it's now STATUS_DIRTY. |
|
941 $self->SetStatus($comp, $status); |
|
942 } |
|
943 # This component wasn't previously in the environment database; |
|
944 # do nothing |
|
945 } |
|
946 elsif ($status == STATUS_DIRTY_SOURCE) { |
|
947 if (defined $entry) { |
|
948 $self->SetStatus($comp, $status); |
|
949 $self->GenerateSignature($comp, $ver); |
|
950 # Because otherwise any 'envinfo' will reset a component status |
|
951 # to dirty, even if only its source is dirty |
|
952 } |
|
953 } |
|
954 print "Status ", StatusString($status), "\n"; |
|
955 return $status; |
|
956 } |
|
957 |
|
958 sub ValidateComp { |
|
959 my $self = shift; |
|
960 my $comp = lc(shift); |
|
961 my $ver = shift; |
|
962 my $keepGoing = shift; |
|
963 my $validatesource = shift; |
|
964 my $keeptemp = shift; |
|
965 my $fullbincheck = shift; |
|
966 unless ( defined $keepGoing ) { |
|
967 $keepGoing = 1; |
|
968 } |
|
969 my $manifestFromThisComponent = undef; |
|
970 my $status = STATUS_CLEAN; |
|
971 die unless defined $ver; |
|
972 |
|
973 my $entry = $self->{db}->{$comp}; |
|
974 if (defined $entry and $entry->{status} == STATUS_PENDING_RELEASE) { |
|
975 if ($ver eq $entry->{ver}) { # allow validation against other versions even if we're pending release |
|
976 return STATUS_PENDING_RELEASE; |
|
977 } |
|
978 } |
|
979 |
|
980 #Create a relData object for retrieving the mrpPath required for building the manifest object |
|
981 my $relData = RelData->Open( $self->{iniData}, $comp, $ver, $self->{verbose} ); |
|
982 |
|
983 #Find the archive location for release and build the file path for loading the manifest file from the location |
|
984 my $relDir = $relData->{iniData}->PathData->LocalArchivePathForExistingComponent( $comp, $ver ); |
|
985 my $manifestPath = File::Spec->catfile( $relDir, MANIFEST_FILE ); |
|
986 |
|
987 #Check if manifest file exists |
|
988 if (-e $manifestPath) { |
|
989 #Define callback to validate files which don't have checksum defined in manifest file. |
|
990 my $callback = sub { |
|
991 my $filesToValidate = shift; |
|
992 my $manifestObject = shift; |
|
993 my $keepGoing = shift; |
|
994 { |
|
995 local $" = ", "; |
|
996 print "No checksum found for file(s) @{$filesToValidate} - reverting to old evalid process.\n"; |
|
997 } |
|
998 Utils::InitialiseTempDir($self->{iniData}); |
|
999 my $tempDir = Utils::TempDir(); |
|
1000 my $epocFilePath = Utils::EpocRoot(); |
|
1001 my $sourceFilePath = Utils::SourceRoot(); |
|
1002 my $fullEvalidName = Utils::FindInPath('evalid.bat'); |
|
1003 my $clean = 1; |
|
1004 my @files; |
|
1005 foreach my $thisFile (@{$filesToValidate}) { |
|
1006 my $zipName; |
|
1007 my $file; |
|
1008 my $fileContentType = $manifestObject->GetFileInfo($thisFile, CONTENT_TYPE); |
|
1009 if ($fileContentType eq 'source' or $fileContentType eq 'export') { |
|
1010 my $cat = $manifestObject->GetFileInfo($thisFile, IPR_CATEGORY); |
|
1011 if ($fileContentType eq 'source') { |
|
1012 $zipName = "source".$cat; |
|
1013 $file = File::Spec->catfile($sourceFilePath, $thisFile) |
|
1014 } else { |
|
1015 $zipName = "exports".$cat; |
|
1016 $file = File::Spec->catfile($epocFilePath, $thisFile); |
|
1017 } |
|
1018 } |
|
1019 elsif ($fileContentType eq 'binary') { |
|
1020 my $platForm = $manifestObject->{files}{$thisFile}{'platform'}; |
|
1021 if (defined $platForm) { |
|
1022 $zipName = "binaries"."_".$platForm; |
|
1023 } |
|
1024 else { |
|
1025 $zipName = "binaries"; |
|
1026 } |
|
1027 $file = File::Spec->catfile($epocFilePath, $thisFile); |
|
1028 } |
|
1029 $zipName = $zipName.".zip"; |
|
1030 my $zipPath = File::Spec->catfile($relDir,$zipName); |
|
1031 Utils::UnzipSingleFile($zipPath,$thisFile, $tempDir, $self->{verbose}, 1, $comp); #overwrite = 1 |
|
1032 push @files, [$thisFile, $file]; |
|
1033 } |
|
1034 foreach my $thisFile (@files) { |
|
1035 my $firstPath = File::Spec->catfile($tempDir,shift(@$thisFile)); |
|
1036 my $secondPath = shift(@$thisFile); |
|
1037 open EVALID, "$fullEvalidName -c $firstPath $secondPath|" or die "Error: Couldn't run EValid: $!\n"; |
|
1038 my $thisLine; |
|
1039 my $acceptablefailures = ACCEPTABLE_EVALID_FAILURES; |
|
1040 while ($thisLine = <EVALID>) { |
|
1041 if ($thisLine =~ m/MISSING:|FAILED:|PROBLEM:/ && $thisLine !~ m/$acceptablefailures/i) { |
|
1042 print $thisLine if ($self->{verbose}); |
|
1043 $clean = 0; |
|
1044 unless ($keepGoing) { |
|
1045 Utils::RemoveTempDir(); |
|
1046 return $clean; |
|
1047 } |
|
1048 } |
|
1049 } |
|
1050 } |
|
1051 Utils::RemoveTempDir(); |
|
1052 return $clean; |
|
1053 }; |
|
1054 |
|
1055 #Load the manifest file to create a manifest object |
|
1056 my $manifestFromBaselineComponent = Symbian::CBR::Component::Manifest->new( $manifestPath ); |
|
1057 |
|
1058 my $mrpPath = Utils::RelativeToAbsolutePath( $relData->MrpName(), $self->{iniData}, SOURCE_RELATIVE ); |
|
1059 |
|
1060 if ($fullbincheck && -e $mrpPath) { |
|
1061 $manifestFromThisComponent = Symbian::CBR::Component::Manifest->new($mrpPath); |
|
1062 } else { |
|
1063 if ($fullbincheck) { |
|
1064 print "Not checking for new binaries; MRP file not present\n"; |
|
1065 } |
|
1066 |
|
1067 $manifestFromThisComponent = Symbian::CBR::Component::Manifest->new($manifestPath); |
|
1068 $manifestFromThisComponent->RefreshMetaData($comp, $ver); |
|
1069 } |
|
1070 |
|
1071 #Compare the manifest objects |
|
1072 eval {$status = $manifestFromThisComponent->Compare($manifestFromBaselineComponent, $validatesource, $keepGoing,$callback)}; |
|
1073 |
|
1074 #Check if Compare() completed without errors |
|
1075 if (!$@) { |
|
1076 |
|
1077 #If $keeptemp set, unpack binaries to temp location |
|
1078 if ( $keeptemp ) { |
|
1079 |
|
1080 Utils::InitialiseTempDir($self->{iniData}); |
|
1081 # Get a temporary copy of the released binaries. |
|
1082 my $tempDir = Utils::TempDir(); |
|
1083 $self->UnpackBinaries($comp, $ver, $tempDir, 1); # 1 = overwrite |
|
1084 |
|
1085 #If $validatesource is set, get temp copy of released sources |
|
1086 $self->UnpackSource($comp, $ver, $tempDir, 1, 0, 1) if $validatesource; |
|
1087 |
|
1088 print "Old release stored in \"".Utils::TempDir()."\"\n"; |
|
1089 } |
|
1090 |
|
1091 #If status is dirty, save manifest to temp location |
|
1092 $self->SaveManifestToTempDir($comp, $manifestFromThisComponent) if $status == STATUS_DIRTY; |
|
1093 |
|
1094 #Update the environemnt as done by validatecompold |
|
1095 $self->UpdateEnvironment( $status, $entry, $relData ); |
|
1096 |
|
1097 print "Status ", StatusString($status), "\n"; |
|
1098 return $status; |
|
1099 } |
|
1100 |
|
1101 else { |
|
1102 print "$@Continuing with old validaterel process..\n"; |
|
1103 } |
|
1104 |
|
1105 } |
|
1106 else { |
|
1107 print "Manifest file does not exist in the version $ver for component $comp..\nContinuing with old validaterel process..\n"; |
|
1108 } |
|
1109 |
|
1110 #Call the old validaterel process if manifest comparison is not possible |
|
1111 $status = $self->ValidateCompOld( $comp, $ver, $keepGoing, $validatesource, $keeptemp, $fullbincheck ); |
|
1112 |
|
1113 #If status is dirty during validatecompold, still we want to save manifest to temp location |
|
1114 if ( defined $manifestFromThisComponent and ($status == STATUS_DIRTY or $status == STATUS_DIRTY_SOURCE) ) { |
|
1115 $self->SaveManifestToTempDir($comp, $manifestFromThisComponent); |
|
1116 } |
|
1117 |
|
1118 return $status; |
|
1119 } |
|
1120 |
|
1121 sub UpdateEnvironment { |
|
1122 my $self = shift; |
|
1123 my $status = shift; |
|
1124 my $entry = shift; |
|
1125 my $relData = shift; |
|
1126 |
|
1127 my $comp = $relData->Component(); |
|
1128 my $ver = $relData->Version(); |
|
1129 |
|
1130 if ($status == STATUS_CLEAN) { |
|
1131 # Previously this SetVersion line was wrapped in an "if", so that |
|
1132 # it didn't happen if $entry was defined - i.e. it was already in the |
|
1133 # environment database. After discussion with Joe and James this behaviour |
|
1134 # has been changed. |
|
1135 $self->SetVersion( $comp, $ver ); |
|
1136 $self->SetStatus( $comp, $status ); |
|
1137 $self->GenerateSignature( $comp, $ver ); |
|
1138 $self->SetMrpName( $comp, $relData->MrpName() ); |
|
1139 $self->SetInternalVersion( $comp, $relData->InternalVersion() ); |
|
1140 } |
|
1141 elsif ($entry && $entry->{status} && |
|
1142 $entry->{status} == STATUS_PENDING_RELEASE) { |
|
1143 # Old status was pending release; so we don't do anything |
|
1144 } |
|
1145 elsif ($status == STATUS_DIRTY) { |
|
1146 if (defined $entry) { |
|
1147 # The component used to be in the environment database |
|
1148 # We set its status in case it used to be STATUS_DIRTY_SOURCE |
|
1149 # and it's now STATUS_DIRTY. |
|
1150 $self->SetStatus( $comp, $status ); |
|
1151 } |
|
1152 # This component wasn't previously in the environment database; |
|
1153 # do nothing |
|
1154 } |
|
1155 elsif ($status == STATUS_DIRTY_SOURCE) { |
|
1156 if (defined $entry) { |
|
1157 $self->SetStatus( $comp, $status ); |
|
1158 $self->GenerateSignature( $comp, $ver ); |
|
1159 # Because otherwise any 'envinfo' will reset a component status |
|
1160 # to dirty, even if only its source is dirty |
|
1161 } |
|
1162 } |
|
1163 } |
|
1164 |
|
1165 sub SaveManifestToTempDir { |
|
1166 my $self = shift; |
|
1167 my $comp = shift; |
|
1168 my $manifestFromThisComponent = shift; |
|
1169 |
|
1170 my $manifestTempFile = "manifest_".$comp.".xml"; |
|
1171 my $manifestFile = $manifestFromThisComponent->Save( File::Spec->tmpdir(), $manifestTempFile ); |
|
1172 # my $manifestTempFile = File::Spec->catfile( File::Spec->tmpdir(), "manifest_".$comp.".xml" ); |
|
1173 # rename( $manifestFile, $manifestTempFile ); |
|
1174 } |
|
1175 |
|
1176 sub Duplicates { |
|
1177 my $self = shift; |
|
1178 my $mrpData = shift; |
|
1179 my $installedComps = $self->VersionInfo(); |
|
1180 my %binHash; |
|
1181 my @duplicates; |
|
1182 |
|
1183 # First cross-check against the components about to be released. |
|
1184 foreach my $thisMrp (@{$mrpData}) { |
|
1185 my $comp = lc($thisMrp->Component()); |
|
1186 my $bins = $thisMrp->BinariesAndExports(); |
|
1187 foreach my $thisBin (@$bins) { |
|
1188 $thisBin = lc(Utils::PrependEpocRoot($thisBin)); |
|
1189 |
|
1190 print "Checking $thisBin for duplicateness (pending release)\n" if ($self->{verbose}>1); |
|
1191 if (exists $binHash{$thisBin}) { |
|
1192 push @duplicates, [$thisBin, $comp, $binHash{$thisBin}]; # $comp attempting to release $thisBin which has already been released by $binHash{$thisBin}"; |
|
1193 } |
|
1194 else { |
|
1195 $binHash{$thisBin} = $comp; |
|
1196 } |
|
1197 } |
|
1198 delete $installedComps->{$comp}; |
|
1199 } |
|
1200 |
|
1201 # Now cross-check against the other components in the environment. |
|
1202 foreach my $thisComp (keys %{$installedComps}) { |
|
1203 my $doCheck = sub { |
|
1204 my $file = lc(shift); |
|
1205 print "Checking $file for duplicateness\n" if ($self->{verbose}>1); |
|
1206 if (exists $binHash{$file}) { |
|
1207 push @duplicates, [$file, $binHash{$file}, $thisComp]; #"$binHash{$file} attempting to release $file which has already been released by $thisComp"; |
|
1208 } |
|
1209 else { |
|
1210 $binHash{$file} = $thisComp; |
|
1211 } |
|
1212 }; |
|
1213 my $sigName = SignatureName($thisComp, $installedComps->{$thisComp}); |
|
1214 ExecuteSignature($sigName, $doCheck); |
|
1215 } |
|
1216 |
|
1217 return \@duplicates; |
|
1218 } |
|
1219 |
|
1220 sub BinaryInfo { |
|
1221 my $self = shift; |
|
1222 my $binary = shift; |
|
1223 unless (-e $binary) { |
|
1224 die "Error: \"$binary\" does not exist\n"; |
|
1225 } |
|
1226 |
|
1227 (my $currentMTime, my $currentSize) = Utils::FileModifiedTimeAndSize($binary); |
|
1228 my $sigMTime; |
|
1229 my $sigSize; |
|
1230 my $sigName; |
|
1231 |
|
1232 my $findBin = sub { |
|
1233 my $file = shift; |
|
1234 if (lc($binary) eq lc($file)) { |
|
1235 $sigMTime = shift; |
|
1236 $sigSize = shift; |
|
1237 $sigName = shift; |
|
1238 return 0; |
|
1239 } |
|
1240 return 1; # Means continue; |
|
1241 }; |
|
1242 ExecuteAllSignatures($findBin); |
|
1243 |
|
1244 my $comp; |
|
1245 my $ver; |
|
1246 my $pendingRelease = 0; |
|
1247 |
|
1248 if (defined $sigMTime and defined $sigName) { |
|
1249 ($comp, $ver) = $self->DecodeSignatureName($sigName); |
|
1250 } |
|
1251 else { |
|
1252 # Binary not found in the signatures, so check for components pending release. |
|
1253 if (Utils::WithinEpocRoot($binary)) { |
|
1254 $binary = Utils::RemoveEpocRoot($binary); # remove EPOCROOT |
|
1255 } |
|
1256 $binary =~ s!^[\\\/]!!; # remove leading slash |
|
1257 |
|
1258 foreach my $thisComp (keys %{$self->{db}}) { |
|
1259 if ($self->Status($thisComp) == STATUS_PENDING_RELEASE) { |
|
1260 my $thisVer = $self->{db}->{$thisComp}->{ver}; |
|
1261 my $thisMrpData = $self->GetMrpData($thisComp); |
|
1262 $thisMrpData->EnsureDoesNotExist(); |
|
1263 |
|
1264 if (grep /^\Q$binary\E$/i, @{$thisMrpData->Binaries()}) { |
|
1265 $pendingRelease = 1; |
|
1266 $comp = $thisComp; |
|
1267 $ver = $thisVer; |
|
1268 last; |
|
1269 } |
|
1270 elsif (grep /^\Q$binary\E$/i, @{$thisMrpData->Exports()}) { |
|
1271 $pendingRelease = 1; |
|
1272 $comp = $thisComp; |
|
1273 $ver = $thisVer; |
|
1274 last; |
|
1275 } |
|
1276 } |
|
1277 } |
|
1278 unless (defined $comp and defined $ver) { |
|
1279 my $ignoreList = $self->{iniData}->BinariesToIgnore(); |
|
1280 push (@$ignoreList, Utils::PrependEpocRoot('\\epoc32\\relinfo\\*')); |
|
1281 foreach my $ignore (@$ignoreList) { |
|
1282 $ignore =~ s/\\/\\\\/g; |
|
1283 $ignore =~ s/\./\\\./g; |
|
1284 $ignore =~ s/\*/\.\*/g; |
|
1285 |
|
1286 if ($binary !~ /^\\/) { |
|
1287 $ignore =~ s/^\\*//; |
|
1288 } |
|
1289 |
|
1290 if ($binary =~ /^$ignore$/i) { |
|
1291 die "Error: no information available for \"$binary\". It is not part of any component, but it is ignored by the 'ignore_binary' rule '$ignore'. This rule might be in your reltools.ini, or it might be one of the standard ignores.\n"; |
|
1292 } |
|
1293 } |
|
1294 die "Error: No information available for \"$binary\". It's not even one of the files/directories that are ignored as standard.\n"; |
|
1295 } |
|
1296 } |
|
1297 |
|
1298 my $info; |
|
1299 push (@$info, ['Component:', $comp]); |
|
1300 push (@$info, ['Version:', $ver]); |
|
1301 if ($pendingRelease) { |
|
1302 push (@$info, ['Status:', 'pending release']); |
|
1303 } |
|
1304 elsif ($currentMTime == $sigMTime and $currentSize == $sigSize) { |
|
1305 push (@$info, ['Status:', 'clean']); |
|
1306 } |
|
1307 else { |
|
1308 push (@$info, ['Status:', 'dirty']); |
|
1309 } |
|
1310 |
|
1311 return $info; |
|
1312 } |
|
1313 |
|
1314 sub ListBins { |
|
1315 my $self = shift; |
|
1316 my $comp = shift; |
|
1317 my $ver = $self->Version($comp); |
|
1318 die unless $ver; |
|
1319 |
|
1320 if ($self->Status($comp) == STATUS_PENDING_RELEASE) { |
|
1321 $self->ListBinsPendingRelease($comp, $ver); |
|
1322 } else { |
|
1323 $self->ListBinsStandard($comp, $ver); |
|
1324 } |
|
1325 } |
|
1326 |
|
1327 sub GetMrpData { |
|
1328 my $self = shift; |
|
1329 my $compname = lc(shift); |
|
1330 my $entry = $self->{db}->{$compname}; |
|
1331 die "Invalid component name \"$compname\"" unless $entry; |
|
1332 |
|
1333 my $name = $entry->{mrpName}; |
|
1334 unless ($self->{mrpcache}->{$name}) { |
|
1335 my $mrpData = MrpData->New($entry->{mrpName}, $entry->{ver}, $entry->{intVer}, $self->{iniData}, $self->{verbose}); |
|
1336 my $namefrommrp = $mrpData->Component(); |
|
1337 die "Error: Component name in MRP file is \"$namefrommrp\" whilst the name of this component in the environment database is \"$compname\".\n" unless (lc $compname eq lc $namefrommrp); |
|
1338 $self->{mrpcache}->{$name} = $mrpData; |
|
1339 } |
|
1340 return $self->{mrpcache}->{$name}; |
|
1341 } |
|
1342 |
|
1343 |
|
1344 sub GetMRPLocations { |
|
1345 my $self = shift; |
|
1346 my $componentName = lc(shift); |
|
1347 |
|
1348 # If only the MRP location for a specified component is required... |
|
1349 if ($componentName) { |
|
1350 if (exists $self->{db}->{$componentName}) { |
|
1351 return (Utils::PrependSourceRoot($self->{db}->{$componentName}->{mrpName})); |
|
1352 } |
|
1353 else { |
|
1354 return undef; |
|
1355 } |
|
1356 } |
|
1357 |
|
1358 # Otherwise all MRP locations are returned to the caller |
|
1359 my @mrpLocations; |
|
1360 |
|
1361 foreach my $component (keys %{$self->{db}}) { |
|
1362 push @mrpLocations, Utils::PrependSourceRoot($self->{db}->{$component}->{mrpName}); |
|
1363 } |
|
1364 |
|
1365 return @mrpLocations; |
|
1366 } |
|
1367 |
|
1368 # |
|
1369 # Private. |
|
1370 # |
|
1371 |
|
1372 sub ListBinsStandard { |
|
1373 my $self = shift; |
|
1374 my $comp = shift; |
|
1375 my $ver = shift; |
|
1376 |
|
1377 my $info; |
|
1378 push (@$info, ['File', 'Status']); |
|
1379 |
|
1380 my $sigName = SignatureName($comp, $ver); |
|
1381 my $gatherInfo = sub { |
|
1382 my $file = shift; |
|
1383 my $sigMTime = shift; |
|
1384 my $sigSize = shift; |
|
1385 |
|
1386 if (-e $file) { |
|
1387 (my $actualMTime, my $actualSize) = Utils::FileModifiedTimeAndSize($file); |
|
1388 if (!defined $actualMTime or !defined $actualSize) { |
|
1389 die "Error: Problem stating \"$file\"\n"; |
|
1390 } |
|
1391 elsif ($sigMTime != $actualMTime or $sigSize != $actualSize) { |
|
1392 push (@$info, [$file, STATUS_STRING_FAILED]); |
|
1393 } |
|
1394 else { |
|
1395 push (@$info, [$file, STATUS_STRING_PASSED]); |
|
1396 } |
|
1397 } |
|
1398 else { |
|
1399 push (@$info, [$file, STATUS_STRING_MISSING]); |
|
1400 } |
|
1401 |
|
1402 return 1; # Means continue with next line in signature. |
|
1403 }; |
|
1404 |
|
1405 ExecuteSignature($sigName, $gatherInfo); |
|
1406 return $info; |
|
1407 } |
|
1408 |
|
1409 sub ListBinsPendingRelease { |
|
1410 my $self = shift; |
|
1411 my $comp = shift; |
|
1412 my $ver = shift; |
|
1413 |
|
1414 my $mrpData = $self->GetMrpData($comp); |
|
1415 |
|
1416 my @info; |
|
1417 push @info, ['File', 'Status', 'Category']; |
|
1418 foreach my $cat (@{$mrpData->BinaryCategories()}) { |
|
1419 foreach my $file (@{$mrpData->Binaries($cat)}) { |
|
1420 push @info, [$file, 'pending release', $cat]; |
|
1421 } |
|
1422 } |
|
1423 foreach my $cat (@{$mrpData->ExportCategories()}) { |
|
1424 foreach my $file (@{$mrpData->Exports($cat)}) { |
|
1425 push @info, [$file, 'pending release', $cat]; |
|
1426 } |
|
1427 } |
|
1428 # To do ideally: add another column to report which bld.inf each binary |
|
1429 # comes from (if any). This requires quite a lot of internal restructuring |
|
1430 # of MrpData.pm so will probably never happen... It's not worth the benefits. |
|
1431 return \@info; |
|
1432 } |
|
1433 |
|
1434 sub DESTROY { |
|
1435 my $self = shift; |
|
1436 $self->Close(); |
|
1437 } |
|
1438 |
|
1439 sub EvalidateDirectories { |
|
1440 my $self = shift; |
|
1441 my $firstdirectory = shift; |
|
1442 my $seconddirectory = shift; |
|
1443 my $keepGoing = shift; |
|
1444 |
|
1445 my $clean = 1; |
|
1446 my $fullEvalidName = Utils::FindInPath('evalid.bat'); |
|
1447 |
|
1448 # Call evalid to compare these with those installed in the environment. |
|
1449 if ($self->{verbose} > 1) { |
|
1450 print "Evalid command is $fullEvalidName -c $firstdirectory $seconddirectory\n"; |
|
1451 } |
|
1452 open EVALID, "$fullEvalidName -c $firstdirectory $seconddirectory|" or die "Error: Couldn't run EValid: $!\n"; |
|
1453 my $thisLine; |
|
1454 while ($thisLine = <EVALID>) { |
|
1455 my $acceptablefailures = ACCEPTABLE_EVALID_FAILURES; |
|
1456 if ($thisLine =~ m/MISSING:|FAILED:|PROBLEM:/ && $thisLine !~ m/$acceptablefailures/i) { |
|
1457 if ($self->{verbose}) { print $thisLine; } |
|
1458 $clean = 0; |
|
1459 unless ($keepGoing) { |
|
1460 last; |
|
1461 } |
|
1462 } |
|
1463 elsif ($self->{verbose} > 1) { |
|
1464 print $thisLine; |
|
1465 } |
|
1466 } |
|
1467 close EVALID; |
|
1468 |
|
1469 return $clean; |
|
1470 } |
|
1471 |
|
1472 sub ScanEnv { |
|
1473 my $self = shift; |
|
1474 my $displayProgress = shift; |
|
1475 my $progressTuner = 0; |
|
1476 |
|
1477 my $processFileSub = sub { |
|
1478 if ($displayProgress) { |
|
1479 ++$progressTuner; |
|
1480 if ($progressTuner >= SCAN_PROGRESS_TUNER) { |
|
1481 $progressTuner = 0; |
|
1482 select STDOUT; $|=1; |
|
1483 print "."; |
|
1484 } |
|
1485 } |
|
1486 my $thisFile = lc($File::Find::name); |
|
1487 Utils::TidyFileName(\$thisFile); |
|
1488 if (-f $thisFile) { |
|
1489 $self->{envFileList}->{$thisFile} = 1; |
|
1490 } |
|
1491 elsif (-d $thisFile and $self->CheckIgnoreDir($thisFile)) { |
|
1492 $File::Find::prune = 1; |
|
1493 } |
|
1494 elsif (-d $thisFile && !@{Utils::ReadDir($thisFile)}) { |
|
1495 # This is an empty directory. It is not possible to own empty directories, |
|
1496 #so this will be included in the unowned list |
|
1497 $self->{envFileList}->{$thisFile} = 1; |
|
1498 } |
|
1499 }; |
|
1500 |
|
1501 my $cwd = cwd(); |
|
1502 $cwd =~ s/:$/:\\/; # Needed because if at root, cwd() just returns drive_letter: |
|
1503 find($processFileSub, Utils::PrependEpocRoot('\\epoc32')); |
|
1504 chdir ($cwd); |
|
1505 if ($displayProgress and $self->{verbose}) { |
|
1506 print "\n"; |
|
1507 } |
|
1508 } |
|
1509 |
|
1510 sub CheckIgnoreDir { |
|
1511 my $self = shift; |
|
1512 my $dir = shift; |
|
1513 if (exists $self->{ignoreDirs}->{$dir}) { |
|
1514 return 1; |
|
1515 } |
|
1516 return 0; |
|
1517 } |
|
1518 |
|
1519 # Classify the ignores according to whether they correspond to directories or files. This allows the |
|
1520 # File::Find scan to prune directories to be ignored efficiently. |
|
1521 sub InitIgnores { |
|
1522 my $self = shift; |
|
1523 my $ignoreStandardIgnores = shift; |
|
1524 my $ignoreList; |
|
1525 unless ($ignoreStandardIgnores) { |
|
1526 $ignoreList = $self->{iniData}->BinariesToIgnore(); |
|
1527 } |
|
1528 push (@$ignoreList, '\\epoc32\\relinfo\\*'); # Need to always ignore \epoc32\relinfo since this contains the environment database. |
|
1529 |
|
1530 foreach my $thisIgnore (@$ignoreList) { |
|
1531 if ($thisIgnore =~ /(.*)\\\*$/) { |
|
1532 my $dir = $1; |
|
1533 Utils::TidyFileName(\$dir); |
|
1534 $self->{ignoreDirs}->{lc(Utils::PrependEpocRoot($dir))} = 1; # Store dirs in a hash so they can be looked up fast. |
|
1535 } |
|
1536 else { |
|
1537 push (@{$self->{ignoreFiles}}, Utils::PrependEpocRoot($thisIgnore)); |
|
1538 } |
|
1539 } |
|
1540 } |
|
1541 |
|
1542 sub CheckFileAgainstEnvScan { |
|
1543 my $self = shift; |
|
1544 my $file = lc(shift); |
|
1545 my $ok = 1; |
|
1546 |
|
1547 if (exists $self->{envFileList}) { |
|
1548 if (exists $self->{envFileList}->{$file}) { |
|
1549 # Exists, so remove from envFileList hash - any file names left in here at the end will be reported to the user. |
|
1550 delete $self->{envFileList}->{$file}; |
|
1551 } |
|
1552 else { |
|
1553 $ok = 0; |
|
1554 } |
|
1555 } |
|
1556 elsif (not -e $file) { |
|
1557 $ok = 0; |
|
1558 } |
|
1559 return $ok; |
|
1560 } |
|
1561 |
|
1562 sub RemoveBinsToIgnore { |
|
1563 my $self = shift; |
|
1564 foreach my $thisIgnore (@{$self->{ignoreFiles}}) { |
|
1565 $thisIgnore =~ s/\\/\\\\/g; |
|
1566 $thisIgnore =~ s/\./\\\./g; |
|
1567 $thisIgnore =~ s/\*/\.\*/g; |
|
1568 foreach my $thisFile (keys %{$self->{envFileList}}) { |
|
1569 if ($thisFile =~ /$thisIgnore/i) { |
|
1570 delete $self->{envFileList}->{$thisFile}; |
|
1571 } |
|
1572 } |
|
1573 } |
|
1574 } |
|
1575 |
|
1576 sub UnaccountedEnvFiles { |
|
1577 my $self = shift; |
|
1578 my @unaccountedFiles = sort keys %{$self->{envFileList}}; |
|
1579 return \@unaccountedFiles; |
|
1580 } |
|
1581 |
|
1582 sub DeleteSignature { |
|
1583 my $self = shift; |
|
1584 my $comp = shift; |
|
1585 my $ver = shift; |
|
1586 |
|
1587 if ($self->{verbose} > 1) { print "Deleting signature file for $comp $ver\n"; } |
|
1588 my $sigName = SignatureName($comp, $ver); |
|
1589 unlink ($sigName) or print "Warning: Couldn't delete $sigName: $!\n"; |
|
1590 } |
|
1591 |
|
1592 sub ExecuteAllSignatures { |
|
1593 my $sub = shift; |
|
1594 |
|
1595 opendir(DIR, Utils::PrependEpocRoot("\\epoc32\\relinfo")) or die "Error: Couldn't open directory \"" . Utils::PrependEpocRoot("\\epoc32\\relinfo") . "\": $!\n"; |
|
1596 while (defined(my $file = readdir(DIR))) { |
|
1597 if ($file =~ /\.sig$/) { |
|
1598 my $continue = ExecuteSignature(Utils::PrependEpocRoot("\\epoc32\\relinfo\\$file"), $sub); |
|
1599 unless ($continue) { |
|
1600 last; |
|
1601 } |
|
1602 } |
|
1603 } |
|
1604 closedir(DIR); |
|
1605 } |
|
1606 |
|
1607 sub ExecuteSignature { |
|
1608 # For each line in the signature file, parse and call the given subroutine with the parsed variables. |
|
1609 |
|
1610 my $sigName = shift; |
|
1611 my $filessub = shift; |
|
1612 my $directoriesSub = shift; |
|
1613 |
|
1614 my %directories; |
|
1615 |
|
1616 my $continue = 1; |
|
1617 open (SIG, $sigName) or die "Couldn't open $sigName for reading: $!\n"; |
|
1618 while (my $line = <SIG>) { |
|
1619 # Parse signature line. |
|
1620 (my $file, my $mTime, my $size) = split (/\t/, $line); |
|
1621 unless (defined $file and defined $mTime and defined $size) { |
|
1622 die "Error: Invalid line in signature file $sigName\n"; |
|
1623 } |
|
1624 $directories{dirname($file)} = 1; |
|
1625 # Call subroutine. |
|
1626 $continue = &$filessub(Utils::PrependEpocRoot($file), $mTime, $size, $sigName); |
|
1627 unless ($continue) { |
|
1628 last; |
|
1629 } |
|
1630 } |
|
1631 close (SIG); |
|
1632 |
|
1633 if ($directoriesSub) { |
|
1634 foreach my $directory (sort keys %directories) { |
|
1635 &$directoriesSub(Utils::PrependEpocRoot($directory), $sigName); |
|
1636 } |
|
1637 } |
|
1638 |
|
1639 return $continue; |
|
1640 } |
|
1641 |
|
1642 sub DeleteFilesInSignature { |
|
1643 my $self = shift; |
|
1644 my $comp = shift; |
|
1645 my $ver = shift; |
|
1646 my $sigName = SignatureName($comp, $ver); |
|
1647 my $filesDeletionSub = sub { |
|
1648 my $file = shift; |
|
1649 if (-e $file) { |
|
1650 if ($self->{verbose} > 1) { print "Deleting \"$file\"...\n"; } |
|
1651 unlink ($file) or die "Error: Couldn't delete \"$file\": $!\n"; |
|
1652 } |
|
1653 return 1; |
|
1654 }; |
|
1655 my $directoriesDeletionSub = sub { |
|
1656 my $directory = shift; |
|
1657 |
|
1658 if (-e $directory && !scalar @{Utils::ReadDir($directory)} ) { |
|
1659 print "Removing directory $directory...\n" if ($self->{verbose}); |
|
1660 rmdir $directory or die "Error: Could not remove directory $directory: $!\n"; |
|
1661 while (($directory = dirname($directory)) && -e $directory && !scalar @{Utils::ReadDir($directory)}) { |
|
1662 print "Removing directory $directory...\n" if ($self->{verbose}); |
|
1663 rmdir $directory or die "Error: Could not remove directory $directory: $!\n"; |
|
1664 } |
|
1665 } |
|
1666 }; |
|
1667 |
|
1668 ExecuteSignature($sigName, $filesDeletionSub, $directoriesDeletionSub); |
|
1669 } |
|
1670 |
|
1671 sub InstallComponent { |
|
1672 my $self = shift; |
|
1673 my $comp = lc(shift); |
|
1674 my $ver = shift; |
|
1675 my $overwrite = shift; |
|
1676 |
|
1677 my $relData = RelData->Open($self->{iniData}, $comp, $ver, $self->{verbose}); |
|
1678 $relData->WarnIfReleaseTooNew(); |
|
1679 $self->UnpackBinaries($comp, $ver, Utils::EpocRoot(), $overwrite); |
|
1680 $self->GenerateSignature($comp, $ver); |
|
1681 $self->SetVersion($comp, $ver); |
|
1682 $self->SetMrpName($comp, $relData->MrpName()); |
|
1683 $self->SetInternalVersion($comp, $relData->InternalVersion()); |
|
1684 $self->SetStatus($comp, STATUS_CLEAN); |
|
1685 } |
|
1686 |
|
1687 sub UnpackBinaries { |
|
1688 my $self = shift; |
|
1689 my $comp = shift; |
|
1690 my $ver = shift; |
|
1691 my $where = shift; |
|
1692 my $overwrite = (shift || $self->{overwrite}); |
|
1693 foreach my $thisBinZip (@{$self->RelevantBinaryZips($comp, $ver)}) { |
|
1694 $overwrite = Utils::Unzip($thisBinZip, $where, $self->{verbose}, $overwrite); |
|
1695 } |
|
1696 |
|
1697 $self->{overwrite} = $overwrite; |
|
1698 } |
|
1699 |
|
1700 sub RelevantBinaryZips { |
|
1701 my $self = shift; |
|
1702 my $comp = shift; |
|
1703 my $ver = shift; |
|
1704 $self->PathData()->CheckReleaseExists($comp, $ver); |
|
1705 |
|
1706 my $requiredBinaries = $self->{iniData}->RequiredBinaries($comp); |
|
1707 my $relDir = $self->PathData->LocalArchivePathForExistingOrNewComponent($comp, $ver); |
|
1708 my @relevantBinaries = (); |
|
1709 foreach my $thisRelFile (@{Utils::ReadDir($relDir)}) { |
|
1710 if ($thisRelFile eq 'binaries.zip') { |
|
1711 push (@relevantBinaries, "$relDir\\$thisRelFile"); |
|
1712 next; |
|
1713 } |
|
1714 if ($thisRelFile =~ /^binaries_(.*)\.zip$/) { |
|
1715 my $category = $1; |
|
1716 if ($requiredBinaries) { |
|
1717 foreach my $requiredBinary (@$requiredBinaries) { |
|
1718 if (($category =~ /^$requiredBinary\_/) || ($category eq $requiredBinary)) { |
|
1719 push (@relevantBinaries, "$relDir\\$thisRelFile"); |
|
1720 last; |
|
1721 } |
|
1722 } |
|
1723 } |
|
1724 else { |
|
1725 push (@relevantBinaries, "$relDir\\$thisRelFile"); |
|
1726 } |
|
1727 } |
|
1728 elsif ($thisRelFile =~ /^exports[a-z].zip$/i) { |
|
1729 push (@relevantBinaries, "$relDir\\$thisRelFile"); |
|
1730 } |
|
1731 } |
|
1732 return \@relevantBinaries; |
|
1733 } |
|
1734 |
|
1735 sub UnpackSource { |
|
1736 my $self = shift; |
|
1737 my $comp = shift; |
|
1738 my $ver = shift; |
|
1739 my $where = shift; |
|
1740 my $overwrite = shift; |
|
1741 my $skipinstall = 0; |
|
1742 unless (defined $overwrite) { |
|
1743 $overwrite = 0; |
|
1744 } |
|
1745 my $showProgress = shift; |
|
1746 unless (defined $showProgress) { |
|
1747 $showProgress = 0; |
|
1748 } |
|
1749 my $toValidate = shift; |
|
1750 unless (defined $toValidate) { |
|
1751 $toValidate = 0; |
|
1752 } |
|
1753 |
|
1754 my $changeInCat = 0; |
|
1755 |
|
1756 $self->PathData()->CheckReleaseExists($comp, $ver); |
|
1757 |
|
1758 if ($where eq "\\") { |
|
1759 $where = Utils::SourceRoot(); |
|
1760 } |
|
1761 |
|
1762 # Unpack all categories of source code that are available. |
|
1763 my $relDir = $self->PathData->LocalArchivePathForExistingOrNewComponent($comp, $ver); |
|
1764 |
|
1765 opendir(RELDIR, $relDir) or die "Error: can't opendir $relDir\n"; |
|
1766 my @srcZipNames = grep {/source[a-z]\.zip/i} map {"$relDir\\$_"} readdir(RELDIR); |
|
1767 close RELDIR; |
|
1768 |
|
1769 if ($self->{verbose} and scalar(@srcZipNames) == 0) { |
|
1770 print "No source available for $comp $ver\n"; |
|
1771 } |
|
1772 else { |
|
1773 unless ($overwrite) { |
|
1774 my $checkFailed = 0; |
|
1775 foreach my $thisSrcZip (@srcZipNames) { |
|
1776 if (Utils::CheckZipFileContentsNotPresent($thisSrcZip, $where, $self->{iniData})) { |
|
1777 $checkFailed = 1; |
|
1778 } |
|
1779 } |
|
1780 if ($checkFailed) { |
|
1781 warn "Warning: Above errors found, skipping the unpacking of $comp zips...\n"; |
|
1782 $skipinstall = 1; |
|
1783 } |
|
1784 } |
|
1785 |
|
1786 unless($skipinstall){ |
|
1787 foreach my $thisSrcZip (@srcZipNames) { |
|
1788 if ($showProgress) { |
|
1789 my $significantDir = Utils::SignificantZipDir($thisSrcZip); |
|
1790 my $unzipDir = Utils::ConcatenateDirNames($where, $significantDir); |
|
1791 |
|
1792 if($self->{iniData}->HasMappings()){ |
|
1793 $unzipDir = $self->{iniData}->PerformMapOnFileName($unzipDir); |
|
1794 } |
|
1795 |
|
1796 print "\tUnpacking \"$thisSrcZip\" into \"$unzipDir\"...\n"; |
|
1797 } |
|
1798 |
|
1799 $changeInCat = Utils::UnzipSource($thisSrcZip, $where, $self->{verbose}, $overwrite, $self->{iniData}, $toValidate, $comp); |
|
1800 if($changeInCat==1 && $toValidate ==1) { |
|
1801 last; |
|
1802 } |
|
1803 } |
|
1804 } |
|
1805 } |
|
1806 |
|
1807 return $changeInCat; # 1 = change in cat found, 0 = change in cat not found. Return value only used for validation. |
|
1808 } |
|
1809 |
|
1810 sub SignatureName { |
|
1811 my $comp = shift; |
|
1812 my $ver = shift; |
|
1813 croak unless defined $ver; |
|
1814 return Utils::PrependEpocRoot("\\epoc32\\relinfo\\$comp.$ver.sig"); |
|
1815 } |
|
1816 |
|
1817 sub DecodeSignatureName { |
|
1818 my $self = shift; |
|
1819 my $sigName = shift; |
|
1820 my $comp; |
|
1821 my $ver; |
|
1822 my $name = $sigName; |
|
1823 $name =~ s/.*\\epoc32\\relinfo\\(.*)\.sig/$1/; |
|
1824 foreach my $thisComp (keys %{$self->{db}}) { |
|
1825 my $thisVer = $self->{db}->{$thisComp}->{ver}; |
|
1826 if ("$thisComp.$thisVer" eq $name) { |
|
1827 $comp = $thisComp; |
|
1828 $ver = $thisVer; |
|
1829 } |
|
1830 } |
|
1831 |
|
1832 unless (defined $comp and defined $ver) { |
|
1833 die "Error: Couldn't decode signature name \"$sigName\"\n"; |
|
1834 } |
|
1835 |
|
1836 return ($comp, $ver); |
|
1837 } |
|
1838 |
|
1839 sub ComponentDir { |
|
1840 require Carp; |
|
1841 Carp->import; |
|
1842 confess ("Obsolete method called"); |
|
1843 } |
|
1844 |
|
1845 sub ReleaseDir { |
|
1846 require Carp; |
|
1847 Carp->import; |
|
1848 confess ("Obsolete method called"); |
|
1849 } |
|
1850 |
|
1851 sub PathData { |
|
1852 my $self = shift; |
|
1853 return $self->{iniData}->PathData(); |
|
1854 } |
|
1855 |
|
1856 sub CheckForAddedFiles { |
|
1857 my $self = shift; |
|
1858 my $reldata = shift; |
|
1859 my $tempdir = shift; |
|
1860 |
|
1861 # Here we have been asked to search for files that exist in the real source directory, |
|
1862 # but don't exist in the temporary source directory. |
|
1863 |
|
1864 my $foundextra = 0; # let's hope this stays zero |
|
1865 foreach my $item (keys %{$reldata->SourceItems}) { |
|
1866 $item = Utils::PrependSourceRoot($item); |
|
1867 next unless -d $item; # we're only checking for added files, so we don't care unless this |
|
1868 # is a directory in which there ought to be files. |
|
1869 |
|
1870 print "Looking for added files inside \"$item\"\n" if ($self->{verbose}); |
|
1871 # Ah, the lovely Find::File |
|
1872 find(sub { |
|
1873 my $tempfile = Utils::ConcatenateDirNames($tempdir, Utils::RemoveSourceRoot($File::Find::name)); |
|
1874 # Be careful with that line - an extra \\ anywhere and it breaks, such is DOS... |
|
1875 |
|
1876 print "Checking existence of \"$tempfile\"\n" if ($self->{verbose}>1); |
|
1877 unless (-e $tempfile) { |
|
1878 print "\"$File::Find::name\" only exists in new source code.\n" if ($self->{verbose}); |
|
1879 $foundextra++; |
|
1880 $File::Find::prune = 1 unless ($self->{verbose}); # skip some of the rest |
|
1881 } |
|
1882 }, $item); |
|
1883 |
|
1884 return $foundextra if ($foundextra && !$self->{verbose}); |
|
1885 # don't bother scanning other directories unless it's verbose |
|
1886 } |
|
1887 return $foundextra; |
|
1888 } |
|
1889 |
|
1890 sub GetReleaseSize { |
|
1891 my $self = shift; |
|
1892 my $comp = shift; |
|
1893 my $ver = shift; |
|
1894 $self->{relsize}->{$comp}->{$ver} = $self->AddUpReleaseSize($comp, $ver) unless defined $self->{relsize}->{$comp}->{$ver}; |
|
1895 return $self->{relsize}->{$comp}->{$ver}; |
|
1896 } |
|
1897 |
|
1898 sub AddUpReleaseSize { |
|
1899 my $self = shift; |
|
1900 my $comp = shift; |
|
1901 my $version = shift; |
|
1902 my $pathdata = $self->{iniData}->PathData(); |
|
1903 my $path = $pathdata->LocalArchivePathForExistingComponent($comp, $version); |
|
1904 die "Component $comp $version didn't exist\n" unless $path; |
|
1905 opendir(DIR, $path) or die "Couldn't open directory \"$path\" because $!"; |
|
1906 my @entries = grep { ! m/^\./ } readdir(DIR); |
|
1907 closedir DIR; |
|
1908 my $size = 0; |
|
1909 print "Adding up size of $comp $version\n" if ($self->{verbose}); |
|
1910 foreach my $file (@entries) { |
|
1911 my $full = $path . "\\" . $file; |
|
1912 $size += -s $full; |
|
1913 } |
|
1914 return $size; |
|
1915 } |
|
1916 |
|
1917 sub GetEnvironmentSize { |
|
1918 my $self = shift; |
|
1919 my $comp = shift; |
|
1920 my $ver = shift; |
|
1921 my $deltasize = shift; |
|
1922 $self->{envsize}->{$comp}->{$ver} = $self->AddUpEnvSize($comp, $ver, $deltasize) if (!exists $self->{envsize}->{$comp}->{$ver}); |
|
1923 return $self->{envsize}->{$comp}->{$ver}; |
|
1924 } |
|
1925 |
|
1926 sub AddUpEnvSize { |
|
1927 my $self = shift; |
|
1928 my $maincomp = shift; |
|
1929 my $mainver = shift; |
|
1930 my $deltasize = shift; |
|
1931 my $relData = RelData->Open($self->{iniData}, $maincomp, $mainver, $self->{verbose}); |
|
1932 die "Component $maincomp version $mainver didn't exist\n" unless $relData; |
|
1933 my $compsToValidate = $relData->Environment(); |
|
1934 my $size = 0; |
|
1935 while ((my $comp, my $ver) = each %$compsToValidate) { |
|
1936 # If a delta size is requested and the component version does not |
|
1937 # match the main component version then don't increment the size |
|
1938 next if ($deltasize && ($mainver ne $ver)); |
|
1939 |
|
1940 $size += $self->GetReleaseSize($comp, $ver); |
|
1941 } |
|
1942 return $size; |
|
1943 } |
|
1944 |
|
1945 1; |
|
1946 |
|
1947 __END__ |
|
1948 |
|
1949 =head1 NAME |
|
1950 |
|
1951 EnvDb.pm - A database to keep track of component versions installed on a development drive. |
|
1952 |
|
1953 =head1 DESCRIPTION |
|
1954 |
|
1955 The database is implemented as a tied hash. It provides a persistent store of component / version pairs. Also provides facilities for checking and validating the contents of an environemnt. |
|
1956 |
|
1957 Each component has a status associated with it. The possible values are as follows: |
|
1958 |
|
1959 =over 4 |
|
1960 |
|
1961 =item C<STATUS_CLEAN>: the binaries on disk match those in the release packet |
|
1962 |
|
1963 =item C<STATUS_DIRTY>: the binaries on disk don't appear to match those in the release packet |
|
1964 |
|
1965 =item C<STATUS_DIRTY_SOURCE>: the binaries match, but the source code doesn't |
|
1966 |
|
1967 =item C<STATUS_PENDING_RELEASE>: the component has been set to 'pending release' |
|
1968 |
|
1969 =back |
|
1970 |
|
1971 =head1 INTERFACE |
|
1972 |
|
1973 =head2 Object Management |
|
1974 |
|
1975 =head3 Open |
|
1976 |
|
1977 Expects to be passed an C<IniData> reference and a verbosity level. Opens the C<EnvDb> on the current drive. If not already present, an empty databse is created. This must be done before any of the following interfaces are used. |
|
1978 |
|
1979 =head3 Close |
|
1980 |
|
1981 Closes the database file. |
|
1982 |
|
1983 =head2 Data Management |
|
1984 |
|
1985 =head3 Version |
|
1986 |
|
1987 Expects to be passed a component name. Returns the version of the component that is currently installed. Returns undef if there is no version currently installed. |
|
1988 |
|
1989 =head3 VersionInfo |
|
1990 |
|
1991 Returns a reference to an in memory hash containing component component name / version pairs for every entry in the database. |
|
1992 |
|
1993 =head3 SetVersion |
|
1994 |
|
1995 Expects to be passed a component name and a optionally a version. If the version is specified, a database entry for the component is created, or, if it is already present, updated. If the version is not specified, and a database entry for the component entry exists, it is deleted. |
|
1996 |
|
1997 =head3 InternalVersion |
|
1998 |
|
1999 Expects to be passed a component name. Returns the internal version of the component that is currently installed. Returns undef if the component is not currently installed. |
|
2000 |
|
2001 =head3 SetInternalVersion |
|
2002 |
|
2003 Expects to be passed a component name and an internal version. Dies if an entry for the component is not already present in the database. Store the component's internal version. |
|
2004 |
|
2005 =head3 Status |
|
2006 |
|
2007 Expects to be passed a component name. Dies if an entry for the component is not already present in the database. Returns the component's last recorded status (which may be C<STATUS_CLEAN>, C<STATUS_DIRTY> or C<STATUS_PENDING_RELEASE>). |
|
2008 |
|
2009 =head3 SetStatus |
|
2010 |
|
2011 Expects to be passed a component name and a status integer. Dies if an entry for the component is not already present in the database. Updates the component's database entry with the new status. |
|
2012 |
|
2013 =head3 MrpName |
|
2014 |
|
2015 Expects to be passed a component name. Dies if an entry for the component is not already present in the database. Returns the corresponding F<mrp> name. |
|
2016 |
|
2017 =head3 SetMrpName |
|
2018 |
|
2019 Expects to be passed a component name and an F<mrp> name. Dies if an entry for the component is not already present in the database. Stores of the F<mrp> name of the component. |
|
2020 |
|
2021 =head3 ComponentsPendingRelease |
|
2022 |
|
2023 Returns a reference to a hash of hash references. The primary hash key is component name. The secondary hashes each containing details a component that is pending release. The secondary hashes contain the following keys: |
|
2024 |
|
2025 mrpName |
|
2026 ver |
|
2027 intVer |
|
2028 |
|
2029 =head3 BinaryInfo |
|
2030 |
|
2031 Expects to be passed the name of a binary file. Searches for this file name within the component signatures. If it is not found there, then checks for components that are pending release. C<MrpData> objects are then created for each of these to see if the binary file is about to be released. Dies if the file is still not found. Otherwise, returns a two dimentional array containing the component name, verion and current file status. |
|
2032 |
|
2033 =head3 ListBins |
|
2034 |
|
2035 Expects to be passed a component name. Returns a 2D array containing all the file names owned by component and their current status. These facts will be in the first and second column; subsequent columns may hold further information. The table contains a header row describing what each column is. |
|
2036 |
|
2037 =head2 Environment Scans |
|
2038 |
|
2039 =head3 CheckEnv |
|
2040 |
|
2041 Performs a scan of the F<\epoc32> tree building a hash of all file names. Calls C<CheckComp> for all the components installed on the drive. C<CheckComp> will remove files that pass the check from the F<\epoc32> tree hash. Any file names left in the hash after all components have been checked will be printed to warn the user, since their origin is unknown to the release tools. The F<reltools.ini> keyword C<ignore_binary> my be used to specify (using file names with DOS style wild characters) binary files to be ignored in the checking process. As standard, the following are ignored: |
|
2042 |
|
2043 \epoc32\relinfo\* |
|
2044 \epoc32\build\* |
|
2045 \epoc32\wins\c\* |
|
2046 \epoc32\release\*.ilk |
|
2047 \epoc32\release\*.bsc |
|
2048 \epoc32\data\emulator\epoc.sys.ini |
|
2049 |
|
2050 Returns the overall status of the environement after the check (which may be of value C<STATUS_CLEAN>, C<STATUS_DIRTY> or C<STATUS_PENDING_RELEASE>), a reference to a list of C<MrpData> objects that are pending release, a reference to a list of component that failed their check, and a reference to a list of unaccounted files. |
|
2051 |
|
2052 =head3 CheckComp |
|
2053 |
|
2054 Expects to be passed a component name and optionally a scalar flag indicating if the check should continue after the first failure is found (true means continue). Details of any files that fail their check will be printed. Returns the status of the component after the check (which may be of value C<STATUS_CLEAN>, C<STATUS_DIRTY>, C<STATUS_DIRTY_SOURCE> or C<STATUS_PENDING_RELEASE>), and a reference to an C<MrpData> object if the status is C<STATUS_PENDING_RELEASE>. |
|
2055 |
|
2056 CheckComp does not check the source code files. In fact, if it determines the binaries match, then it returns either C<STATUS_CLEAN> or C<STATUS_DIRTY_SOURCE> depending on what the environment database says. A component will only ever attain the status of C<STATUS_DIRTY_SOURCE> through the operation of ValidateComp: effectively CheckComp just passes that information through, if the component otherwise appears clean. |
|
2057 |
|
2058 =head3 ValidateEnv |
|
2059 |
|
2060 Calls C<ValidateComp> for all the components installed on the drive that don't have a status of I<pending release>. Returns a reference to a list of components names that failed. May optionally be passed a component name and version of an external environment against which to validate. This mode may only be used when the current environment database is empty. It causes a complete set of database entries to be written corresponding to the external environment. However, a dummy signature file will be generated for components that fail their validation which contains the names of the binaries released in the external environment, but zero last modified times and sizes. This is to ensure that C<CheckEnv> continues to report these components as C<STATUS_DIRTY>. |
|
2061 |
|
2062 =head3 ValidateComp |
|
2063 |
|
2064 Expects to be passed a component name, a version and optionally two scalar flags indicating: |
|
2065 |
|
2066 =over 4 |
|
2067 |
|
2068 =item whether validation should continue after the first failure is found (true means continue) |
|
2069 |
|
2070 =item whether source code should be validated |
|
2071 |
|
2072 =back |
|
2073 |
|
2074 Makes use of Manifest.pm and constructs manifest object of the current environment using the mrp file for the components and another manifest object using the manifest file available in the archive location of the previous release for the component. These objects are compared for their similarity and shall return STATUS_CLEAN if everything validates OK and returns STATUS_DIRTY otherwise. |
|
2075 |
|
2076 If for some reasons, validation through manifest objects is not possible, then the call is transferred to the old process of validation described herewith as follows: |
|
2077 |
|
2078 The process returns the overall status of the release, which is C<STATUS_DIRTY> if there are dirty binaries, C<STATUS_DIRTY_SOURCE> if the binaries are clean but there is dirty source code, or C<CLEAN> if everything validates OK. C<STATUS_DIRTY_SOURCE> will only ever be set if source code validation is turned on; otherwise all components will be set to either C<CLEAN> or C<DIRTY>. |
|
2079 |
|
2080 If the validation passes, but there is currently no entry for the release in the database, an entry is created with details corresponding to the version being validated. Whether or not an entry previously existed, if the validation passes, the component's status is set to C<STATUS_CLEAN> and a signature file is generated. If the validation failed and there is already an entry in the database for the component, it's status is set to C<STATUS_DIRTY> or C<STATUS_DIRTY_SOURCE> as appropriate. |
|
2081 |
|
2082 If the overall process results in validating the component status as DIRTY, then the manifest information for the current environment will be generated and saved as a manifest file in a temporary location within local file system for use during release processes. |
|
2083 |
|
2084 =head2 Environment Management |
|
2085 |
|
2086 =head3 InstallComponent |
|
2087 |
|
2088 Expects to be passed a component name, and a version. Unpacks the component's binaries, and creates (or updates) a complete database entry from the provided version and information read out of the release's C<RelData> object. |
|
2089 |
|
2090 =head3 RemoveComponent |
|
2091 |
|
2092 Expects to be passed a component name. Removes all the binary files associated with the installed version of the component, the component's signature file and the component's environment database record. |
|
2093 |
|
2094 =head3 DeleteSource |
|
2095 |
|
2096 Expects to be passed a component name, a dryrun and a force flag. Removes all the source files associated with the installed version of the component. If dryrun is used the script just reports what it would do. If force is used the script would delete write-protected files. |
|
2097 |
|
2098 =head3 UnpackBinaries |
|
2099 |
|
2100 Expects to be passed a component name, a version and a directory in which the release should be installed. Unpacks the component's binaries into the specified directory. The environment database is neither consulted, nor modified by this interface. It is intended to allow a set of released binaries to be temporarily unpacked (for example, for validation purposes) |
|
2101 |
|
2102 =head3 UnpackSource |
|
2103 |
|
2104 Expects to be passed a component name, a version, a directory in which the release should be installed, a flag which represents the verbose level, a flag which represents to overwrite or not, an inidata and a flag which represent whether this process is for validation or not. Unpacks the component's source into the specified directory. The environment database is neither consulted, nor modified by this interface. Returns a change in category flag, when flag is 1 a change in category has been found. Change in category flag is only uses when a validation occurs. |
|
2105 |
|
2106 =head3 GetReleaseSize |
|
2107 |
|
2108 Takes a component name and a version number. Returns the total size (in bytes) of the zips in the local archive making up a release. |
|
2109 |
|
2110 =head3 GetEnvironmentSize |
|
2111 |
|
2112 Takes a component name and a version number. Returns the total size (in bytes) of the zips in the local archive making up the environment. |
|
2113 |
|
2114 =head2 Notable private methods |
|
2115 |
|
2116 =head3 EvalidateDirectories |
|
2117 |
|
2118 Expects to be passed two directory names; it will then run C<EValid> over the two. Returns a Boolean (whether the two directories match), and prints the results according to the verbosity level. If the verbosity level is 1 or greater, details of failures are printed. If the verbosity level is greater than 1, all C<EValid> output is printed. |
|
2119 |
|
2120 =head3 CheckForAddedFiles |
|
2121 |
|
2122 This method checks to see if any files have been added to a component since it was packetised. It's part of source validation. It uses C<Find::File> to list all the files that are in a component's source code directory, then checks each of them are in a temporary directory which has been unzipped from the release packet. |
|
2123 |
|
2124 =head1 KNOWN BUGS |
|
2125 |
|
2126 None. |
|
2127 |
|
2128 =head1 COPYRIGHT |
|
2129 |
|
2130 Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2131 All rights reserved. |
|
2132 This component and the accompanying materials are made available |
|
2133 under the terms of the License "Eclipse Public License v1.0" |
|
2134 which accompanies this distribution, and is available |
|
2135 at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
2136 |
|
2137 Initial Contributors: |
|
2138 Nokia Corporation - initial contribution. |
|
2139 |
|
2140 Contributors: |
|
2141 |
|
2142 Description: |
|
2143 |
|
2144 |
|
2145 =cut |