248 lines
5.9 KiB
Perl
248 lines
5.9 KiB
Perl
# FileName: ChangesToFiles.pl
|
|
#
|
|
#
|
|
# Usage = ChangesToFiles.pl [project] changesfile > filesfile
|
|
#
|
|
# Function: Takes build.changes and runs sd describe on each change to get the file list.
|
|
# Specifiying a project limits the output to just that project
|
|
#
|
|
|
|
# WARNING:
|
|
# WARNING: make sure pathname comparisons are case insensitive. Either convert the case or do the
|
|
# WARNING: comparisons like this:
|
|
# WARNING: if ($foo =~ /^\Q$bar\E$/i) {}
|
|
# WARNING: or if ($foo !~ /^\Q$bar\E$/i) {}
|
|
# WARNING:
|
|
|
|
$PGM='ChangesToFiles: ';
|
|
|
|
$Usage = "ChangesToFiles.pl [options] changesfile\n"
|
|
. "options:\n"
|
|
. " [-verbose]\n"
|
|
. " [-descriptions]\n"
|
|
. " [-integrates]\n"
|
|
. " [-branches]\n"
|
|
. " [-deletes]\n"
|
|
. " [-publics]\n"
|
|
. " [-all]\n"
|
|
. " [-project depotname]\n"
|
|
;
|
|
|
|
$DefaultChangesFile = "build.Changes";
|
|
|
|
|
|
#
|
|
# Debug routines for printing out variables
|
|
#
|
|
sub gvar {
|
|
for (@_) {
|
|
print "\$$_ = $$_\n";
|
|
}
|
|
}
|
|
|
|
#
|
|
# get current directory
|
|
#
|
|
sub thisdir () {
|
|
open CWD, 'cd 2>&1|';
|
|
my $here = <CWD>;
|
|
close CWD;
|
|
|
|
return $here;
|
|
}
|
|
|
|
#
|
|
# grap sdxroot from the environment
|
|
#
|
|
|
|
$sdxroot = $ENV{'SDXROOT'} or die $PGM, "SDXROOT not set in environment\n";
|
|
|
|
$sdxpath = $sdxroot;
|
|
$sdxpath =~ s/^[A-Z]://i;
|
|
|
|
#
|
|
# Process arguments
|
|
#
|
|
while ($_ = shift) {
|
|
|
|
$nextarg = $ARGV[0];
|
|
$nextarg =~ tr/A-Z/a-z/;
|
|
|
|
if (/^-verbose$/i) { $Verbose++; next; }
|
|
if (/^-v/i) { $Verbose++; next; }
|
|
|
|
if (/^-all$/i) { $DoAll++; next; }
|
|
if (/^-a$/i) { $DoAll++; next; }
|
|
|
|
if (/^-debug$/i) { $Debug++; next; }
|
|
if (/^-d$/i) { $Debug++; next; }
|
|
|
|
if (/^-descriptions$/i) { $DoDescriptions++; next; }
|
|
if (/^-integrates$/i) { $DoIntegrates++; next; }
|
|
if (/^-branches$/i) { $DoBranches++; next; }
|
|
if (/^-deletes$/i) { $DoDeletes++; next; }
|
|
if (/^-publics$/i) { $DoPublics++; next; }
|
|
|
|
if (/^-nofiles$/i) { $NoFiles++; next; }
|
|
|
|
if (/^-project$/i) { $OnlyProjects++; $ProjectList{$nextarg}++; shift; next; }
|
|
if (/^-p$/i) { $OnlyProjects++; $ProjectList{$nextarg}++; shift; next; }
|
|
|
|
if (/^-?$/i) { die $Usage; }
|
|
if (/^-help$/i) { die $Usage; }
|
|
if (/^-/) { die $Usage; }
|
|
|
|
if (not $ChangesFile) {
|
|
$ChangesFile = $_;
|
|
next;
|
|
}
|
|
|
|
die $Usage;
|
|
}
|
|
|
|
if ($DoAll) {
|
|
$DoIntegrates++;
|
|
$DoBranches++;
|
|
$DoDeletes++;
|
|
$DoPublics++;
|
|
$DoDescriptions++;
|
|
}
|
|
|
|
$ChangesFile = "$sdxroot\\$DefaultChangesFile" unless $ChangesFile;
|
|
|
|
# gvar Verbose, DoAll, Debug, DoDescriptions, DoIntegrates, DoBranches, DoDeletes, DoPublics, OnlyProjects, ChangesFile;
|
|
|
|
#
|
|
# setup SD.MAP mapping from projects to directories
|
|
#
|
|
|
|
$sdxmapfile = "$sdxroot\\sd.map";
|
|
open SDMAPFILE, $sdxmapfile or die $PGM, "Could not open $sdxmapfile <$!>\n";
|
|
|
|
while (<SDMAPFILE>) {
|
|
last if /^#\s*project\s*root\s*$/i;
|
|
}
|
|
|
|
die $PGM, "Malformed sd.map file\n" if <SDMAPFILE> !~ /^#\s*-+\s+-+\s*$/;
|
|
|
|
while (<SDMAPFILE>) {
|
|
last if /^\s*$/;
|
|
next unless /^\s*(\S+)\s*=\s*(\S+)\s*$/;
|
|
|
|
$p = $1;
|
|
$r = $2;
|
|
|
|
$p =~ tr/A-Z/a-z/;
|
|
$r =~ tr/A-Z/a-z/;
|
|
|
|
$SDProjectDir{$p} = "$sdxpath\\$r";
|
|
}
|
|
|
|
close SDMAPFILE;
|
|
|
|
#
|
|
# Check the -projects arguments against SDMAP
|
|
#
|
|
if ($Project) {
|
|
for (keys %ProjectList) {
|
|
die $PGM, $_, " not found in sd.map\n";
|
|
}
|
|
}
|
|
|
|
#
|
|
# Open and process the changes file
|
|
#
|
|
open BUILDCHANGES, $ChangesFile or die $PGM, "Could not open: ", $ChangesFile, "\n";
|
|
|
|
$CurrentProject = "";
|
|
|
|
for (<BUILDCHANGES>) {
|
|
$CurrentProject = $1 if /^---+\s*(\w+)\s*$/;
|
|
$CurrentProject =~ tr/A-Z/a-z/;
|
|
|
|
next unless /^Change\s(\d+)\s+on\s+(\S+)\s+(\S+)\s+by\s+(\S+)\\(\S+)\@(\S+)\s*'/i;
|
|
|
|
$Change = $1;
|
|
$Timestamp = "$2 $3";
|
|
$Domain = "$4";
|
|
$Alias = "$5";
|
|
$Machine = "$6";
|
|
|
|
next if $Project and not $ProjectList{$CurrentProject};
|
|
|
|
$ProjectChanges{$CurrentProject} .= "$Change ";
|
|
}
|
|
|
|
$origdir = thisdir();
|
|
|
|
for (keys %ProjectChanges) {
|
|
|
|
$Depot = $_;
|
|
|
|
#
|
|
# Change to the project and run sd describe
|
|
#
|
|
chdir $SDProjectDir{$_} or die $PGM, "Could not chdir to $SDProjectDir{$_}: $!\n";
|
|
|
|
open SDOUT, "sd describe -s $ProjectChanges{$_} |" or die "Could not run sd describe: $!\n";
|
|
|
|
chdir $origdir;
|
|
|
|
TOP: while (<SDOUT>) {
|
|
|
|
next if /^\s*$/; # skip initial blank lines
|
|
|
|
if (not /^Change\s+(\d+)\s+by\s+(\S+)\\(\S+)\@(\S+)\s+on\s+(\S+)\s+(\S+)\s*$/i) {
|
|
warn $PGM, "Could not parse sd output: $_";
|
|
last;
|
|
}
|
|
|
|
$Change = $1;
|
|
$Domain = "$2";
|
|
$Alias = "$3";
|
|
$Machine = "$4";
|
|
$Timestamp = "$5 $6";
|
|
|
|
#
|
|
# Collect the description lines
|
|
#
|
|
$Description = "";
|
|
while (<SDOUT>) {
|
|
last if /^Affected files/i;
|
|
$Description .= $_;
|
|
}
|
|
|
|
#
|
|
# Output Change summary if doing descriptions
|
|
#
|
|
printf "Description of %-10s %6d by %s:%s", $Depot, $Change, $Alias, $Description if $DoDescriptions;
|
|
|
|
#
|
|
# Collect the files
|
|
#
|
|
while (<SDOUT>) {
|
|
redo TOP if /^Change\s/i;
|
|
next if /^\s*$/;
|
|
|
|
warn $PGM, "Can't parse: $_" unless /^\.\.\.\s/;
|
|
|
|
($dots, $Filename, $FileStatus) = split ' ';
|
|
|
|
#
|
|
# Finally, the output happens...
|
|
#
|
|
$dontprint = (not $DoIntegrates and $FileStatus =~ /integrat/i
|
|
or not $DoBranches and $FileStatus =~ /branch/i
|
|
or not $DoDeletes and $FileStatus =~ /delete/i
|
|
or not $DoPublics and $Filename =~ m+root/public/+i
|
|
or $NoFiles );
|
|
|
|
printf "%-10s %6d %-8s %19s %s %s\n", $Depot, $Change, $Alias, $Timestamp, $Filename, $FileStatus unless $dontprint;
|
|
}
|
|
}
|
|
close SDOUT;
|
|
}
|
|
|
|
exit 0;
|
|
|