# 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 = ; 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 () { last if /^#\s*project\s*root\s*$/i; } die $PGM, "Malformed sd.map file\n" if !~ /^#\s*-+\s+-+\s*$/; while () { 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 () { $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 () { 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 () { 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 () { 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;