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
+ − 17
package RelData;
+ − 18
+ − 19
use strict;
+ − 20
use Data::Dumper;
+ − 21
use MrpData;
+ − 22
use PathData;
+ − 23
+ − 24
#
+ − 25
# Data version history.
+ − 26
#
+ − 27
# 1 - Original release.
+ − 28
# 2 - Added 'relToolsVer' tag.
+ − 29
#
+ − 30
+ − 31
+ − 32
#
+ − 33
# Public.
+ − 34
#
+ − 35
+ − 36
sub New {
+ − 37
my $pkg = shift;
+ − 38
my $self = {};
+ − 39
bless $self, $pkg;
+ − 40
$self->{iniData} = shift;
+ − 41
$self->{mrpData} = shift;
+ − 42
$self->{notesSrc} = shift;
+ − 43
$self->{data}->{env} = shift;
+ − 44
$self->{data}->{toolName} = shift;
+ − 45
$self->{verbose} = shift;
+ − 46
$self->{dontPersist} = shift;
+ − 47
$self->{project} = shift;
+ − 48
+ − 49
$self->{comp} = $self->{mrpData}->Component();
+ − 50
$self->{ver} = $self->{mrpData}->ExternalVersion();
+ − 51
$self->{data}->{dataFormatVer} = 2;
+ − 52
$self->{data}->{intVer} = $self->{mrpData}->InternalVersion();
+ − 53
$self->{data}->{mrpName} = $self->{mrpData}->MrpName();
+ − 54
$self->{data}->{relToolsVer} = Utils::ToolsVersion();
+ − 55
$self->{data}->{notesSrc}->{srcFilterErrors} = $self->{mrpData}->SourceFilterErrors();
+ − 56
$self->{data}->{notesSrc}->{date} = localtime;
+ − 57
+ − 58
foreach my $srcitem (keys %{$self->{mrpData}->SourceItems()}) {
+ − 59
if($self->{iniData}->HasMappings()){
+ − 60
$srcitem = $self->{iniData}->PerformReverseMapOnFileName($srcitem);
+ − 61
$srcitem = Utils::RemoveSourceRoot($srcitem);
+ − 62
}
+ − 63
+ − 64
$self->{data}->{srcitems}->{$srcitem} = 1;
+ − 65
}
+ − 66
+ − 67
unless(defined $self->{data}->{srcitems}){
+ − 68
$self->{data}->{srcitems} = $self->{mrpData}->SourceItems();
+ − 69
}
+ − 70
+ − 71
$self->{data}->{envUserName} = ($ENV{FirstName} || '') . " " . ($ENV{LastName} || '');
+ − 72
$self->ParseNotesSource();
+ − 73
$self->WorkOutFirstCompatibleVersion();
+ − 74
unless (defined $self->{dontPersist}) {
+ − 75
$self->WriteToFile();
+ − 76
}
+ − 77
return $self;
+ − 78
}
+ − 79
+ − 80
sub Open {
+ − 81
my $pkg = shift;
+ − 82
my $self = {};
+ − 83
bless $self, $pkg;
+ − 84
$self->{iniData} = shift;
+ − 85
$self->{comp} = shift;
+ − 86
$self->{ver} = shift;
+ − 87
$self->{verbose} = shift;
+ − 88
$self->ReadFromFile();
+ − 89
return $self;
+ − 90
}
+ − 91
+ − 92
sub OpenExternal {
+ − 93
my $pkg = shift;
+ − 94
my $externalArchive = shift;
+ − 95
my $comp = shift;
+ − 96
my $ver = shift;
+ − 97
my $self = {};
+ − 98
$self->{comp} = $comp;
+ − 99
$self->{ver} = $ver;
+ − 100
my $externalFile = File::Spec->catdir($externalArchive, $comp, $ver);
+ − 101
bless $self, $pkg;
+ − 102
$self->ReadFromSpecificFile($externalFile);
+ − 103
return $self;
+ − 104
}
+ − 105
+ − 106
+ − 107
sub OpenSet {
+ − 108
my $pkg = shift;
+ − 109
my $iniData = shift;
+ − 110
my $comp = shift;
+ − 111
my $verbose = shift;
+ − 112
my $versionfilter = shift;
+ − 113
+ − 114
my @relDataObjects;
+ − 115
foreach my $ver (@{$iniData->PathData->ListVersions($comp, 0, $versionfilter, $iniData->LatestVerFilter)}) {
+ − 116
my $thisRelData = {};
+ − 117
bless $thisRelData, $pkg;
+ − 118
eval {
+ − 119
# ReadFromFile may die, if the file is corrupt.
+ − 120
# In which case we do not add it to the set.
+ − 121
$thisRelData->{iniData} = $iniData;
+ − 122
$thisRelData->{comp} = $comp;
+ − 123
$thisRelData->{ver} = $ver;
+ − 124
$thisRelData->{verbose} = $verbose;
+ − 125
$thisRelData->ReadFromFile();
+ − 126
push (@relDataObjects, $thisRelData);
+ − 127
};
+ − 128
print "Warning: could not examine \"$comp\" \"$ver\" because $@" if ($@);
+ − 129
}
+ − 130
+ − 131
@relDataObjects = sort { $b->ReleaseTime() <=> $a->ReleaseTime() } @relDataObjects;
+ − 132
+ − 133
return \@relDataObjects;;
+ − 134
}
+ − 135
+ − 136
sub Component {
+ − 137
my $self = shift;
+ − 138
die unless exists $self->{comp};
+ − 139
return $self->{comp};
+ − 140
}
+ − 141
+ − 142
sub MadeWith {
+ − 143
my $self = shift;
+ − 144
my $ver = $self->{data}->{relToolsVer} || "(unknown version)";
+ − 145
my $tool = $self->{data}->{toolName} || "(unknown tool)";
+ − 146
return "$tool $ver";
+ − 147
}
+ − 148
+ − 149
sub MadeWithVersion {
+ − 150
my $self = shift;
+ − 151
return "".$self->{data}->{relToolsVer};
+ − 152
}
+ − 153
+ − 154
sub SourceIncluded {
+ − 155
my $self = shift;
+ − 156
my $items;
+ − 157
eval {
+ − 158
$items = $self->SourceItems();
+ − 159
};
+ − 160
return "(unknown)" if $@;
+ − 161
return join (", ", keys %$items);
+ − 162
}
+ − 163
+ − 164
sub Version {
+ − 165
my $self = shift;
+ − 166
die unless exists $self->{ver};
+ − 167
return $self->{ver};
+ − 168
}
+ − 169
+ − 170
sub InternalVersion {
+ − 171
my $self = shift;
+ − 172
die unless exists $self->{data};
+ − 173
return $self->{data}->{intVer};
+ − 174
}
+ − 175
+ − 176
sub MrpName {
+ − 177
my $self = shift;
+ − 178
die unless exists $self->{data};
+ − 179
return $self->{data}->{mrpName};
+ − 180
}
+ − 181
+ − 182
sub FirstCompatibleVersion {
+ − 183
my $self = shift;
+ − 184
die unless exists $self->{data};
+ − 185
return $self->{data}->{firstCompatibleVersion};
+ − 186
}
+ − 187
+ − 188
sub Environment {
+ − 189
my $self = shift;
+ − 190
die unless exists $self->{data};
+ − 191
return $self->{data}->{env};
+ − 192
}
+ − 193
+ − 194
sub NotesSource {
+ − 195
my $self = shift;
+ − 196
die unless exists $self->{data};
+ − 197
return $self->{data}->{notesSrc};
+ − 198
}
+ − 199
+ − 200
sub UpdateProject {
+ − 201
my $self = shift;
+ − 202
$self->{project} = shift;
+ − 203
$self->WriteToFile();
+ − 204
}
+ − 205
+ − 206
sub UpdateNotes {
+ − 207
my $self = shift;
+ − 208
$self->{notesSrc} = shift;
+ − 209
$self->DeleteNotesSource();
+ − 210
$self->ParseNotesSource();
+ − 211
$self->WriteToFile();
+ − 212
}
+ − 213
+ − 214
sub UpdateInternalVersion {
+ − 215
my $self = shift;
+ − 216
$self->{data}->{intVer} = shift;
+ − 217
$self->WriteToFile();
+ − 218
}
+ − 219
+ − 220
sub UpdateEnv {
+ − 221
my $self = shift;
+ − 222
$self->{data}->{env} = shift;
+ − 223
$self->WriteToFile();
+ − 224
}
+ − 225
+ − 226
sub ReleaseTime {
+ − 227
my $self = shift;
+ − 228
unless (exists $self->{releaseTime}) {
+ − 229
$self->{releaseTime} = Utils::TextTimeToEpochSeconds($self->{data}->{notesSrc}->{date});
+ − 230
}
+ − 231
return $self->{releaseTime};
+ − 232
}
+ − 233
+ − 234
sub SourceItems {
+ − 235
my $self = shift;
+ − 236
unless (defined $self->{data}->{srcitems}) {
+ − 237
my $createdver = $self->{data}->{relToolsVer} || 0;
+ − 238
if (Utils::CompareVers($createdver,2.54)<0) {
+ − 239
die "this release was created with Release Tools $createdver, and the necessary information is only present in releases created with 2.54 or later.\n";
+ − 240
}
+ − 241
die "Could not return the list of \"source\" statements used in the MRP file."
+ − 242
}
+ − 243
return $self->{data}->{srcitems};
+ − 244
}
+ − 245
+ − 246
sub EnvUserName {
+ − 247
my $self = shift;
+ − 248
return $self->{data}->{envUserName};
+ − 249
}
+ − 250
+ − 251
#
+ − 252
# Private.
+ − 253
#
+ − 254
+ − 255
sub WriteToFile {
+ − 256
my $self = shift;
+ − 257
my $relDir = $self->{iniData}->PathData->LocalArchivePathForExistingOrNewComponent($self->{comp}, $self->{ver}, $self->{project});
+ − 258
+ − 259
my $file = "$relDir\\reldata";
+ − 260
+ − 261
if (-e $file) {
+ − 262
Utils::SetFileWritable($file);
+ − 263
}
+ − 264
open (OUT, ">$file") or die "Error: Couldn't open \"$file\" for writing: $!\n";
+ − 265
print OUT Data::Dumper->Dump([$self->{data}], ['self->{data}']);
+ − 266
close (OUT);
+ − 267
Utils::SetFileReadOnly($file);
+ − 268
}
+ − 269
+ − 270
sub ReadFromFile {
+ − 271
my $self = shift;
+ − 272
my $pathData = shift || $self->{iniData}->PathData;
+ − 273
+ − 274
my $comp = $self->{comp};
+ − 275
my $ver = $self->{ver};
+ − 276
+ − 277
my $relDir = $pathData->LocalArchivePathForExistingComponent($comp, $ver);
+ − 278
die "Error: \"$comp $ver\" does not exist\n" unless $relDir;
+ − 279
die "Error: \"$comp $ver\" was not a valid release (can't find \"$relDir\\reldata\")\n" unless -e "$relDir\\reldata";
+ − 280
$self->{project} = $pathData->ComponentProject($comp, $ver);
+ − 281
$self->ReadFromSpecificFile($relDir);
+ − 282
}
+ − 283
+ − 284
sub ReadFromSpecificFile {
+ − 285
my $self = shift;
+ − 286
my $relDir = shift;
+ − 287
unless (-e $relDir) {
+ − 288
die "Error: $self->{comp} $self->{ver} does not exist\n";
+ − 289
}
+ − 290
my $file = "$relDir\\reldata";
+ − 291
open (IN, $file) or die "Error: Couldn't open \"$file\" for reading: $!\n";
+ − 292
local $/ = undef;
+ − 293
my $data = <IN>;
+ − 294
die "Error: Reldata in \"$relDir\" is blank" unless $data =~ (m/\S/);
+ − 295
eval ($data) or die "Error: Couldn't parse reldata in \"$relDir\"\n";
+ − 296
close (IN);
+ − 297
}
+ − 298
+ − 299
sub ParseNotesSource {
+ − 300
my $self = shift;
+ − 301
+ − 302
if ($self->{verbose} > 1) { print "Parsing notes source...\n"; }
+ − 303
+ − 304
open(SRC,"$self->{notesSrc}") or die "Unable to open $self->{notesSrc} for reading: $!\n";
+ − 305
+ − 306
my $thisTag;
+ − 307
while (<SRC>) {
+ − 308
if (m/^NOTESRC/i) {
+ − 309
chomp;
+ − 310
$thisTag = $_;
+ − 311
}
+ − 312
elsif (m/^\s*$/) {
+ − 313
next;
+ − 314
}
+ − 315
elsif (defined $thisTag) {
+ − 316
$self->AddLine($thisTag, $_);
+ − 317
}
+ − 318
}
+ − 319
close SRC;
+ − 320
+ − 321
$self->ValidateSource();
+ − 322
}
+ − 323
+ − 324
sub AddLine {
+ − 325
my $self = shift;
+ − 326
my $thisTag = shift;
+ − 327
my $thisLine = shift;
+ − 328
chomp $thisLine;
+ − 329
+ − 330
if ($thisTag =~ m/^NOTESRC_RELEASER$/i) {
+ − 331
$self->{data}->{notesSrc}->{releaser} = $thisLine;
+ − 332
}
+ − 333
elsif ($thisTag =~ m/^NOTESRC_RELEASE_REASON$/i) {
+ − 334
push @{$self->{data}->{notesSrc}->{releaseReason}}, $thisLine;
+ − 335
}
+ − 336
elsif ($thisTag =~ m/^NOTESRC_GENERAL_COMMENTS$/i) {
+ − 337
push @{$self->{data}->{notesSrc}->{generalComments}}, $thisLine;
+ − 338
}
+ − 339
elsif ($thisTag =~ m/^NOTESRC_KNOWN_DEVIATIONS$/i) {
+ − 340
push @{$self->{data}->{notesSrc}->{knownDeviations}}, $thisLine;
+ − 341
}
+ − 342
elsif ($thisTag =~ m/^NOTESRC_BUGS_FIXED$/i) {
+ − 343
push @{$self->{data}->{notesSrc}->{bugsFixed}}, $thisLine;
+ − 344
}
+ − 345
elsif ($thisTag =~ m/^NOTESRC_BUGS_REMAINING$/i) {
+ − 346
push @{$self->{data}->{notesSrc}->{bugsRemaining}}, $thisLine;
+ − 347
}
+ − 348
elsif ($thisTag =~ m/^NOTESRC_OTHER_CHANGES$/i) {
+ − 349
push @{$self->{data}->{notesSrc}->{otherChanges}}, $thisLine;
+ − 350
}
+ − 351
else {
+ − 352
die "Error: Unknown tag \"$thisTag\" in $self->{notesSrc}\n";
+ − 353
}
+ − 354
}
+ − 355
+ − 356
sub ValidateSource {
+ − 357
my $self = shift;
+ − 358
+ − 359
if ($self->{verbose} > 1) { print "Validating notes source...\n"; }
+ − 360
+ − 361
unless (exists $self->{data}->{notesSrc}->{releaser}) {
+ − 362
die "Error <NOTESRC_RELEASER> not specified in $self->{notesSrc}\n";
+ − 363
}
+ − 364
unless (exists $self->{data}->{notesSrc}->{releaseReason}) {
+ − 365
die "Error <NOTESRC_RELEASE_REASON> not specified in $self->{notesSrc}\n";
+ − 366
}
+ − 367
unless (exists $self->{data}->{notesSrc}->{generalComments}) {
+ − 368
push @{$self->{data}->{notesSrc}->{generalComments}}, "<unspecified>";
+ − 369
}
+ − 370
unless (exists $self->{data}->{notesSrc}->{knownDeviations}) {
+ − 371
push @{$self->{data}->{notesSrc}->{knownDeviations}}, "<unspecified>";
+ − 372
}
+ − 373
unless (exists $self->{data}->{notesSrc}->{bugsFixed}) {
+ − 374
push @{$self->{data}->{notesSrc}->{bugsFixed}}, "<unspecified>";
+ − 375
}
+ − 376
unless (exists $self->{data}->{notesSrc}->{bugsRemaining}) {
+ − 377
push @{$self->{data}->{notesSrc}->{bugsRemaining}}, "<unspecified>";
+ − 378
}
+ − 379
unless (exists $self->{data}->{notesSrc}->{otherChanges}) {
+ − 380
push @{$self->{data}->{notesSrc}->{otherChanges}}, "<unspecified>";
+ − 381
}
+ − 382
}
+ − 383
+ − 384
sub DeleteNotesSource {
+ − 385
my $self = shift;
+ − 386
delete $self->{data}->{notesSrc}->{releaser};
+ − 387
delete $self->{data}->{notesSrc}->{releaseReason};
+ − 388
delete $self->{data}->{notesSrc}->{generalComments};
+ − 389
delete $self->{data}->{notesSrc}->{knownDeviations};
+ − 390
delete $self->{data}->{notesSrc}->{bugsFixed};
+ − 391
delete $self->{data}->{notesSrc}->{bugsRemaining};
+ − 392
delete $self->{data}->{notesSrc}->{otherChanges};
+ − 393
}
+ − 394
+ − 395
sub WorkOutFirstCompatibleVersion {
+ − 396
my $self = shift;
+ − 397
+ − 398
my $version = "2.00";
+ − 399
$version = "2.50" if ($self->{iniData}->CategoriseBinaries());
+ − 400
$version = "2.59" if ($self->{iniData}->CategoriseExports());
+ − 401
$version = "2.80.1000" if grep /[^A-GX]/, @{$self->{mrpData}->SourceCategories()};
+ − 402
# Add to this when extra features are added which break
+ − 403
# backward compatibility of release formats.
+ − 404
$self->{data}->{firstCompatibleVersion} = $version;
+ − 405
}
+ − 406
+ − 407
sub WarnIfReleaseTooNew {
+ − 408
my $self = shift;
+ − 409
# Called from EnvDb::InstallComponent
+ − 410
my $relversion = $self->FirstCompatibleVersion();
+ − 411
return unless defined $relversion;
+ − 412
my $toolsver = Utils::ToolsVersion;
+ − 413
if (Utils::CompareVers($relversion,$toolsver)>0) {
+ − 414
my $thisComp = $self->{comp};
+ − 415
print "Warning: $thisComp requires Release Tools version $relversion or later. You have $toolsver.\n";
+ − 416
print " It's recommended you stop and upgrade your tools before continuing, as\n";
+ − 417
print " the release probably won't install correctly.\n";
+ − 418
print " Continue? [y/n] ";
+ − 419
my $response = <STDIN>;
+ − 420
chomp $response;
+ − 421
if (lc $response eq 'y') {
+ − 422
return;
+ − 423
}
+ − 424
die "Aborting operation.\n";
+ − 425
}
+ − 426
}
+ − 427
+ − 428
1;
+ − 429
+ − 430
=head1 NAME
+ − 431
+ − 432
RelData.pm - Provides an interface to data associated with a release.
+ − 433
+ − 434
=head1 DESCRIPTION
+ − 435
+ − 436
Along with the source and binaries of a component release, the following information is also stored:
+ − 437
+ − 438
=over 4
+ − 439
+ − 440
=item *
+ − 441
+ − 442
The name of the F<mrp> file used to create the release.
+ − 443
+ − 444
=item *
+ − 445
+ − 446
The release's internal version.
+ − 447
+ − 448
=item *
+ − 449
+ − 450
The name and version of every component in the environment used to create the release.
+ − 451
+ − 452
=item *
+ − 453
+ − 454
The time and date the release was made.
+ − 455
+ − 456
=item *
+ − 457
+ − 458
The release notes source, which can subsequently be used to compile the release notes.
+ − 459
+ − 460
=back
+ − 461
+ − 462
All this information is stored in a single file named F<reldata> within the release directory using the module Data::Dumper.
+ − 463
+ − 464
=head1 INTERFACE
+ − 465
+ − 466
=head2 New
+ − 467
+ − 468
Creates a new C<RelData> object and corresponding data file. Expects to be passed an C<IniData> reference, a component name, a version, an internal version, an F<mrp> file name, release notes source file name, a reference to a list of components in the release environment and a verbosity level. This information is assembled into an in-memory data structure, and then written into F<reldata> in the component's release directory. You may optionally pass a "project" name to this function, to specify where the F<reldata> should be written.
+ − 469
+ − 470
=head2 Open
+ − 471
+ − 472
Creates a C<RelData> object from an already existing data file. Expects to be passed an C<IniData> reference, a component name, a version, and a verbosity level.
+ − 473
+ − 474
=head2 OpenExternal
+ − 475
+ − 476
As C<New> except expects to be explicitly passed an archive path file name, rather than an C<IniData> object. Effectively creates a C<RelData> object from an external archive.
+ − 477
+ − 478
=head2 OpenSet
+ − 479
+ − 480
Expects to be passed an C<IniData> reference, a component name, and a verbosity level. Opens C<RelData> objects for all of the releases of the specified component made to date and returns a reference to an array of references to them in descending date order.
+ − 481
+ − 482
Optionally takes a regular expression to limit the versions that are returned.
+ − 483
+ − 484
=head2 Component
+ − 485
+ − 486
Returns the component name.
+ − 487
+ − 488
=head2 Version
+ − 489
+ − 490
Returns the component's version.
+ − 491
+ − 492
=head2 InternalVersion
+ − 493
+ − 494
Returns the component's internal version.
+ − 495
+ − 496
=head2 MrpName
+ − 497
+ − 498
Returns the component's F<mrp> file name.
+ − 499
+ − 500
=head2 Environment
+ − 501
+ − 502
Returns a reference to a hash containing component name / version pairs for the components that were in the release environment.
+ − 503
+ − 504
=head2 NotesSource
+ − 505
+ − 506
Returns a reference to a hash containing all the data needed to compile a set of release notes.
+ − 507
+ − 508
=head1 SourceItems
+ − 509
+ − 510
Returns a reference to a hash of all the "source" lines that were in the MRP file used to create this component. This function will die if no such information was found; this means it will die for releases created with Release Tools versions prior to 2.54.
+ − 511
+ − 512
Note that a hash is used just to ensure uniqueness. Only the keys of the hash have value; the values of the hash currently have no meaning.
+ − 513
+ − 514
=head2 SourceIncluded
+ − 515
+ − 516
Returns a string version of the output of SourceItems.
+ − 517
+ − 518
=head2 UpdateProject
+ − 519
+ − 520
Expects to be passed a project. The project passed is then set as the project for the reldata.pm object, which is used when writing the reldata file.
+ − 521
+ − 522
=head2 UpdateNotes
+ − 523
+ − 524
Expects to be passed the name of a notes source file. Parses this and replaces the persisted version of the release notes.
+ − 525
+ − 526
=head2 UpdateInternalVersion
+ − 527
+ − 528
Expects to be passed an internal version. The internal version is then set as internal version for the reldata.pm object, which is used when writing the reldata file.
+ − 529
+ − 530
=head2 UpdateEnv
+ − 531
+ − 532
Expects to be passed an environment. The environment is then set as environment for the reldata.pm object, which is used when writing the reldata file.
+ − 533
+ − 534
=head2 ReleaseTime
+ − 535
+ − 536
Returns the time (in epoch seconds) at which the release was made.
+ − 537
+ − 538
=head2 MadeWith
+ − 539
+ − 540
Returns a string describing which tool this was made with, including the version number.
+ − 541
+ − 542
=head2 EnvUserName
+ − 543
+ − 544
Returns the full name of the user who made this release, according to environment variables FirstName and LastName.
+ − 545
+ − 546
=head1 KNOWN BUGS
+ − 547
+ − 548
None.
+ − 549
+ − 550
=head1 COPYRIGHT
+ − 551
+ − 552
Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+ − 553
All rights reserved.
+ − 554
This component and the accompanying materials are made available
+ − 555
under the terms of the License "Eclipse Public License v1.0"
+ − 556
which accompanies this distribution, and is available
+ − 557
at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ − 558
+ − 559
Initial Contributors:
+ − 560
Nokia Corporation - initial contribution.
+ − 561
+ − 562
Contributors:
+ − 563
+ − 564
Description:
+ − 565
+ − 566
+ − 567
=cut