602
+ − 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