diff -r 000000000000 -r 83f4b4db085c bldsystemtools/commonbldutils/GenerateChangesReport.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bldsystemtools/commonbldutils/GenerateChangesReport.pl Tue Feb 02 01:39:43 2010 +0200 @@ -0,0 +1,820 @@ +#! perl + +use strict; +use Getopt::Long; + +# TODO: +# Improve performance by not accessing P4 for every source line in every MRP file +# Handle situation where clean-src dir is missing by accessing MRP file from Perforce +# Use autobuild database to get perforce information directly? +# What should we do about change C reverts change B which reverted change A? +# => Hope C has a good description, as this implementation will discard both A and B descriptions. + +#note: currently relies on existence of perforce report of previous build + +# Parameters passed to script +my $Product = shift; # e.g. 9.3 +my $Platform = shift; # e.g. cedar +my $CurentBuild = shift; # e.g. 03935 +my $CurrentCL = shift; # e.g. 775517 +shift; # e.g. 03935_Symbian_OS_v9.3 +my $CurrCodeLine = shift; # e.g. //epoc/master/ +my $PreviousBuild = shift; # the build number of the previous release (eg 03925) +my $LogDirs = shift; # e.g. \\builds01\devbuilds +my $CleanSourceDir = shift; # e.g. M:\clean-src (synched file from perforce) + +my $debug = 0; # set to 1 to print debug logfile and progress information + +GetOptions( + 'v' => \$debug); + +# Derived parameters +my $CurrBldName = "$CurentBuild\_Symbian_OS_v$Product"; # e.g. 03935_Symbian_OS_v9.3 + + +# Global variables + +my $PreviousLogDir; # location of the logs associated with the previous release build +my $PrevFileAndPath; # name of the previous release build's perforce report and its location +my $PrevBldName; # e.g. 03925_Symbian_OS_v9.3 + +my $MainLineCL = 0; # the CL of the build from which the current build + # was branched if it is on a delivery branch +my $MainLineLine; # the codeline of the build from which the current + # build was branched if on a delivery branch + +my %allDefects; # hash containing all of the defect fixes +my %allBreaks; # hash contains all of the delivered breaks +my %changeToComponents; # hash containing lists of components affected by a given change +my %reverted; # hash of reverted changelists + +# Tidy up directories to ensure they are in a standard format +$CurrCodeLine =~ s/[^\/]$/$&\//;# ensure a trailing fwdslash for codeline +$LogDirs =~ s/\\$//; # ensure no trailing back slash for codeline +$CleanSourceDir =~ s/\\$//; # ensure no trailing back slash for codeline + +# add information to the debug log if the debug flag is set +if ($debug) +{ + # Open an error log + open ERRORLOG, "> Errorlog.txt"; + print ERRORLOG <<"END"; +Inputs: + +Product: $Product +Platform: $Platform +Current build: $CurentBuild +Current build CL: $CurrentCL +Current Build Name: $CurrBldName +Previous Build: $PreviousBuild +Log Directory: $LogDirs +Clean Source Dir: $CleanSourceDir + +Errors: + +END +} + +# If the previous release was from a delivery branch, then use the build from +# from which the delivery branch was created by removing the letters (changes +# on the files on the branch will also have been made on the main codeline) +$PreviousBuild =~ s/[a-z]+(\.\d+)?//; + +# If the current build is on a delivery branch, then store the information about +# the build from which it was branched as it will be necessary to get the descriptions +# from perforce for versions on the branch and versions on the main codeline up to +# where the branch was created separately + +if ($CurentBuild =~ /[a-z]+/) +{ + my $MainLineBuild = $CurentBuild; + $MainLineBuild =~ s/[a-z]+(\.\d+)?//; + # There is insufficient information here anyway, e.g. if M09999 failed and we did + # M09999.01 as the original candidate, then there is no way of telling the tool + + my $MainLineBldName = "$MainLineBuild\_Symbian_OS_v$Product"; + my $MainLinePerforce = "$LogDirs\\$MainLineBldName\\logs\\$MainLineBuild\_$Product" . "PC_Perforce_report.html"; + ($MainLineCL, $MainLineLine) = GetPrevCodelineandCL($MainLinePerforce, $Platform); +} + +# Construct the previous build name +$PrevBldName = "$PreviousBuild\_Symbian_OS_v$Product"; + +# Construct the name of the peforce report file for the previous external release +# to look similar to this: 03925_9.3PC_Perforce_report.html +my $PerforceReport = $PreviousBuild."_".$Product."PC_Perforce_report.html"; + +# Look for $PerforceReport in the build logs directory and the log archive directory +$PreviousLogDir = "$LogDirs\\$PrevBldName\\logs\\"; + +$PrevFileAndPath = $PreviousLogDir.$PerforceReport; + +if (! -d $CleanSourceDir) +{ + # if the report is found in neither directory then die + if ($debug==1) + { + print ERRORLOG "Clean-src directory does not exist! ($CleanSourceDir)\n"; + } + die "ERROR: Clean-src directory does not exist"; +} + +if (! -e $PrevFileAndPath) +{ + $PreviousLogDir = "$LogDirs\\logs\\$PrevBldName\\"; + $PrevFileAndPath = $PreviousLogDir.$PerforceReport; +} +if (! -e $PrevFileAndPath) +{ + # if the report is found in neither directory then die + if ($debug==1) + { + print ERRORLOG "Could not find Perforce report of previous external release! ($PrevFileAndPath)\n"; + } + die "ERROR: Cannot find previous Perforce report"; +} + +# Parse the Perforce report to extract the previous build's change list and codeline path +my ($PreviousCL, $PrevCodeLine) = GetPrevCodelineandCL($PrevFileAndPath, $Platform); + +# Create the path of the current build's log directory +my $CurrentLogDir = "$LogDirs\\$CurrBldName\\logs\\"; + +# Obtain the component lists (arrays are passed back by reference, each element containing a component +# name separated by one or more spaces from its associated mrp file as it appears in the component files) +my ($GTprevCompList, $GTlatestCompList, + $TVprevCompList, $TVlatestCompList) = GetGTandTVcomponentLists($CurrentLogDir, $PreviousLogDir); + +# Consolidate the lists of components in to two hashes: one for the current build and one for the previous +# release build. These contain an index to distinguish between GT and TechView components and another index +# with the names of the components. The mrp files are the elements being indexed. +my ($PrevMRP, $CurrMRP) = CreateMRPLists($GTprevCompList, + $GTlatestCompList, + $TVprevCompList, + $TVlatestCompList); + +# For each component, extract its source directories from its MRP file and add the information to a list +my (@ComponentAndSource) = ProcessLists($Product, + $PrevCodeLine, + $Platform , + $PrevMRP, + $CurrMRP, + $PreviousCL, + $CleanSourceDir); + +# Put together the HTML file using the components list with their associated source files +(my $ChangesFileHTML) = CreateReleaseNotes($Product, + $CurrCodeLine, + $MainLineLine, + $PreviousCL, + $CurrentCL, + $MainLineCL, + @ComponentAndSource); + +if ($debug) +{ + close ERRORLOG; +} + +print "FINISHED!! - $ChangesFileHTML\n"; + +exit; + +# +# +# Gets component lists from the builds' log directories. Reads the contents +# of the files in to arrays and returns references to these arrays. +# +# Inputs: Current and previous build's logfile locations +# Outputs: Arrays containing contents of previous and current GTcomponents.txt +# and TVcomponents.txt files (list of components with their associated +# mrp files). An example array elment might contain: +# "ChatScripts \sf\os\unref\orphan\comtt\chatscripts\group\testtools_chatscripts.mrp" +# +sub GetGTandTVcomponentLists +{ + my ($CurrLogPath, $PrevLogPath) = @_; + + # Data to return: array of refs to arrays of contents of files + my @return; + + # Files to read from + my @FileNames = ( + $PrevLogPath."GTcomponents.txt", + $CurrLogPath."GTcomponents.txt", + $PrevLogPath."TechViewComponents.txt", + $CurrLogPath."TechViewComponents.txt", + ); + + foreach my $FileName (@FileNames) + { + if (!open(DAT, $FileName)) + { + if ($debug) + { + print ERRORLOG "Could not open $FileName!\n"; + } + die "ERROR: Could not open $FileName: $!"; + } + push @return, []; + close DAT; + } + + return @return; +} + +# +# +# Creates two list of components and their associated mrp files - one for the previous +# build and one for the current build +# +# Inputs: the contents of the GT and TV components files +# Outputs: Two lists of components and their mrp files, one from the previous build +# and one from the current build +# +# +sub CreateMRPLists +{ + # references to the contents of the components files + my $GTprevFile = shift; + my $GTlatestFile = shift; + my $TVprevFile = shift; + my $TVlatestFile = shift; + + my %PreviousMrps; #Hash of all Components and their MRP file locations for the previous build + my %CurrentMrps; #Hash of all Components and their MRP file locations for the current build + + # Add mrp files to a hash indexed under GT or TV and by component names + foreach my $case ( + [\%PreviousMrps, 'GT', $GTprevFile], + [\%CurrentMrps, 'GT', $GTlatestFile], + [\%PreviousMrps, 'TV', $TVprevFile], + [\%CurrentMrps, 'TV', $TVlatestFile], + ) + { + foreach my $element (@{$case->[2]}) + { + if ( $element =~ /(.*)\s+(\\sf\\.*)$/ ) + { + ${$case->[0]}{$case->[1]}{uc($1)} = lc($2); + } + } + } + + return \%PreviousMrps, \%CurrentMrps; +} + + +# +# +# Use the contents of the MRP files to create a single list containing the GT and TechView +# components paired with associated source files. +# +# Inputs: Product, Codeline, Previous Codeline, Platform, Both lists of mrps, +# Previous Changelist number, Build machine's clean source directory which +# contains copies of the current build's mrp files. +# Outputs: Array containing all components and their source locations +# +# +sub ProcessLists +{ + my $Product = shift; + my $PrevCodeLine = shift; + my $Platform = shift; + my $PreviousMrps = shift; #Hash of MRPs at the Previous changelist number + my $CurrentMrps = shift; #Hash of MRPs at the Current changelist number + my $PrevCL = shift; + my $CleanSourceDir = shift; + + my @PrevGTMrpComponents; #Array of GT Components at Previous changelist number + my @CurrGTMrpComponents; #Array of GT Components at Current changelist number + my @PrevTVMrpComponents; #Array of TV Components at Previous changelist number + my @CurrTVMrpComponents; #Array of TV Components at Current changelist number + + # Isolate hashes + my $CurrGT = $CurrentMrps->{'GT'}; + my $CurrTV = $CurrentMrps->{'TV'}; + my $PrevGT = $PreviousMrps->{'GT'}; + my $PrevTV = $PreviousMrps->{'TV'}; + + # Append the location of the clean source directory for the current build + # to all the mrp files. If a file appears only in the previous build (i.e. + # a component has been removed) its location in perforce is later substituted + # in place of this path + foreach my $component (sort keys %$CurrGT) + { + $CurrGT->{$component} =~ s|\\sf|$CleanSourceDir|ig; + $CurrGT->{$component} =~ s|\\|\/|g; + push @CurrGTMrpComponents, "$component\t$CurrGT->{$component}"; + } + + foreach my $component (sort keys %$CurrTV) + { + $CurrTV->{$component} =~ s|\\sf|$CleanSourceDir|ig; + $CurrTV->{$component} =~ s|\\|\/|g; + push @CurrTVMrpComponents, "$component\t$CurrTV->{$component}"; + } + + foreach my $component (sort keys %$PrevGT) + { + $PrevGT->{$component} =~ s|\\sf|$CleanSourceDir|ig; + $PrevGT->{$component} =~ s|\\|\/|g; + push @PrevGTMrpComponents, "$component"."\t"."$PrevGT->{$component}"; + } + + foreach my $component (sort keys %$PrevTV) + { + $PrevTV->{$component} =~ s|\\sf|$CleanSourceDir|ig; + $PrevTV->{$component} =~ s|\\|\/|g; + push @PrevTVMrpComponents, "$component"."\t"."$PrevTV->{$component}"; + } + + # add any components that appear only in the previous build's list to the + # current build's list with its location in perforce. + foreach my $PrevGTComp(@PrevGTMrpComponents) + { + my $match = 0; + #Compare component lists to ensure they contain the same components. + foreach my $CurrGTComp(@CurrGTMrpComponents) + { + $match = 1 if($PrevGTComp eq $CurrGTComp); + } + + #If a component is found in the Previous list which isn't in the Current list, + #then insert it into the Current list with the previous build's path + if($match == 0) + { + $PrevGTComp =~ s|\/|\\|g; + $PrevGTComp =~ s|\Q$CleanSourceDir\E\\|$PrevCodeLine|ig; + $PrevGTComp =~ s|\\|\/|g; + push @CurrGTMrpComponents, $PrevGTComp; + } + } + + # add any components that appear only in the previous build's list to the + # current build's list with its location in perforce. + foreach my $PrevTVComp(@PrevTVMrpComponents) + { + my $match = 0; + #Compare component lists to ensure they contain the same components. + foreach my $CurrTVComp(@CurrTVMrpComponents) + { + $match = 1 if($PrevTVComp eq $CurrTVComp); + } + + #If a component is found in the Previous list which isn't in the Current list, + #then insert it into the Current list + if($match == 0) + { + $PrevTVComp =~ s|$CleanSourceDir|$PrevCodeLine|ig; + push @CurrTVMrpComponents, $PrevTVComp; + } + } + + # Combine current GT and TV components, with a boundary marker + my @CurrMrpComponents = (@CurrGTMrpComponents, "**TECHVIEWCOMPONENTS**", @CurrTVMrpComponents); + + # Swap the back slashes for forward slashes + $CleanSourceDir =~ s/\\/\//g; + $PrevCodeLine =~ s/\\/\//g; + + #Use the MRP file for each component to obtain the source directory locations + my @ComponentAndSource; + foreach my $ComponentLine(@CurrMrpComponents) + { + #Array to hold mrp file contents + my @MrpContents; + + # if the file is in the Clean Source Directory then read its contents from there + if($ComponentLine =~ /.*(\Q$CleanSourceDir\E.*)/) + { + my $MrpFile = $1; + $MrpFile =~ s/\.mrp.*$/\.mrp/; #drop any trailing spaces or tabs + if (-e $MrpFile) + { + open(FILE, $MrpFile); + @MrpContents=; + close FILE; + } + } + elsif($ComponentLine =~ /.*(\Q$PrevCodeLine\E.*)/) + { + # If a component has been removed between the previous build and the current one then + # its MRP file will only exist at the PrevCL + @MrpContents = `p4 print -q $1...\@$PrevCL`; # access Perforce via system command + } + elsif($ComponentLine =~ /\*\*TECHVIEWCOMPONENTS\*\*/) + { + push @MrpContents, $ComponentLine; + } + + #Construct an array containing components in uppercase followed by + #all their sourcelines in lowercase + foreach my $line(@MrpContents) + { + if($line =~ /^component\s+(.*)/i) + { + my $ComponentName = uc($1); + push @ComponentAndSource, $ComponentName; + } + elsif($line =~ /^source\s+(.*)/i) + { + my $Source = lc($1); + $Source =~ s/\\/\//g; + $Source =~ s|/sf/||; + $Source =~ s|/product/|$Platform/product|ig; + push @ComponentAndSource, $Source; + } + elsif($line =~ /TECHVIEWCOMPONENTS/) + { + push @ComponentAndSource, $line; + } + } + } + return @ComponentAndSource; +} + +# +# Format the changes associated with a component +# +# Inputs: +# reference to hash of change descriptions by changelist number, +# component name, +# reference to (formatted) list of names of changed components +# reference to list of names of unchanged components +# +# Updates: +# adds component name to changed or unchanged list, as appropriate +# +sub PrintComponentDescriptions(\%$\@\@) +{ + my ($Descriptions,$CompName,$ChangedComponents,$UnchangedComponents) = @_; + + if (scalar keys %{$Descriptions} == 0) + { + # no changes in this component + push @{$UnchangedComponents}, $CompName; + return; + } + push @{$ChangedComponents}, "$CompName"; + + # Format the changes for this component + + my @CompLines = ("

