diff -r 85578ba0aa08 -r be14ecca790f bldsystemtools/commonbldutils/GenerateChangesReport.pl --- a/bldsystemtools/commonbldutils/GenerateChangesReport.pl Fri Apr 16 16:10:01 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,844 +0,0 @@ -# -# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -# All rights reserved. -# This component and the accompanying materials are made available -# under the terms of "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: -# -#! 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; - my $spacer = "\n"; - - - # 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); - - # Process all lines starting with the first section. - while (($line =~ /$/) || ($line = shift @changeLines)) - { - # Process an section. - while ($line =~ /$/) - { - # Keep processing until an line is encountered - while(($line = shift @changeLines) && ($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; - } - } - push @revisedLines, $spacer; - } - } - - # 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; -} - -