--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/makecbr/CConfig.pm Fri Jun 25 18:37:20 2010 +0800
@@ -0,0 +1,541 @@
+#!\bin\perl -w
+# Copyright (c) 2003-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:
+# CConfig
+#
+
+package CConfig;
+
+use strict;
+use IO::File;
+use COutputHandler;
+
+# Added for scanlog compatibility
+use Time::localtime;
+
+# CConfig New(scalar aFilename) : constructor
+sub New($)
+ {
+ my $proto = shift;
+ my ($aFilename) = @_;
+
+ my $class = ref($proto) || $proto;
+
+ my $self = { RELTOOLS_REQUIRED => "",
+ outputHandler => COutputHandler->new()};
+ bless($self, $class);
+ # undef the logfile here so that the folowing warning goes to stdout
+ $self->{iLOGFILE} = undef;
+ # Load in options
+ if (defined($aFilename))
+ {
+ if (!$self->Reload($aFilename))
+ {
+ $self->Warning("Option file could not be loaded.\n");
+ }
+ }
+
+ # Added support for scanlog and Die() control.
+ $self->{iPhaseErrorCount} = 0;
+ $self->{iPhase} = undef;
+
+ return $self;
+ }
+
+# boolean Set(scalar aOptionName, scalar aValue)
+sub Set($$)
+ {
+ my $self = shift;
+ my ($aOptionName, $aValue) = @_;
+
+ if (!defined($aOptionName))
+ {
+ $self->Warning("Cannot set undefined option");
+
+ return 0;
+ }
+
+ if (!defined($aValue))
+ {
+ $self->Warning("Cannot set option '$aOptionName' to undefined value.");
+ return 0;
+ }
+
+ if ((ref($aValue) ne "") && (ref($aValue) ne "ARRAY"))
+ {
+ $self->Warning("Value of '$aOptionName' must be either a string or list.");
+ return 0;
+ }
+
+ $self->{iOptions}->{lc($aOptionName)} = [$aOptionName, $aValue];
+ return 1;
+ }
+
+# scalar Get(scalar aOptionName)
+sub Get($)
+ {
+ my $self = shift;
+ my ($aOptionName) = @_;
+
+ if (defined($self->{iOptions}->{lc($aOptionName)}))
+ {
+ return ($self->{iOptions}->{lc($aOptionName)})->[1];
+ }
+ else
+ {
+ return undef;
+ }
+ }
+
+# boolean Reload(scalar aFilename)
+sub Reload($)
+ {
+ my $self = shift;
+ my ($aFilename) = @_;
+ my $okay = 1;
+
+ $self->{iOptions}={}; # Blank existing options
+
+ if (!open(FILE, $aFilename))
+ {
+ $self->Warning("Option file '$aFilename' could not be opened.");
+ $okay = 0;
+ }
+ else
+ {
+ foreach my $line (<FILE>)
+ {
+ chomp ($line);
+
+ # Split on colon
+ my $parms = $line;
+ $parms =~ s/([^\\]):/$1\x08/g; # Turn unescaped colons into 0x08 chars
+ $parms =~ s/\\:/:/g; # Unescape escaped colons
+ my @parms = split(/\x08/,$parms); # Split on 0x08
+
+ if (scalar(@parms) != 0)
+ {
+ if (scalar(@parms) == 2)
+ {
+ my $key = $parms[0];
+ $key =~ s/^\s+//; # Remove preceding spaces
+ $key =~ s/([^\\])\s$/$1/g; # Remove unescaped trailing spaces
+ $key =~ s/\\(\s)/$1/g; # Unescape space characters
+
+ my $value = $parms[1];
+ if ($value =~ /\s*\[.*\]\s*$/)
+ {
+ # Value is a [list]
+
+ # Remove square brackets
+ $value =~ s/^\s*\[//;
+ $value =~ s/\]\s*$//;
+
+ # Split on comma
+ $value =~ s/([^\\]),/$1\x08/g; # Turn unescaped commas into 0x08 chars
+ $value =~ s/\\,/,/g; # Unescape escaped commas
+ my @values = split(/\x08/,$value); # Split on 0x08
+
+ map(s/^\s+//, @values); # Remove preceding spaces
+ map(s/([^\\])\s$/$1/g, @values); # Remove unescaped trailing spaces
+ map(s/\\(\s)/$1/g, @values); # Unescape space characters
+
+ $value = [@values];
+ }
+ else
+ {
+ # Value is a scalar
+
+ $value =~ s/^\s+//; # Remove preceding spaces
+ $value =~ s/([^\\])\s$/$1/g; # Remove unescaped trailing spaces
+ $value =~ s/\\(\s)/$1/g; # Unescape space characters
+ }
+
+ if (!($self->Set($key, $value)))
+ {
+ $okay = 0;
+ }
+ }
+ else
+ {
+ $self->Warning("In file '$aFilename', ".scalar(@parms)." parameters found on a line.\nOnly two parameters, colon separated, are supported.\nLine: '$line'");
+ $okay = 0;
+ }
+ }
+ }
+ close(FILE);
+ }
+
+ return ($okay);
+ }
+
+# boolean Save(scalar aFilename)
+sub Save($)
+ {
+ my $self = shift;
+ my ($aFilename) = @_;
+ my $okay = 1;
+
+ if (!open(FILE, ">$aFilename"))
+ {
+ $self->Warning("Could not open option file '$aFilename' to save to.");
+ $okay = 0;
+ }
+ else
+ {
+ foreach my $pair (values(%{$self->{iOptions}}))
+ {
+ my $key = $pair->[0];
+ my $value = $pair->[1];
+
+ if (!defined($value))
+ {
+ $self->Error("Cannot write undefined value for key '$key' when saving options.");
+ $okay = 0;
+ }
+ else
+ {
+
+ if (ref($value))
+ {
+ if (ref($value) ne "ARRAY")
+ {
+ $self->Error("Cannot write ".ref($value)." for key '$key' when saving options.");
+ $okay = 0;
+ }
+ else
+ {
+ # It's a list: [value,value,value] and escape any commas or opening spaces
+ my @values = @{$value};
+ map(s/^(\s)/\\$1/,@values);
+ map(s/,/\\,/g,@values);
+ $value = "[".join(",",@values)."]";
+ }
+ }
+ else
+ {
+ # It's a scalar string
+ # Escape opening space
+ $key =~ s/^(\s)/\\$1/;
+ # Escape square brackets;
+ }
+
+ # Escape colons
+ $key =~ s/:/\\:/g;
+ $value =~ s/:/\\:/g;
+
+ print FILE $key.":".$value."\n";
+ }
+ }
+ close (FILE)
+ }
+ return $okay;
+ }
+
+# boolean SetLog(scalar aFilename)
+sub SetLog($)
+ {
+ my $self = shift;
+ my ($aLogFile) = @_;
+
+ if (defined($self->{iLOGFILE}))
+ {
+ $self->{iLOGFILE}->close();
+ # This forces any subsequent error message to go to stdout
+ $self->{iLOGFILE} = undef;
+ }
+
+ if (-e $aLogFile)
+ {
+ if (-e $aLogFile."~")
+ {
+ if (!unlink $aLogFile."~")
+ {
+ $self->Error("Couldn't delete backup log file\n");
+ return 0;
+ }
+ }
+
+ if (system("copy $aLogFile $aLogFile~ > nul 2>&1"))
+ {
+ $self->Error("Couldn't back-up existing log file\n");
+ return 0;
+ }
+ }
+
+ $self->{iLOGFILE}=new IO::File("> $aLogFile");
+
+ if (defined($self->{iLOGFILE}))
+ {
+ return 1;
+ }
+ else
+ {
+ $self->Error("Couldn't open logfile $aLogFile\n");
+ return 0;
+ }
+ }
+
+# void Print(scalar aLogLine)
+sub Print($)
+ {
+ my $self = shift;
+ my ($aLogLine) = @_;
+
+ my $logfile = $self->{iLOGFILE};
+
+ if ($aLogLine !~ /\n$/)
+ {
+ $aLogLine = $aLogLine."\n";
+ }
+
+ $aLogLine = $self->{outputHandler}->CheckOutput($aLogLine);
+
+ if (!defined($logfile))
+ {
+ print $aLogLine;
+ }
+ else
+ {
+ print $logfile $aLogLine;
+ }
+ }
+
+# void Die(scalar aError)
+sub Die($)
+ {
+ my $self = shift;
+ my ($aError) = @_;
+
+ my $logfile = $self->{iLOGFILE};
+
+ if ($aError !~ /\n$/)
+ {
+ $aError = $aError."\n";
+ }
+
+ if (!defined($logfile))
+ {
+ die $aError;
+ }
+ else
+ {
+ print $logfile $aError;
+ die "ERROR: System experienced a fatal error; check the log file.\n";
+ }
+ }
+
+# void Status(scalar aMessage)
+sub Status($)
+ {
+ my $self = shift;
+ my ($aMessage) = @_;
+
+ if (defined($self->{iLOGFILE}))
+ {
+ print STDOUT $aMessage."\n"; # Only display status (to STDOUT) if everything else is going to the logfile
+ }
+ }
+
+# Returns the number of errors encountered in a phase
+sub GetErrorCount()
+ {
+ my $self = shift;
+ return $self->{iPhaseErrorCount};
+ }
+
+###########################################
+# Utility functions
+###########################################
+
+# boolean CheckRelTools()
+
+sub CheckRelTools()
+ {
+ # Search for reldata API
+ my $found = 0;
+ foreach my $path (split(/;/,$ENV{PATH}))
+ {
+ if (-e $path."\\reldata\.pm")
+ {
+ $found = 1;
+ last;
+ }
+ }
+
+ return $found
+ }
+
+# void RequireRelTools() - Requires RelData and IniData. Dies if tools can't be located, or die when being required.
+
+sub RequireRelTools()
+ {
+ my $self = shift;
+
+ if ($self->{RELTOOLS_REQUIRED} ne "required")
+ {
+ # Locate reldata API
+ my $found = 0;
+ foreach my $path (split(/;/,$ENV{PATH}))
+ {
+ if (-e $path."\\reldata\.pm")
+ {
+ push @INC, $path;
+ $found = 1;
+ last;
+ }
+ }
+
+ if (!$found)
+ {
+ $self->Error("Couldn't find release tools in path");
+ }
+
+ # Require core modules
+ require RelData;
+ require IniData;
+ $self->{RELTOOLS_REQUIRED}="required";
+ }
+ }
+
+###########################################
+# Handling Commands, Phases and components.
+###########################################
+
+# void Command(scalar aMessage)
+# Prints out a command in scanlog format to the log file or stdout
+sub Command($)
+ {
+ my $self = shift;
+ my ($aCommand) = @_;
+ my $message = "===-------------------------------------------------\n=== Stage=$self->{stageNumber}.$aCommand\n===-------------------------------------------------\n"; my $logfile = $self->{iLOGFILE};
+ $self->Print($message);
+ }
+
+# void PhaseStart(scalar aPhaseName)
+# If a current phase is active then this is closed, if when doing so a
+# non-zero error count is returned by PhaseEnd() then Die is called. This
+# is regarded as a logic error as the stage runner should normally call PhaseEnd()
+# itself and decide what to do about any errors that occured in that phase.
+sub PhaseStart($)
+ {
+ my $self = shift;
+ my $phase = shift;
+ if (defined $self->{iPhase})
+ {
+ my $numErrs = $self->PhaseEnd();
+ # If there are errors returned by PhaseEnd then Die()
+ if ($numErrs != 0)
+ {
+ $self->Die("Fatal logic error detected, CConfig::PhaseStart() called without PhaseEnd() when phase has $numErrs errors.\n");
+ }
+ }
+
+ $self->{stageNumber}++; # For scanlog compatibility
+
+
+ $self->Command($phase);
+ $self->{iPhase} = $phase;
+
+ my $localTime = ctime();
+ my $message = "=== Stage=$self->{stageNumber}.$self->{iPhase} started $localTime\n";
+ $message .= "=== Stage=$self->{stageNumber}.$self->{iPhase} == $self->{iPhase}\n"; # For Scanlog compatibility
+ $message .= "+++ HiRes Start " . time() . "\n"; # For Scanlog compatibility
+ $message .= "-- $self->{iPhase}: Miscellaneous\n"; # For Scanlog compatibility
+ $self->Print($message);
+ $self->{iPhaseErrorCount} = 0;
+ }
+
+# scalar PhaseEnd(void)
+# Closes the current phase and returns a count of the number of errors encountered.
+# This will die if a PhaseStart() has not been declared.
+sub PhaseEnd()
+ {
+ my $self = shift;
+ my $localTime = ctime();
+ if (defined $self->{iPhase})
+ {
+ my $message = "+++ HiRes End " . time() . "\n"; # For Scanlog compatibility
+ $message .= "=== Stage=$self->{stageNumber}.$self->{iPhase} finished $localTime\n";
+ $self->Print($message);
+ }
+ else
+ {
+ $self->Die("Error: CConfig::PhaseEnd() called without corresponding PhaseStart()\n");
+ }
+ $self->{iPhase} = undef;
+ return $self->{iPhaseErrorCount};
+ }
+
+# void Component(scalar aComponent)
+# Prints out a component for this phase in scanlog format to the log file or stdout
+sub Component($)
+ {
+ my $self = shift;
+ my ($aComponent) = @_;
+ if (!defined $self->{iPhase})
+ {
+ $self->Die("Logger: Undefined phase for component \"$aComponent\"\n");
+ }
+ else
+ {
+ my $message = "+++ HiRes End " . time() . "\n-- $aComponent\n+++ HiRes Start " . time();
+ $self->Print($message);
+ }
+ }
+
+###############################
+# Handling errors and warnings.
+###############################
+
+# void Error(scalar aMessage)
+# Writes an error message to the logfile (if defined) or stdout
+# and will increment the error count for this phase.
+sub Error($)
+ {
+ my $self = shift;
+ my ($aMessage) = @_;
+ $self->{iPhaseErrorCount} += 1;
+ my $message = "ERROR: $aMessage";
+ $self->Print($message);
+ }
+
+# void Warning(scalar aMessage)
+# Writes an warning message to the logfile (if defined) or stdout
+sub Warning($)
+ {
+ my $self = shift;
+ my ($aMessage) = @_;
+ my $message = "WARNING: $aMessage";
+ $self->Print($message);
+ }
+
+sub DESTROY
+ {
+ my $self = shift;
+
+ # Avoid "unreferenced scalar" error in Perl 5.6 by not calling
+ # PhaseEnd method for each object in multi-threaded CDelta.pm
+
+ if ((defined $self->{iPhase}) && ($self->{iPhase} !~ /CDelta/)) {
+ $self->PhaseEnd;
+ }
+
+ if (defined($self->{iLOGFILE}))
+ {
+ $self->{iLOGFILE}->close();
+ $self->{iLOGFILE} = undef;
+ }
+ }
+1;