windows-nt/Source/XPSP1/NT/admin/pchealth/build/tools/sdslm/log.pl
2020-09-26 16:20:57 +08:00

451 lines
12 KiB
Perl

# __________________________________________________________________________________
#
# Purpose:
# PERL Script to emulate SLM's 'log' command
#
# Parameters:
# See Usage below
#
# Output:
# Perforce output manipulated to look like the output from SLM's 'log' command or
# the appropriate error message or usage statement
# __________________________________________________________________________________
#
# Load common SLM wrapper subroutine module
#
use SlmSubs;
#
# Parse command line arguments
#
SlmSubs::ParseArgs(@ARGV);
#
# Call usage and exit if ParseArgs has set the Usage or InvalidFlag flags
#
if ($Usage or $InvalidFlag)
{
print $ErrorMessage;
&Usage;
exit 1;
}
#
# Default maximum number of output lines is 10
#
$MaxOutputLines = 10;
#
# If a different number was passed in on the command line use it for the maximum
#
if ($Number)
{
$MaxOutputLines = $Number;
}
#
# Add Branch Heading if -b specified
#
if ($CrossBranches)
{
$BranchHeading = "branch ";
}
#
# Print out header; suppress if -z is passed in
#
if (!$NoHeaders)
{
print "time user $BranchHeading op file comment\n";
}
#
# Call subroutine that handles recursion and calls the RetrieveLog subroutine that
# pulls 'log' information from @LogCache
#
&SlmSubs::Recurser("main::RetrieveLog");
sub RetrieveLog
# __________________________________________________________________________________
#
# Does all the interaction with the SLM server and reformatting of results to look
# like SLM's 'log' output
#
# Parameters:
# Optional Subdirectory
#
# Output:
# Regular SLM 'log' output
#
# __________________________________________________________________________________
{
if ($_[0])
{
$SubDirectory = $_[0];
#
# Make a chopped version of $SubDirectory to print out
#
$ChoppedSubDirectory = $SubDirectory;
chop $ChoppedSubDirectory;
}
else
{
#
# Initialize string to null
#
$SubDirectory = "";
}
#
# Get the list of changes for either @FileList or every file from Perforce
#
if (@FileList)
{
#
# Append $Subdirectory to every file in $FileList
#
@RelativeFileList = ();
foreach $File (@FileList)
{
push @RelativeFileList, "$SubDirectory$File";
}
@FileSpec = @RelativeFileList;
}
else
{
push @FileSpec, "$SubDirectory\%1";
}
open(FILELOG, qq/$SourceControlClient filelog -m $MaxOutputLines @FileSpec|/);
@FileLog = <FILELOG>;
close(FILELOG);
#
# Make a list of FileLog output
#
foreach $FileLogLine (@FileLog)
{
#
# Figure out which section we're in and manipulate output differently depending
# on which section it is
#
if ( $FileLogLine =~ /^(\/\/.*)$/ )
{
$FileName = $1;
}
else
{
if ( $FileLogLine =~ /^\.\.\. #(\d+) change (\d+) (\S+) on (.*) (.*) by .*@(\S*).*'(.*)'/ )
{
#
# Manipulate filelog output to look like SLM's 'log' output
#
$Version = $1;
$Change = $2;
$Action = $3;
$Time = "$4\@$5";
$Owner = "\U$6";
$Comment = $7;
$Time =~ s/^19//;
$Time =~ s/:[^:]*$//;
$Time =~ s/^(9.)\//19$1\//;
$LogLine = "$Time, $Owner, $Action, $FileName, $Version, $Change, $Comment";
push @LogCache, "$LogLine\n";
}
}
}
if ($CrossBranches)
{
do
{
$FoundBranches = $main::FALSE;
@BranchLogNext = ();
if (not @BranchLog)
{
@BranchLog = @FileLog;
}
#
# Find source of change if not in this branch.
#
foreach $FileBranchLine (@BranchLog)
{
if ( $FileBranchLine =~ /^(\/\/.*)$/ )
{
$FileName = $1;
}
if ( $FileBranchLine =~ /^\.\.\. #(\d+) change (\d+) (\S+) on (.*) (.*) by .*@(\S*).*'(.*)'/ )
{
$ChangeNumber = $1;
}
if ( $FileBranchLine =~ /^\.\.\. \.\.\. .* from ([^#]*#\d+).*\n/ )
{
$FileLogHash{lc("$FileName#$ChangeNumber")} = $1;
push @BranchLogNext, "$1\n";
$FoundBranches = $main::TRUE;
}
}
if (@BranchLogNext)
{
open( TemporaryFileSpec, ">$ENV{tmp}\\TmpBranchSpec");
print TemporaryFileSpec @BranchLogNext;
close (TemporaryFileSpec);
open(BRANCHLOG, qq/type $ENV{tmp}\\TmpBranchSpec | $SourceControlClient -x - filelog -m 1 |/);
@BranchLog = <BRANCHLOG>;
push @FullBranchLog, @BranchLog;
close(BRANCHLOG);
}
} while ($FoundBranches);
unlink "$ENV{tmp}\\TmpBranchSpec";
#
# Make a list of BranchLog output
#
foreach $BranchLogLine (@FullBranchLog)
{
#
# Figure out which section we're in and manipulate output differently depending
# on which section it is
#
if ( $BranchLogLine =~ /^(\/\/.*)$/ )
{
$FileName = $1;
}
else
{
if ( $BranchLogLine =~ /^\.\.\. #(\d+) change (\d+) (\S+) on (.*) (.*) by .*@(\S*).*'(.*)'/ )
{
#
# Manipulate BranchLog output to look like SLM's 'log' output
#
$Version = $1;
$Change = $2;
$Action = $3;
$Time = "$4\@$5";
$Owner = "\U$6";
$Comment = $7;
$Time =~ s/^19//;
$Time =~ s/:[^:]*$//;
$Time =~ s/^(9.)\//19$1\//;
$LogLine = "$Time, $Owner, $Action, $FileName, $Version, $Change, $Comment";
$BranchLogHash{lc("$FileName#$Version")} = "$LogLine\n";
push @BranchLogCache, "$LogLine\n";
}
}
}
}
#
# Print out standard header of 'log' output unless -z switch used
#
if (!$NoHeaders)
{
print "\n";
if ($ChoppedSubDirectory)
{
print "Log for $LocalMap\/$ChoppedSubDirectory:\n";
}
else
{
print "Log for $LocalMap:\n";
}
print "\n";
}
#
# Sort list in case cache was out of order
#
@SortedLogCache = sort @LogCache;
#
# Figure out where to start in @SortedLogCache so that there are no more than $MaxOutputLines outputted
#
$PrintCounter = $#LogCache - $MaxOutputLines;
if ($PrintCounter < 0)
{
$PrintCounter = 0;
}
#
# Print out @SortedLogCache
#
while ($SortedLogCache[$PrintCounter])
{
$LogLine = $SortedLogCache[$PrintCounter++];
$FormattedLine = FormatLine($LogLine);
print "$FormattedLine\n";
if ($CrossBranches)
{
$LogLine =~ /[^,]*, [^,]*, [^,]*, ([^,]*), ([^,]*),.*/;
$FileVer = $FileLogHash{lc("$1#$2")};
@BranchList = ();
while ($FileVer)
{
$FormattedLine = FormatLine(" ($BranchLogHash{lc($FileVer)}");
push @BranchList, "$FormattedLine)\n";
$FileVer = $FileLogHash{lc($FileVer)};
}
print sort @BranchList;
}
}
}
sub FormatLine
# __________________________________________________________________________________
#
# Formats a line from the LogCache to the format specified log.pl parameters
#
# Parameters:
# Line from LogCache
#
# Output:
# Formatted Line
#
# __________________________________________________________________________________
{
$LogCacheLine = $_[0];
$RelativeDepotMap = $DepotMap;
$RelativeDepotMap =~ s/^\/\/depot\/[^\/]+(\/.*)/$1/;
#
# Append the current directory to the root depot map and grep for only those files in the cache that are in this
# subdirectory
#
if ( $LogCacheLine =~ /([^,]*), ([^,]*), ([^,]*), \/\/depot\/([^,]*), ([^,]*), ([^,]*), (.*)\n/i )
{
#
# Format the output to look like SLM's 'log' output
#
$Owner = sprintf "%-12s", "$2";
$Time = sprintf "%-18s", "$1";
$Action = sprintf "%-9s", "$3";
$FileName = $4;
$Version = $5;
$Change = $6;
$Comment = $7;
if ( $FileName =~ /(.*)\Q$RelativeDepotMap$SubDirectory\E([^,]*)/i )
{
$Branch = sprintf "%-9s", "$1";
$FileName = $2;
}
else
{
if ( $FileName =~ /(.*)\/([^,]*)/i )
{
$Branch = sprintf "%-9s", "$1";
$FileName = $2;
}
}
#
# Don't pick up files in subdirectories
#
if (! ($FileName =~ /\//))
{
#
# If $FileList specified, only match files in it
#
if ( (! @FileList) or (SlmSubs::InList($FileName, \@FileList)))
{
#
# Add subdirectory to $FormattedFileName if -z was passed in on command line
#
if ($NoHeaders)
{
$FormattedFileName = sprintf "%-22s", "$SubDirectory$FileName v$Version c$Change";
}
else
{
$FormattedFileName = sprintf "%-22s", "$FileName v$Version c$Change";
}
if ($CrossBranches)
{
$FormattedLogLine = "$Time $Owner $Branch $Action $FormattedFileName $Comment";
}
else
{
$FormattedLogLine = "$Time $Owner $Action $FormattedFileName $Comment";
}
}
}
}
#
# Don't truncate line if in verbose mode
#
if (!$Verbose)
{
$FormattedLogLine = sprintf "%.80s", "$FormattedLogLine";
}
return $FormattedLogLine;
}
sub Usage
# __________________________________________________________________________________
#
# Prints out a usage statement for this script. In this case usurped from SLM's
# 'log' usage statement
#
# Parameters:
# None
#
# Output:
# The usage statement
#
# __________________________________________________________________________________
{
print q/log - prints historical information for a project
Usage: log [-?fhvrzd] [-#] [file1] [file2...]
Arguments:
-h prints out this message.
-v (verbose) Provides a more extensive listing of log information.
-r (recursive) applies the command to a given directory and in every
subdirectory beneath it. Note that a pattern argument is NOT accepted
with this flag for the log command. Use -a or -r, but not both.
-# specifies how many log entries to display, counting back from the
present moment (log -3 displays the 3 most recent events).
-z format the log in a sortable format without headers.
-d include deleted subdirectories in search.
-b apply history across branches.
/;
}