191501Sjoe#!/usr/bin/perl -w 291501Sjoe 391501Sjoe# $FreeBSD$ 491501Sjoe 591501Sjoe# This script walks the tree from the current directory 691501Sjoe# and spits out a database generated by md5'ing the cvs log 791501Sjoe# messages of each revision of every file in the tree. 891501Sjoe 991501Sjoeuse strict; 1091501Sjoeuse Digest::MD5 qw(md5_hex); 1191501Sjoe 1291501Sjoemy $dbname = "commitsdb"; 1391501Sjoeopen DB, "> $dbname" or die "$!\n"; 1491501Sjoe 1591501Sjoe# Extract all the logs for the current directory. 1691501Sjoemy @dirs = "."; 1791501Sjoewhile (@dirs) { 1891501Sjoe my $dir = shift @dirs; 1991501Sjoe my %logs; 2091501Sjoe 2191501Sjoe opendir DIR, $dir or die $!; 22105334Sjoe foreach my $f (grep { /[^\.]/ } readdir DIR) { 23105334Sjoe my $filename = "$dir/$f"; 2491501Sjoe if (-f $filename) { 2591501Sjoe my %loghash = parse_log_message($filename); 2691501Sjoe next unless %loghash; 2791501Sjoe 2891501Sjoe $logs{$filename} = {%loghash}; 29105334Sjoe } elsif (-d $filename) { 30105334Sjoe next if $filename =~ /\/CVS$/; 31105334Sjoe push @dirs, $filename; 3291501Sjoe } 3391501Sjoe } 3491501Sjoe close DIR; 3591501Sjoe 36105334Sjoe # Produce a database of the commits 3791501Sjoe foreach my $f (keys %logs) { 3891501Sjoe my $file = $logs{$f}; 3991501Sjoe foreach my $rev (keys %$file) { 4091501Sjoe my $hash = $$file{$rev}; 4191501Sjoe 4291501Sjoe print DB "$f $rev $hash\n"; 4391501Sjoe } 4491501Sjoe } 4591501Sjoe 4691501Sjoe print "\r" . " " x 30 . "\r$dir"; 4791501Sjoe} 4891501Sjoeprint "\n"; 4991501Sjoe 5091501Sjoeclose DB; 5191501Sjoe 5291501Sjoe 5391501Sjoe 5491501Sjoe################################################## 5591501Sjoe# Run a cvs log on a file and return a parse entry. 5691501Sjoe################################################## 5791501Sjoesub parse_log_message { 5891501Sjoe my $file = shift; 5991501Sjoe 6091501Sjoe # Get a log of the file. 61105334Sjoe open LOG, "cvs -R log $file 2>/dev/null |" or die $!; 6291501Sjoe my @log = <LOG>; 6391501Sjoe my $log = join "", @log; 6491501Sjoe close LOG; 6591501Sjoe 6691501Sjoe # Split the log into revisions. 6791501Sjoe my @entries = split /----------------------------\n/, $log; 6891501Sjoe 6991501Sjoe # Throw away the first entry. 7091501Sjoe shift @entries; 7191501Sjoe 7291501Sjoe # Record the hash of the message against the revision. 7391501Sjoe my %loghash = (); 7491501Sjoe foreach my $e (@entries) { 7591501Sjoe # Get the revision number 7691501Sjoe $e =~ s/^revision\s*(\S*)\n//s; 7791501Sjoe my $rev = $1; 7891501Sjoe 7991501Sjoe # Strip off any other headers. 80105334Sjoe my $user; 81105334Sjoe while ($e =~ s/^(date|branches):([^\n]*)\n//sg) { 82105334Sjoe my $sub = $2; 83105334Sjoe $user = $1 if $sub =~ /author: (.*?);/; 8491501Sjoe }; 8591501Sjoe 8691501Sjoe my $hash = string_to_hash($e); 87105334Sjoe $loghash{$rev} = "$user:$hash"; 8891501Sjoe } 8991501Sjoe 9091501Sjoe return %loghash; 9191501Sjoe} 9291501Sjoe 9391501Sjoe 9491501Sjoe################################################## 9591501Sjoe# Convert a log message into an md5 checksum. 9691501Sjoe################################################## 9791501Sjoesub string_to_hash { 9891501Sjoe my $logmsg = shift; 9991501Sjoe 10091501Sjoe return md5_hex($logmsg); 10191501Sjoe} 10291501Sjoe 10391501Sjoe 10491501Sjoe 10591501Sjoe#end 106