Windows-Server-2003/tools/postbuildscripts/pdbsrcstream.cmd

462 lines
14 KiB
Batchfile

@REM -----------------------------------------------------------------
@REM
@REM PdbSrcStream.cmd - skupec
@REM Adds source depot information to private PDBs.
@REM
@REM Copyright (c) Microsoft Corporation. All rights reserved.
@REM
@REM -----------------------------------------------------------------
@perl -x "%~f0" %*
@goto :EOF
#!perl
#line 13
################################################################################
#
# Required packages
#
################################################################################
use strict;
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
use lib $ENV{RAZZLETOOLPATH};
use PbuildEnv;
use Logmsg qw(errmsg logmsg wrnmsg);
use ParseArgs;
use BuildName;
use File::Spec;
use File::Temp qw(tempfile);
################################################################################
#
# Global vars
#
################################################################################
sub TRUE {return(1);} # BOOLEAN TRUE
sub FALSE {return(0);} # BOOLEAN FALSE
# This program's base filename
my $program;
# Name of our lock file
my $lock;
# Generic loop vars
my $lpCount = 0;
my $i = 0;
# Temp var for splitting strings into
my @data;
# Hash for processing nt.have file
my %NtHave;
# Path to recurse for processing symbols
my $SymbolsPath;
# Default nt.have file
my $NT_HAVE = "$ENV{_NTPOSTBLD}\\build_logs\\sourcefilelists.txt";
# Counting var for indexing server variables
my $cnt = "00";
# Hashes for mapping root->server<->var
my %SERVER_TO_VAR;
my %VAR_TO_SERVER;
my %PATH_TO_SERVER;
################################################################################
#
# Create .tmp file so postbuild.cmd knows we're running.
#
################################################################################
BEGIN {
# name of this script w/o the full path
$program = substr($0, rindex($0, "\\")+1);
$lock = substr($program, 0, rindex($program, ".")) . ".tmp";
if (! open(hLogFile, ">$ENV{TEMP}\\$lock") ) {
errmsg("Can't open $ENV{TEMP}\\$lock for writing: $! - Exiting");
exit(-1);
}
print (hLogFile "1");
close (hLogFile);
}
################################################################################
#
# Unsure we always remove our temp file when exiting so postbuild.cmd knows the
# script has finished
#
################################################################################
END {
unlink ("$ENV{TEMP}\\$lock");
}
################################################################################
#
# Script usage
#
################################################################################
sub Usage { print<<USAGE; exit(1) }
Usage: $program [-l <language>] [<directory>]
-l <language> - Optional. Default is USA. If a language other than USA
is provided, the script exits because this process should only be done
once per build.
<directory> - Optional. The directory to recurse for processing symbols.
Default is %_NTPOSTBLD%\\symbols.pri
USAGE
################################################################################
#
# This script does nothing for incremental builds since we can't guarentee that
# the source file lists were correctly updated first. Since the rebuilding of
# a binary will cause the PDB to also be regenerated, we already know that the
# PDB has an empty source stream. By not running, it'll stay empty which means
# the streams for any build should never end up in an inconsistent state.
#
################################################################################
if ( -e "$ENV{_NTTREE}\\build_logs\\bindiff.txt" ) {
logmsg("PdbSrcStreams are not incremental build capable.");
exit(0);
}
################################################################################
#
# Main code
#
################################################################################
################################################################################
#
# Handle the command line options
#
################################################################################
for ($lpCount=0; $lpCount <= ($#ARGV); $lpCount++) {
SWITCH: {
# NOTE: PbuildEnv.pm handles the -l <lang> parameter
if ((substr($ARGV[$lpCount],0,1) eq "-") or (substr($ARGV[$lpCount],0,1) eq "/")) {
for ($i=1;$i<length($ARGV[$lpCount]);$i++) {
exit(Usage()) if uc(substr($ARGV[$lpCount],$i,1)) eq "?";
exit(Usage()) if uc(substr($ARGV[$lpCount],$i,1)) eq "H";
}
} else {
$SymbolsPath = $ARGV[$lpCount];
}
1; #Last line should do nothing
}
}
################################################################################
#
# Test for all conditions that require us to terminate early.
#
################################################################################
# nice exit if not defined
if (! (defined $ENV{OFFICIAL_BUILD_MACHINE}||defined $ENV{PDB_SRC_STREAM}) ) {
logmsg("PdbSrcStreams only runs on OFFICIAL_BUILD_MACHINES by default. ".
"Set PDB_SRC_STREAM in your environment to override this behavior.\n");
exit(0);
}
# Required env. vars that don't get a special error message
foreach ( qw(_NTPOSTBLD) ) {
if (! defined $ENV{$_} ) {
errmsg("Missing required environment variable '$_'. Terminating.\n");
exit(-1);
}
}
# %LANG% is set by PBuildEnv.pm
if ( defined $ENV{LANG} ) {
if (uc $ENV{LANG} ne "USA") {
logmsg("This script is only for US builds - Exiting");
exit(0);
}
} else {
# Assume %LANG%==USA
}
# allow default symbol path override
if ($SymbolsPath eq "") {
$SymbolsPath = "$ENV{_NTPOSTBLD}\\symbols.pri";
}
if (! -e "$SymbolsPath" ) {
errmsg("$SymbolsPath doesn't exist! - exiting.");
exit(-1);
}
################################################################################
#
# Make hash to resolve directories to servers. Modifies globals.
#
################################################################################
GetNtSrv();
################################################################################
#
# Allow override of nt.have file
#
################################################################################
if (defined $ENV{NT_HAVE}) {
$NT_HAVE = $ENV{NT_HAVE};
}
################################################################################
#
# Slurp nt.have into a hash in memory
#
################################################################################
if ( ! open(hFILE, "$NT_HAVE") ) {
errmsg("Can't open $NT_HAVE ($!) - exiting");
exit(-1);
}
while (<hFILE>) {
chomp;
@data = split(/\s+-\s+/, $_);
$NtHave{uc $data[1]} = $data[0];
}
close(hFILE);
################################################################################
#
# Process the PDBs
#
################################################################################
RecurseDirectoryTree("$SymbolsPath", \&StuffSrcIntoPdb);
################################################################################
#
# Subroutines - keep sorted by name!
#
################################################################################
# --------------------------------------------------------------------------
# Populates globals with data about the SD servers
# --------------------------------------------------------------------------
sub GetNtSrv {
RecurseDirectoryTree("$ENV{_NTPOSTBLD}\\build_logs\\sourcefilelists",
\&GetServers);
%VAR_TO_SERVER = reverse %SERVER_TO_VAR;
}
# --------------------------------------------------------------------------
# Callback for GetNtSrv() directory recursion
# --------------------------------------------------------------------------
sub GetServers {
my $file = shift;
return unless (-e "$file");
return if (-d "$file");
return unless ($file =~ /\.txt$/);
local *hFILE;
open(hFILE, "$file");
my $text = <hFILE>;
close(hFILE);
chomp($text);
my $basename = substr($file, rindex($file, "\\")+1);
$basename =~ s/\.txt$//i;
my $root = "$ENV{SDXROOT}\\$basename";
my ($domain, $server) = split(/\s+/, $text);
# Root depot is a special case
if ($root =~ /ROOT$/i) {
$root =~ s/\\ROOT$//i;
}
# All fields must be defined
if ( defined $domain && defined $server ) {
if (! defined $SERVER_TO_VAR{lc $server}) {
$server =~ /^(.*?)(depot)?\./i;
my $var_name = "WIN_".uc($1);
$SERVER_TO_VAR{lc $server} = "$var_name";
}
if (! defined $PATH_TO_SERVER{uc $root} ) {
$PATH_TO_SERVER{uc $root} = lc $server;
}
} else {
wrnmsg("can't parse $file - skipping.");
}
}
# --------------------------------------------------------------------------
# Recurses a directory tree and invokes the callback routine for
# every file and directory found (except '.' and '..')
# --------------------------------------------------------------------------
sub RecurseDirectoryTree {
# setup
my $TreeRoot = shift;
$TreeRoot =~ s/\\$//; # cut possible trailing '\'
my $Function = shift;
my $file;
my @files;
local *hDIR;
if (!opendir(hDIR, "$TreeRoot") ) {
errmsg("Cannot open $TreeRoot\n");
return(0);
}
#
# Loop through all entries
#
foreach $file ( readdir(hDIR) ) {
next if ($file eq "."); # skip '.'
next if ($file eq ".."); # skip '..'
$file = "$TreeRoot\\$file"; # add parent path
&$Function("$file"); # invoke callback
if (-d "$file" ){ # recurse directories
RecurseDirectoryTree("$file", \&$Function);
}
}
# cleanup
closedir(hDIR);
}
# --------------------------------------------------------------------------
# Returns the file+sd_spec or empty array
# --------------------------------------------------------------------------
sub ResolveFileToSD {
my @SD_SPEC;
my $file = shift;
if ( defined $NtHave{uc $file}) {
@SD_SPEC = ($file, $NtHave{uc $file});
} else {
@SD_SPEC = ();
}
return(@SD_SPEC);
}
# --------------------------------------------------------------------------
# Processes a single PDB
# --------------------------------------------------------------------------
sub StuffSrcIntoPdb {
my $line;
my $file = shift;
return if ($file !~ /\.pdb$/i);
return if (! -e "$file");
return if ( -d "$file");
return if (! -W "$file");
my @lines_to_stuff = ();
my %var_references = ();
if (! open(hCV, "cvdump -sf $file|") ) {
printf("WARN $0: Can't call cvdump! ($!)\n");
return();
}
LOOP: while ( $line = <hCV> ) {
last LOOP if ($line =~ /^\*\*\* SOURCE FILES/);
}
while ($line = <hCV>) {
my @file_spec = ();
chomp $line;
next if ($line =~ m/^\s*$/);
#
# Translate the local file path to a source depot path and revision
#
@file_spec = ResolveFileToSD($line);
#
# Make sure an empty array wasn't returned
#
if (@file_spec && $#file_spec == 1) {
#
# Loop through the SD servers in reverse order until we find one
# who's local root path matches the root path of the current file.
#
foreach (reverse sort keys %PATH_TO_SERVER) {
if ($file_spec[0] =~ /^\Q$_\E/i) {
#
# Write the source line into the format:
# <LocalPath>*<ServerVariable>*<SourceDepotPath>
#
my $sdvar = $SERVER_TO_VAR{lc $PATH_TO_SERVER{$_}};
if (! defined $sdvar ) {
$sdvar = $PATH_TO_SERVER{$_};
}
$file_spec[1] =~ /#(\d*)$/;
my $vernum = $1;
$file_spec[1] =~ s/#\d*$//;
$file_spec[1] =~ s/^\/\/depot\///i;
# second version of the SD string
push(@lines_to_stuff, "$file_spec[0]*$sdvar*$file_spec[1]*$vernum");
$var_references{$sdvar} = 1;
@file_spec = ();
}
}
}
}
close(hCV);
#
# Only write the stream if we found at least one file spec.
#
if ( @lines_to_stuff > 0 ) {
#
# Use a temp file to create the stream data
#
my $TempFile;
(undef, $TempFile) = tempfile("PdbXXXXXX", SUFFIX=>".stream", OPEN => 0, DIR => "$ENV{TEMP}");
if (! open(hTEMP, ">$TempFile") ) {
logmsg("Can't open tempfile for $file ($!) - skipping\n");
return(FALSE);
}
#
# List each server
#
printf(hTEMP "SRCSRV: ini ------------------------------------------------\n");
# version control system string to identify the system to the user
printf(hTEMP "VERSION=1\n");
printf(hTEMP "VERCTRL=Source Depot\n");
printf(hTEMP "SRCSRV: variables ------------------------------------------\n");
printf(hTEMP "SRCSRVTRG=%%targ%%\\%%var2%%\\%%fnbksl%%(%%var3%%)\\%%var4%%\\%%fnfile%%(%%var1%%)\n");
printf(hTEMP "SRCSRVCMD=sd.exe -p %%fnvar%%(%%var2%%) print -o %%srcsrvtrg%% -q %%depot%%/%%var3%%#%%var4%%\n");
printf(hTEMP "DEPOT=//depot\n");
foreach (sort keys %VAR_TO_SERVER) {
printf(hTEMP "$_=$VAR_TO_SERVER{$_}\n") if (defined $var_references{$_});
}
printf(hTEMP "SRCSRV: source files ---------------------------------------\n");
#
# Now write the file information
#
foreach (@lines_to_stuff) {
printf(hTEMP "$_\n");
}
printf(hTEMP "SRCSRV: end ------------------------------------------------\n");
close(hTEMP);
system("pdbstr -w -i:$TempFile -p:$file -s:srcsrv");
unlink("$TempFile");
}
}