$CompName

"); + foreach my $change (reverse sort keys %{$Descriptions}) + { + # Heading for the change description + my $summary = shift @{$$Descriptions{$change}}; + $summary =~ s/(on .*)\s+by.*//; + $summary = "Change $change $1"; + push @CompLines, "

$summary"; + # Body of the change description + push @CompLines, "

";
+        push @CompLines,
+            grep { $_; }	# ignore blank lines
+            @{$$Descriptions{$change}};
+        push @CompLines, "
"; + + # record the component in the cross-reference table + push @{$changeToComponents{$change}}, "$CompName"; + } + + &PrintLines(@CompLines); +} + +# +# +# Creates the Release Notes html file by extracting the perforce descriptions for each +# change that has been made to the components +# +# Inputs: Product, Source path of the product (i.e.//EPOC/master), the source path on the +# main codeline if a delivery branch is being used, Previous changelist, +# Current changelist, changelist from which the branch was made if a branch is being +# used, array of components and their source. +# Outputs: Release Notes html file. +# +# Algorithm: +# Loop through the component&source array +# Determine whether a boundary, component name, a source dir +# If a source dir, query perforce to see what changelists have affected it in the period that we're interested in +# If it has been affected, add the changelist to this component's changelists, unless it's already there +# +# This is rather inefficient :-( +# +sub CreateReleaseNotes +{ + my $Product = shift; + my $Srcpath = shift; + my $MainLinePath = shift; + my $PrevCL = shift; + my $CurrentCL = shift; + my $BranchCL = shift; + my @ComponentAndSource = @_; + + #Reset all arrays to NULL + my @PrevGTMrpComponents = (); + my @CurrGTMrpComponents = (); + my @PrevTVMrpComponents = (); + my @CurrTVMrpComponents = (); + my @CurrMrpComponents = (); + my @Components = (); + my @UnchangedComponents = (); + my @ChangedComponents = (); + my %changeProcessed = (); # hash of changelists processed for this component + my %changeToDescription = (); # hash of descriptions for non-reverted changelists + + $PrevCL++; # increment changelist number so we don't include the very first submission + # - it would have been picked up in the last run of this script + + my $ProductName = "Symbian_OS_v$Product\_Changes_Report"; + + open OUTFILE, "> $ProductName.html" or die "ERROR: Can't open $ProductName.html for output\n$!"; + print OUTFILE <\n\n\n$ProductName\n\n\n +\n +\n\n
\n\n +

