--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/cbrtools/perl/RelData.pm Fri Jun 25 18:37:20 2010 +0800
@@ -0,0 +1,567 @@
+# Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+#
+
+package RelData;
+
+use strict;
+use Data::Dumper;
+use MrpData;
+use PathData;
+
+#
+# Data version history.
+#
+# 1 - Original release.
+# 2 - Added 'relToolsVer' tag.
+#
+
+
+#
+# Public.
+#
+
+sub New {
+ my $pkg = shift;
+ my $self = {};
+ bless $self, $pkg;
+ $self->{iniData} = shift;
+ $self->{mrpData} = shift;
+ $self->{notesSrc} = shift;
+ $self->{data}->{env} = shift;
+ $self->{data}->{toolName} = shift;
+ $self->{verbose} = shift;
+ $self->{dontPersist} = shift;
+ $self->{project} = shift;
+
+ $self->{comp} = $self->{mrpData}->Component();
+ $self->{ver} = $self->{mrpData}->ExternalVersion();
+ $self->{data}->{dataFormatVer} = 2;
+ $self->{data}->{intVer} = $self->{mrpData}->InternalVersion();
+ $self->{data}->{mrpName} = $self->{mrpData}->MrpName();
+ $self->{data}->{relToolsVer} = Utils::ToolsVersion();
+ $self->{data}->{notesSrc}->{srcFilterErrors} = $self->{mrpData}->SourceFilterErrors();
+ $self->{data}->{notesSrc}->{date} = localtime;
+
+ foreach my $srcitem (keys %{$self->{mrpData}->SourceItems()}) {
+ if($self->{iniData}->HasMappings()){
+ $srcitem = $self->{iniData}->PerformReverseMapOnFileName($srcitem);
+ $srcitem = Utils::RemoveSourceRoot($srcitem);
+ }
+
+ $self->{data}->{srcitems}->{$srcitem} = 1;
+ }
+
+ unless(defined $self->{data}->{srcitems}){
+ $self->{data}->{srcitems} = $self->{mrpData}->SourceItems();
+ }
+
+ $self->{data}->{envUserName} = ($ENV{FirstName} || '') . " " . ($ENV{LastName} || '');
+ $self->ParseNotesSource();
+ $self->WorkOutFirstCompatibleVersion();
+ unless (defined $self->{dontPersist}) {
+ $self->WriteToFile();
+ }
+ return $self;
+}
+
+sub Open {
+ my $pkg = shift;
+ my $self = {};
+ bless $self, $pkg;
+ $self->{iniData} = shift;
+ $self->{comp} = shift;
+ $self->{ver} = shift;
+ $self->{verbose} = shift;
+ $self->ReadFromFile();
+ return $self;
+}
+
+sub OpenExternal {
+ my $pkg = shift;
+ my $externalArchive = shift;
+ my $comp = shift;
+ my $ver = shift;
+ my $self = {};
+ $self->{comp} = $comp;
+ $self->{ver} = $ver;
+ my $externalFile = File::Spec->catdir($externalArchive, $comp, $ver);
+ bless $self, $pkg;
+ $self->ReadFromSpecificFile($externalFile);
+ return $self;
+}
+
+
+sub OpenSet {
+ my $pkg = shift;
+ my $iniData = shift;
+ my $comp = shift;
+ my $verbose = shift;
+ my $versionfilter = shift;
+
+ my @relDataObjects;
+ foreach my $ver (@{$iniData->PathData->ListVersions($comp, 0, $versionfilter, $iniData->LatestVerFilter)}) {
+ my $thisRelData = {};
+ bless $thisRelData, $pkg;
+ eval {
+ # ReadFromFile may die, if the file is corrupt.
+ # In which case we do not add it to the set.
+ $thisRelData->{iniData} = $iniData;
+ $thisRelData->{comp} = $comp;
+ $thisRelData->{ver} = $ver;
+ $thisRelData->{verbose} = $verbose;
+ $thisRelData->ReadFromFile();
+ push (@relDataObjects, $thisRelData);
+ };
+ print "Warning: could not examine \"$comp\" \"$ver\" because $@" if ($@);
+ }
+
+ @relDataObjects = sort { $b->ReleaseTime() <=> $a->ReleaseTime() } @relDataObjects;
+
+ return \@relDataObjects;;
+}
+
+sub Component {
+ my $self = shift;
+ die unless exists $self->{comp};
+ return $self->{comp};
+}
+
+sub MadeWith {
+ my $self = shift;
+ my $ver = $self->{data}->{relToolsVer} || "(unknown version)";
+ my $tool = $self->{data}->{toolName} || "(unknown tool)";
+ return "$tool $ver";
+}
+
+sub MadeWithVersion {
+ my $self = shift;
+ return "".$self->{data}->{relToolsVer};
+}
+
+sub SourceIncluded {
+ my $self = shift;
+ my $items;
+ eval {
+ $items = $self->SourceItems();
+ };
+ return "(unknown)" if $@;
+ return join (", ", keys %$items);
+}
+
+sub Version {
+ my $self = shift;
+ die unless exists $self->{ver};
+ return $self->{ver};
+}
+
+sub InternalVersion {
+ my $self = shift;
+ die unless exists $self->{data};
+ return $self->{data}->{intVer};
+}
+
+sub MrpName {
+ my $self = shift;
+ die unless exists $self->{data};
+ return $self->{data}->{mrpName};
+}
+
+sub FirstCompatibleVersion {
+ my $self = shift;
+ die unless exists $self->{data};
+ return $self->{data}->{firstCompatibleVersion};
+}
+
+sub Environment {
+ my $self = shift;
+ die unless exists $self->{data};
+ return $self->{data}->{env};
+}
+
+sub NotesSource {
+ my $self = shift;
+ die unless exists $self->{data};
+ return $self->{data}->{notesSrc};
+}
+
+sub UpdateProject {
+ my $self = shift;
+ $self->{project} = shift;
+ $self->WriteToFile();
+}
+
+sub UpdateNotes {
+ my $self = shift;
+ $self->{notesSrc} = shift;
+ $self->DeleteNotesSource();
+ $self->ParseNotesSource();
+ $self->WriteToFile();
+}
+
+sub UpdateInternalVersion {
+ my $self = shift;
+ $self->{data}->{intVer} = shift;
+ $self->WriteToFile();
+}
+
+sub UpdateEnv {
+ my $self = shift;
+ $self->{data}->{env} = shift;
+ $self->WriteToFile();
+}
+
+sub ReleaseTime {
+ my $self = shift;
+ unless (exists $self->{releaseTime}) {
+ $self->{releaseTime} = Utils::TextTimeToEpochSeconds($self->{data}->{notesSrc}->{date});
+ }
+ return $self->{releaseTime};
+}
+
+sub SourceItems {
+ my $self = shift;
+ unless (defined $self->{data}->{srcitems}) {
+ my $createdver = $self->{data}->{relToolsVer} || 0;
+ if (Utils::CompareVers($createdver,2.54)<0) {
+ 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";
+ }
+ die "Could not return the list of \"source\" statements used in the MRP file."
+ }
+ return $self->{data}->{srcitems};
+}
+
+sub EnvUserName {
+ my $self = shift;
+ return $self->{data}->{envUserName};
+ }
+
+#
+# Private.
+#
+
+sub WriteToFile {
+ my $self = shift;
+ my $relDir = $self->{iniData}->PathData->LocalArchivePathForExistingOrNewComponent($self->{comp}, $self->{ver}, $self->{project});
+
+ my $file = "$relDir\\reldata";
+
+ if (-e $file) {
+ Utils::SetFileWritable($file);
+ }
+ open (OUT, ">$file") or die "Error: Couldn't open \"$file\" for writing: $!\n";
+ print OUT Data::Dumper->Dump([$self->{data}], ['self->{data}']);
+ close (OUT);
+ Utils::SetFileReadOnly($file);
+}
+
+sub ReadFromFile {
+ my $self = shift;
+ my $pathData = shift || $self->{iniData}->PathData;
+
+ my $comp = $self->{comp};
+ my $ver = $self->{ver};
+
+ my $relDir = $pathData->LocalArchivePathForExistingComponent($comp, $ver);
+ die "Error: \"$comp $ver\" does not exist\n" unless $relDir;
+ die "Error: \"$comp $ver\" was not a valid release (can't find \"$relDir\\reldata\")\n" unless -e "$relDir\\reldata";
+ $self->{project} = $pathData->ComponentProject($comp, $ver);
+ $self->ReadFromSpecificFile($relDir);
+}
+
+sub ReadFromSpecificFile {
+ my $self = shift;
+ my $relDir = shift;
+ unless (-e $relDir) {
+ die "Error: $self->{comp} $self->{ver} does not exist\n";
+ }
+ my $file = "$relDir\\reldata";
+ open (IN, $file) or die "Error: Couldn't open \"$file\" for reading: $!\n";
+ local $/ = undef;
+ my $data = <IN>;
+ die "Error: Reldata in \"$relDir\" is blank" unless $data =~ (m/\S/);
+ eval ($data) or die "Error: Couldn't parse reldata in \"$relDir\"\n";
+ close (IN);
+}
+
+sub ParseNotesSource {
+ my $self = shift;
+
+ if ($self->{verbose} > 1) { print "Parsing notes source...\n"; }
+
+ open(SRC,"$self->{notesSrc}") or die "Unable to open $self->{notesSrc} for reading: $!\n";
+
+ my $thisTag;
+ while (<SRC>) {
+ if (m/^NOTESRC/i) {
+ chomp;
+ $thisTag = $_;
+ }
+ elsif (m/^\s*$/) {
+ next;
+ }
+ elsif (defined $thisTag) {
+ $self->AddLine($thisTag, $_);
+ }
+ }
+ close SRC;
+
+ $self->ValidateSource();
+}
+
+sub AddLine {
+ my $self = shift;
+ my $thisTag = shift;
+ my $thisLine = shift;
+ chomp $thisLine;
+
+ if ($thisTag =~ m/^NOTESRC_RELEASER$/i) {
+ $self->{data}->{notesSrc}->{releaser} = $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_RELEASE_REASON$/i) {
+ push @{$self->{data}->{notesSrc}->{releaseReason}}, $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_GENERAL_COMMENTS$/i) {
+ push @{$self->{data}->{notesSrc}->{generalComments}}, $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_KNOWN_DEVIATIONS$/i) {
+ push @{$self->{data}->{notesSrc}->{knownDeviations}}, $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_BUGS_FIXED$/i) {
+ push @{$self->{data}->{notesSrc}->{bugsFixed}}, $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_BUGS_REMAINING$/i) {
+ push @{$self->{data}->{notesSrc}->{bugsRemaining}}, $thisLine;
+ }
+ elsif ($thisTag =~ m/^NOTESRC_OTHER_CHANGES$/i) {
+ push @{$self->{data}->{notesSrc}->{otherChanges}}, $thisLine;
+ }
+ else {
+ die "Error: Unknown tag \"$thisTag\" in $self->{notesSrc}\n";
+ }
+}
+
+sub ValidateSource {
+ my $self = shift;
+
+ if ($self->{verbose} > 1) { print "Validating notes source...\n"; }
+
+ unless (exists $self->{data}->{notesSrc}->{releaser}) {
+ die "Error <NOTESRC_RELEASER> not specified in $self->{notesSrc}\n";
+ }
+ unless (exists $self->{data}->{notesSrc}->{releaseReason}) {
+ die "Error <NOTESRC_RELEASE_REASON> not specified in $self->{notesSrc}\n";
+ }
+ unless (exists $self->{data}->{notesSrc}->{generalComments}) {
+ push @{$self->{data}->{notesSrc}->{generalComments}}, "<unspecified>";
+ }
+ unless (exists $self->{data}->{notesSrc}->{knownDeviations}) {
+ push @{$self->{data}->{notesSrc}->{knownDeviations}}, "<unspecified>";
+ }
+ unless (exists $self->{data}->{notesSrc}->{bugsFixed}) {
+ push @{$self->{data}->{notesSrc}->{bugsFixed}}, "<unspecified>";
+ }
+ unless (exists $self->{data}->{notesSrc}->{bugsRemaining}) {
+ push @{$self->{data}->{notesSrc}->{bugsRemaining}}, "<unspecified>";
+ }
+ unless (exists $self->{data}->{notesSrc}->{otherChanges}) {
+ push @{$self->{data}->{notesSrc}->{otherChanges}}, "<unspecified>";
+ }
+}
+
+sub DeleteNotesSource {
+ my $self = shift;
+ delete $self->{data}->{notesSrc}->{releaser};
+ delete $self->{data}->{notesSrc}->{releaseReason};
+ delete $self->{data}->{notesSrc}->{generalComments};
+ delete $self->{data}->{notesSrc}->{knownDeviations};
+ delete $self->{data}->{notesSrc}->{bugsFixed};
+ delete $self->{data}->{notesSrc}->{bugsRemaining};
+ delete $self->{data}->{notesSrc}->{otherChanges};
+}
+
+sub WorkOutFirstCompatibleVersion {
+ my $self = shift;
+
+ my $version = "2.00";
+ $version = "2.50" if ($self->{iniData}->CategoriseBinaries());
+ $version = "2.59" if ($self->{iniData}->CategoriseExports());
+ $version = "2.80.1000" if grep /[^A-GX]/, @{$self->{mrpData}->SourceCategories()};
+ # Add to this when extra features are added which break
+ # backward compatibility of release formats.
+ $self->{data}->{firstCompatibleVersion} = $version;
+}
+
+sub WarnIfReleaseTooNew {
+ my $self = shift;
+ # Called from EnvDb::InstallComponent
+ my $relversion = $self->FirstCompatibleVersion();
+ return unless defined $relversion;
+ my $toolsver = Utils::ToolsVersion;
+ if (Utils::CompareVers($relversion,$toolsver)>0) {
+ my $thisComp = $self->{comp};
+ print "Warning: $thisComp requires Release Tools version $relversion or later. You have $toolsver.\n";
+ print " It's recommended you stop and upgrade your tools before continuing, as\n";
+ print " the release probably won't install correctly.\n";
+ print " Continue? [y/n] ";
+ my $response = <STDIN>;
+ chomp $response;
+ if (lc $response eq 'y') {
+ return;
+ }
+ die "Aborting operation.\n";
+ }
+}
+
+1;
+
+=head1 NAME
+
+RelData.pm - Provides an interface to data associated with a release.
+
+=head1 DESCRIPTION
+
+Along with the source and binaries of a component release, the following information is also stored:
+
+=over 4
+
+=item *
+
+The name of the F<mrp> file used to create the release.
+
+=item *
+
+The release's internal version.
+
+=item *
+
+The name and version of every component in the environment used to create the release.
+
+=item *
+
+The time and date the release was made.
+
+=item *
+
+The release notes source, which can subsequently be used to compile the release notes.
+
+=back
+
+All this information is stored in a single file named F<reldata> within the release directory using the module Data::Dumper.
+
+=head1 INTERFACE
+
+=head2 New
+
+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.
+
+=head2 Open
+
+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.
+
+=head2 OpenExternal
+
+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.
+
+=head2 OpenSet
+
+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.
+
+Optionally takes a regular expression to limit the versions that are returned.
+
+=head2 Component
+
+Returns the component name.
+
+=head2 Version
+
+Returns the component's version.
+
+=head2 InternalVersion
+
+Returns the component's internal version.
+
+=head2 MrpName
+
+Returns the component's F<mrp> file name.
+
+=head2 Environment
+
+Returns a reference to a hash containing component name / version pairs for the components that were in the release environment.
+
+=head2 NotesSource
+
+Returns a reference to a hash containing all the data needed to compile a set of release notes.
+
+=head1 SourceItems
+
+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.
+
+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.
+
+=head2 SourceIncluded
+
+Returns a string version of the output of SourceItems.
+
+=head2 UpdateProject
+
+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.
+
+=head2 UpdateNotes
+
+Expects to be passed the name of a notes source file. Parses this and replaces the persisted version of the release notes.
+
+=head2 UpdateInternalVersion
+
+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.
+
+=head2 UpdateEnv
+
+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.
+
+=head2 ReleaseTime
+
+Returns the time (in epoch seconds) at which the release was made.
+
+=head2 MadeWith
+
+Returns a string describing which tool this was made with, including the version number.
+
+=head2 EnvUserName
+
+Returns the full name of the user who made this release, according to environment variables FirstName and LastName.
+
+=head1 KNOWN BUGS
+
+None.
+
+=head1 COPYRIGHT
+
+ Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+ All rights reserved.
+ This component and the accompanying materials are made available
+ under the terms of the License "Eclipse Public License v1.0"
+ which accompanies this distribution, and is available
+ at the URL "http://www.eclipse.org/legal/epl-v10.html".
+
+ Initial Contributors:
+ Nokia Corporation - initial contribution.
+
+ Contributors:
+
+ Description:
+
+
+=cut