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