$ProductName

+

----------------------------------------
\n +

GT Components

\n +HEADING_EOF + + my $CompName; + my $dirCount = 0; + + + # Loop through the list of elements running perforce commands to obtain the descriptions + # of any changes that have been made since the last release build + foreach my $element(@ComponentAndSource) + { + # Is it the boundary? + if($element =~ /\*\*TECHVIEWCOMPONENTS\*\*/) + { + # print out the accumulated GT component, if any + &PrintComponentDescriptions(\%changeToDescription, $CompName, \@ChangedComponents, \@UnchangedComponents) if ($dirCount); + $dirCount = 0; + # no need to clear the hashes, because that will happen at the first TV component + + print OUTFILE "

Techview Components

\n"; + } + # Is it a component name? + elsif($element =~ /^([A-Z].*)/) + { + my $newName = $1; + + &PrintComponentDescriptions(\%changeToDescription, $CompName, \@ChangedComponents, \@UnchangedComponents) if ($dirCount); + $dirCount = 0; + + $CompName = $newName; + %changeProcessed = (); + %changeToDescription = (); + print "Processing $CompName...\n" if ($debug); + } + # Is it a source directory? + elsif($element =~ /^([a-z].*?)\s*$/) + { + my $Topdir = $1; + $dirCount++; + + # If it contains spaces, quote it + if($Topdir =~ /.*\s+.*/) + { + $Topdir = "\"$Topdir\""; + } + + # Find the changes that have affected this dir + # (Changes come back in reverse chronological order) + my @CompChange = `p4 changes -l $Srcpath$Topdir...\@$PrevCL,\@$CurrentCL`; + + # if the current release is on a branch then the p4 command also needs to be run + # to capture changes on the codeline before the files were branched + if ($MainLinePath) + { + # So far, @CompChange contains the info from the delivery + # branch only + # The earliest changelist on the delivery branch is the creation + # of the branch, which is not interesting to anyone. + # Hence, remove it here: + + # Work backwards from the end of the output chopping off the + # last item till we've chopped off a changelist header + my $choppedText; + do + { + # Remove last line + $choppedText = pop @CompChange; + } + until (!defined $choppedText || $choppedText =~ m/^Change\s\d+\s/); + + # Now append the earlier changes from the main line + my @extrainfo = `p4 changes -l $MainLinePath$Topdir...\@$PrevCL,\@$BranchCL`; + push @CompChange, @extrainfo; + } + + # Normalise the output of P4 + @CompChange = map { split "\n"; } @CompChange; + + # Extract change descriptions into a hash keyed on changelist number + my %moreChangeDescriptions; + my $change; + foreach my $line (@CompChange) + { + if ($line =~ /^Change\s(\d+)\s/) + { + my $newchange = $1; + $change = ""; + # ignore if already processed for this component + next if ($changeProcessed{$newchange}); + $changeProcessed{$newchange} = 1; + $change = $newchange; + } + next if (!$change); + push @{$moreChangeDescriptions{$change}}, $line; + } + + # Process changes (newest first), extracting the section and + # processing any reversion information + foreach my $change (reverse sort keys %moreChangeDescriptions) + { + if ($reverted{$change}) + { + print "REMARK: $CompName - deleting description of reverted change $change\n"; + delete $moreChangeDescriptions{$change}; + next; + } + + my @changeLines = @{$moreChangeDescriptions{$change}}; + + my @revisedLines = (); + push @revisedLines, shift @changeLines; # keep the "Change" line + + my $line; + while ($line = shift @changeLines) + { + last if ($line =~ /$/); + + $line =~ s/^\t+//; + $line =~ s/\&/&/g; + $line =~ s/\/>/g; + $line =~ s/\"/"/g; # quote the " character as well + + push @revisedLines, $line; + } + + if (scalar @changeLines == 0) + { + # consumed the whole description without seeing + # must be old format + @{$changeToDescription{$change}} = @revisedLines; + printf ".. unformatted change %d - %d lines\n", $change, scalar @changeLines if ($debug); + next; + } + + # Must be properly formatted change description + # discard everything seen so far except the "Change" line. + @revisedLines = (shift @revisedLines); + while ($line = shift @changeLines) + { + last if ($line =~ /<\/EXTERNAL>$/); + + $line =~ s/^\t+//; + $line =~ s/\&/&/g; + $line =~ s/\/>/g; + $line =~ s/\"/"/g; # quote the " character as well + + push @revisedLines, $line; + + # Opportunity to pick information out of changes as they go past + if ($line =~ /^\s*((DEF|PDEF|INC)\d+):?\s/) + { + $allDefects{$1} = $line; + next; + } + if ($line =~ /^(BR[0-9.]+)\s/) + { + $allBreaks{$1} = $line; + next; + } + + } + + # update the description for this change + @{$changeToDescription{$change}} = @revisedLines; + printf ".. formatted change %d - %d external lines\n", $change, scalar @revisedLines if ($debug); + + # check for reversion information in rest of the formatted description + # submission checker delivers one line per list element + foreach my $line (grep /Changed Components\n", join(", \n", sort @ChangedComponents), "") if (@ChangedComponents); + + &PrintLines("

