diff --git a/tools/tools/README b/tools/tools/README index 0d47beb92cf0..6bdc8c4f0897 100644 --- a/tools/tools/README +++ b/tools/tools/README @@ -7,6 +7,8 @@ other categories. Please make a subdir per program, and add a brief description to this file. +commitsdb A tool for reconstructing commit history using md5 + checksums of the commit logs. editing Editor modes and the like to help editing FreeBSD code. epfe Extract printing filter examples from printing.sgml. html-mv Rename HTML generated filenames to human readable filenames. diff --git a/tools/tools/commitsdb/make_commit_db b/tools/tools/commitsdb/make_commit_db new file mode 100644 index 000000000000..7b0fee780c78 --- /dev/null +++ b/tools/tools/commitsdb/make_commit_db @@ -0,0 +1,102 @@ +#!/usr/bin/perl -w + +# $FreeBSD$ + +# This script walks the tree from the current directory +# and spits out a database generated by md5'ing the cvs log +# messages of each revision of every file in the tree. + +use strict; +use Digest::MD5 qw(md5_hex); + +my $dbname = "commitsdb"; +open DB, "> $dbname" or die "$!\n"; + +# Extract all the logs for the current directory. +my @dirs = "."; +while (@dirs) { + my $dir = shift @dirs; + my %logs; + + opendir DIR, $dir or die $!; + foreach (grep { /[^\.]/ } readdir DIR) { + my $filename = "$dir/$_"; + if (-f $filename) { + my %loghash = parse_log_message($filename); + next unless %loghash; + + $logs{$filename} = {%loghash}; + } elsif (-d $_) { + next if /^CVS$/; + push @dirs, $_; + } + } + close DIR; + + # Product a database of the commits + foreach my $f (keys %logs) { + my $file = $logs{$f}; + foreach my $rev (keys %$file) { + my $hash = $$file{$rev}; + + print DB "$f $rev $hash\n"; + } + } + + print "\r" . " " x 30 . "\r$dir"; +} +print "\n"; + +close DB; + + + +################################################## +# Run a cvs log on a file and return a parse entry. +################################################## +sub parse_log_message { + my $file = shift; + + # Get a log of the file. + open LOG, "cvs -R log $file |" or die $!; + my @log = ; + my $log = join "", @log; + close LOG; + + # Split the log into revisions. + my @entries = split /----------------------------\n/, $log; + + # Throw away the first entry. + shift @entries; + + # Record the hash of the message against the revision. + my %loghash = (); + foreach my $e (@entries) { + # Get the revision number + $e =~ s/^revision\s*(\S*)\n//s; + my $rev = $1; + + # Strip off any other headers. + while ($e =~ s/^(date|branches):[^\n]*\n//sg) { + }; + + my $hash = string_to_hash($e); + $loghash{$rev} = $hash; + } + + return %loghash; +} + + +################################################## +# Convert a log message into an md5 checksum. +################################################## +sub string_to_hash { + my $logmsg = shift; + + return md5_hex($logmsg); +} + + + +#end diff --git a/tools/tools/commitsdb/query_commit_db b/tools/tools/commitsdb/query_commit_db new file mode 100644 index 000000000000..f753f327b898 --- /dev/null +++ b/tools/tools/commitsdb/query_commit_db @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w + +# $FreeBSD$ + +# This script takes a filename and revision number as arguments +# and spits out a list of other files and their revisions that share +# the same log message. This is done by referring to the database +# previously written by running make_commit_db. + +use strict; +use Digest::MD5 qw(md5_hex); + +my $dbname = "commitsdb"; + +# Take the filename and revision number from the command line. +my ($file, $revision) = (shift, shift); + +# Find the checksum of the named revision. +my %possible_files; +open DB, "< $dbname" or die "$!\n"; +my $cksum; +while () { + chomp; + my ($name, $rev, $hash) = split; + $name =~ s/^\.\///g; + + $possible_files{$name} = 1 if $file !~ /\// && $name =~ /^.*\/$file/; + + next unless $name eq $file and $rev eq $revision; + $cksum = $hash; +} +close DB; + +# Handle the fall-out if the file/revision wasn't matched. +unless ($cksum) { + if (%possible_files) { + print "Couldn't find the file. Maybe you meant:\n"; + foreach (sort keys %possible_files) { + print "\t$_\n"; + } + } + die "Can't find $file rev $revision in database\n"; +} + + +# Look for similar revisions. +my @results; +open DB, "< $dbname" or die "$!\n"; +while () { + chomp; + my ($name, $rev, $hash) = split; + + next unless $hash eq $cksum; + + push @results, "$name $rev"; +} +close DB; + +print map { "$_\n" } sort @results; + +#end