### ### File: ### srcwatch.pl ### ### History: ### 06/17/2000 Jasonsch - Original hacking. ### 07/21/2000 Jasonsch - Made more general so other groups can use it. ### ### Description: ### Watches a set of directories for changes and e-mails someone about 'em. ### use POSIX qw(strftime); BEGIN { require "$ENV{'SDXROOT'}\\tools\\sendmsg.pl"; } ### Constants my $DEF_CONF_FILE = "srcwatch.txt"; my $NUM_CHANGES = 50; ### pseudo-globals my $CDATE = localtime(); my (%config); my $text = ""; # the body of the message my $sendmail = 0; if (!exists($ENV{'SDXROOT'})) { print "srcwatch.pl must be called from a razzle window!\n"; exit(0); } &InitConfig(\%config, @ARGV); $cnt = keys %{$config{'paths'}}; &InitHtmlText(\%config, $cnt); foreach (keys %{$config{'paths'}}) { $sendmail += &GetDepotChanges($_, \%config, $cnt); } $text .= << " EOHF"; EOHF if ($sendmail) { &sendmsg($config{'from'}, "$config{'groupname'} code changes for $config{'startdate'} to $config{'enddate'}", $text, $config{'targets'}, "content:text/html"); } ######################### S U B R O U T I N E S ########################## sub GetTodaysDate() { strftime("%Y/%m/%d", localtime(time())); } sub GetYesterdaysDate() { strftime("%Y/%m/%d", localtime(time() - 60 * 60 * 24)); } sub GetNewChanges($$$$) { my $sdate = shift; # start date my $edate = shift; # end date my $config = shift; my $depot = shift; my @changes = split(/\n/, `sd changes \@$sdate,$edate -s submitted`); my ($change, $cnum, $date, $time, $who, $desc, $integration); my (@new_changes, @files, $file, $lab, $ar); foreach $change (@changes) { $change =~ /^Change\s+(\d+)\s+on\s+(.*)\s+(.*)\s+by\s+(.*)\s+'(.*)'$/; $cnum = $1; $date = $2; $time = $3; $who = $4; $desc = $5; @files = &GetChangedFiles($cnum, $config, $depot); next unless(@files); # @files is an array of array refs ([$file, $lab, $op]) if ($files[0]->[2] eq 'integrate' || $files[0]->[2] eq 'branch') { if ($files[0]->[1] eq $$config{'lab'}) { my @md; # array of array refs (meta-data), with the structure: # ($cnum, $date, $time, $who, $desc, @files) @md = &GetIntegrationRecords($config, $depot, $desc, @files); foreach $ar (@md) { $fileref = pop(@$ar); @files = &ExtractFiles(@$fileref); push(@new_changes, [@$ar, $$fileref[0]->[1], [@files]]); } } else { # This is just some other lab integrating files in our depots, # which we don't care about. next; } } elsif (&InOurView($files[0]->[1], $config, 0)){ my @filelist = &ExtractFiles(@files); push(@new_changes, [$cnum, $date, $time, $who, $desc, $files[0]->[1], [@filelist]]); } } @new_changes; } sub ExtractFiles(@) { my @files; my $file; foreach $file (@_) { push(@files, $file->[0]); } @files; } sub GetChangedFiles($$$) { my $change = shift; my $config = shift; my $depot = shift; my @files = split(/\n/, `sd describe -s $change`); my (@files2, $branch, $op, $file); foreach (@files) { if (/^\s*\.\.\.\s+\/\/depot(\/private)?\/(\w+)\/([^\s]+) (\w+)$/) { $branch = lc($2); $file = $3; $op = $4; next unless (&CheckPath($file, $config, $depot)); push(@files2, [$file, $branch, $op]); } } @files2; } sub GetIntegratedFiles($$$) { my $change = shift; my $config = shift; my $depot = shift; my @files = split(/\n/, `sd describe -s $change`); my (@files2, $branch, $op, $file); foreach (@files) { if (/^\s*\.\.\.\s+\/\/depot\/(\w+)\/([^\s]+) (\w+)$/) { $branch = lc($1); $file = $2; $op = $3; if (&CheckPath($file, $config, $depot)) { ### TODO: Should the test below *just* be !InOutView(...) if (!&InOurView($branch, $config, 1) && $op ne 'integrate' && $op ne 'branch') { push(@files2, [$file, $branch, $op]); } } } } @files2; } sub CheckIgnorePath($$$) { my $path = shift; my $config = shift; my $depot = shift; my $ret = 0; my $p; foreach $p (@{$config->{'ignore_paths'}->{$depot}}) { if ($path =~ /^$depot\/$p/i) { $ret = 1; last; } } $ret; } sub CheckPath($$$) { my $path = shift; my $config = shift; my $depot = shift; my $ret = 0; my $p; foreach $p (@{$config->{'paths'}->{$depot}}) { if ($path =~ /^$depot\/$p/i && !&CheckIgnorePath($path, $config, $depot)) { $ret = 1; last; } } $ret; } sub GetIntegrationRecords($$$) { my $config = shift; my $depot = shift; my $int_desc = shift; my ($file, $text, @files, $cnum, $date, $time, $who, $desc, $line, @lines); my (@changes, $shortlab); my $originlab = ""; my %cs; # changes we've already seen $int_desc =~ /lab(\d+)_n/i; foreach $file (@_) { $file->[0] =~ s/#\d+$//; $file->[0] =~ s#^$depot/##i; foreach $line (@lines = split(/\n/, `sd changes -i $file->[0]`)) { chomp($line); $line =~ /^Change\s+(\d+)\s+on\s+(.*)\s+(.*)\s+by\s+(.*)\s+'(.*)'$/; $cnum = $1; $date = $2; $time = $3; $who = $4; $desc = $5; last if ($who =~ /ntbuild/i && $originlab && ($desc =~ /$originlab/ || $desc =~ /$shortlab/)); next unless (@files = &GetIntegratedFiles($cnum, $config, $depot)); next if (exists($cs{$cnum})); if (&HasFile($file->[0], @files)) { if (!$originlab) { $originlab = &GetOriginLab($cnum); $originlab =~ /^lab(\d+)/i; $shortlab = "lab$1"; } next unless ($files[0]->[1] eq $originlab); $cs{$cnum} = 1; push(@changes, [$cnum, $date, $time, $who, $desc, [@files]]); } } } @changes; } sub GetOriginLab($) { my $cnum = shift; my @lines = `sd describe -s $cnum`; my $lab = ""; foreach (@lines) { if (/^\s*\.\.\.\s+\/\/depot\/(\w+)\/[^\s]+\s+\w+$/) { $lab = lc($1); last; } } lc($lab); } sub HasFile($@) { my $file = shift; my $ret = 0; foreach (@_) { if ($_->[0] =~ /$file(#\d+)?$/) { $ret = 1; } } $ret; } sub GetDepotChanges($$) { my $depot = shift; my $config = shift; my $dc = shift; my ($domain, $alias, $client, $who, $change, $lab); my $bChanges = 0; chdir("$ENV{'SDXROOT'}\\$depot"); my @changes = &GetNewChanges($$config{'startdate'}, $$config{'enddate'}, $config, $depot); foreach $change (@changes) { $$change[4] =~ s//>/g; $$change[3] =~ /^(\w+)\\(.*)\@(.*)$/; $domain = $1; $alias = $2; $client = $3; @files = @{$$change[6]}; $lab = $$change[5]; next if ($#files < $[); if ($lab ne $$config{'lab'}) { $lab = "$lab"; } $bChanges = 1; if(!exists(${$$config{'group'}}{$alias})) { $alias = "$alias"; } $dh = "$depot" if ($dc > 1); $text .= << " EOROW"; $dh$alias$$change[0]$$change[1]$lab$$change[4]@files\n EOROW } $bChanges; } sub InitConfig($@) { my $config = shift; my @args = @_; my $configfile = $DEF_CONF_FILE; my $startdate = ""; my $enddate = ""; my ($arg, $opt); while (@args) { $arg = shift(@args); if ($arg =~ /^-(\w)/) { $opt = $1; if ($opt eq 'f') { $configfile = shift(@args); } elsif ($opt eq 's') { $startdate = shift(@args); } elsif ($opt eq 'e') { $enddate = shift(@args); } else { &PrintUsage(); } } else { &PrintUsage(); } } if ($startdate) { # Convert mm/dd/yy to yy/mm/dd $startdate =~ /^(\d+)\/(\d+)\/(\d+)$/; $startdate = "$3/$1/$2"; } else { $startdate = &GetYesterdaysDate(); } if ($enddate) { # Convert mm/dd/yy to yy/mm/dd $enddate =~ /^(\d+)\/(\d+)\/(\d+)$/; $enddate = "$3/$1/$2"; } else { $enddate = &GetTodaysDate(); } $$config{'startdate'} = $startdate; $$config{'enddate'} = $enddate; $$config{'premonition'} = 0; &ReadConfigFile($configfile, $config); } sub ReadConfigFile($$) { my $file = shift; my $config = shift; my ($key, $value, $dir, $depot); local (*FILE); # Fill in the config file we're reading from. $$config{'configfile'} = $file; if (open(FILE, $file)) { while () { /^\s*(\w+)\s*=\s*(.*)$/; $key = $1; $value = $2; # Some config options require fixup/processing $key = lc($key); if ($key eq "group") { foreach (split(/\s+|,/, $value)) { ${$$config{'group'}}{$_} = 1; } } elsif ($key eq "paths") { foreach $dir (split(/\s+|,/, $value)) { $dir =~ /(\!)?(\w+)\\(.*)$/; $bang = $1; $depot = $2; $dir = $3; &PathFixup($dir); if ($bang) { push(@{$config->{'ignore_paths'}->{$depot}}, $dir); } else { push(@{$config->{'paths'}->{$depot}}, $dir); } } } else { $$config{$key} = $value; } } close(FILE); } else { print "Couldn't open $file for reading: $!\n"; } } sub PrintUsage() { print << " EOPU"; srcwatch.pl [-f file] -s mm/dd/yyyy - The start date of the period you want a listing for. -e mm/dd/yyyy - The end date of the period you want a listing for. -f file - Use file to read config info. If omitted, srcwatch.txt is assumed. The config file looks like: targets = jasonsch from = jasonsch paths = core advcore\\duser !core\\ntgdi !core\\cslpk groupname = NTUSER group = dwaynen gerardob hiroyama jasonsch jeffbog jstall markfi mhamid msadek lab = lab06_dev branches = ntuser premonition = 1 EOPU exit(0); } sub PathFixup($) { $_[0] =~ s#\\#/#g; } sub InOurView($$$) { my $branch = lc(shift()); # the branch the file was in my $config = shift; my $ip = shift; # ignore "premonition" feature my $fRet = 0; if (!$ip && $$config{'premonition'}) { $fRet = 1; } else { if($branch ne $$config{'lab'}) { foreach (split(/\s+/, $$config{'branches'})) { if ($branch eq lc($_)) { $fRet = 1; } } } else { $fRet = 1; } } $fRet; } sub InitHtmlText($$) { my $config = shift; my $dc = shift; my $date = ""; my $dh = ""; # depot column heading, if needed $dh = "Depot" if ($dc > 1); $text .= << " EOHTML"; srcwatch report $dh EOHTML } __END__
WhoChange #DateLabDescriptionFiles