Unchanged Components

\n", join(", \n", sort @UnchangedComponents), "") if (@UnchangedComponents); + + if (scalar @ChangedComponents) + { + &PrintLines("

Components affected by each change

"); + + &PrintLines("\n"); + foreach my $change (reverse sort keys %changeToComponents) + { + &PrintLines("\n"); + } + &PrintLines("
$change", join(", ", @{$changeToComponents{$change}}), "
\n"); + } + + my @allDefectTitles = (); + foreach my $defect (sort keys %allDefects) + { + push @allDefectTitles,$allDefects{$defect}; + } + &PrintLines("

List of Defect Fixes

", "
", @allDefectTitles, "
") if (scalar @allDefectTitles); + + my @allBreakTitles = (); + foreach my $break (sort keys %allBreaks) + { + push @allBreakTitles,$allBreaks{$break}; + } + &PrintLines("

List of Breaks

", "
", @allBreakTitles, "
") if (scalar @allBreakTitles); + + &PrintLines(""); + close OUTFILE; + + return "$ProductName.html"; +} + +sub PrintLines +{ + # Output field and record separators set (locally) to produce newlines + # between items in list, and another newline on the end + local $, = "\n"; + local $\ = "\n"; + print OUTFILE @_; +} + +# +# +# Extracts the sourcecode path and changelist from a Perforce report file. +# +# Inputs: Location of a perforce report file, Platform (e.g. cedar) +# Outputs: Source path of the product (e.g.//EPOC/master), changelist used in build +# +# +sub GetPrevCodelineandCL +{ + my $FileAndPath = shift; + my $Platform = shift; + + my $LogFile; + my $PrevCL; + my $PrevCodeline; + + if (!open(DAT, $FileAndPath)) + { + print ERRORLOG "Could not open $FileAndPath!\n" if $debug; + die "ERROR: Cannot open $FileAndPath: $!\n"; + } + { + # Grab complete file in one string + local $/ = undef; + $LogFile = ; + } + close DAT; + + if ($LogFile =~ m{ClientSpec.*?]*>.*?(//.+?)$Platform/.*?}s) + { + $PrevCodeline = $1; + } + + if ($LogFile =~ m{Perforce Change[Ll]ist.*?]*>(.*?)}s) + { + # Perforce changelist table data may either be in form of "nnnnnn" or "ssssss @ nnnnnn" + # ssssss is the snapshot id, which may be a string of digits + # nnnnnn is the changelist number + # + # Get the later string of digits + ($PrevCL) = $1 =~ m{(\d+)\D*$}; + } + + unless ($PrevCL) { die "ERROR: Unable to parse previous changelist from $FileAndPath\n"; } + unless ($PrevCodeline) { die "ERROR: Unable to parse previous codeline from $FileAndPath\n"; } + + return $PrevCL, $PrevCodeline; +} + +