diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/mfc/README | 19 | ||||
-rw-r--r-- | tools/tools/mfc/mfc.pl | 330 |
2 files changed, 349 insertions, 0 deletions
diff --git a/tools/tools/mfc/README b/tools/tools/mfc/README new file mode 100644 index 0000000..1396ae7 --- /dev/null +++ b/tools/tools/mfc/README @@ -0,0 +1,19 @@ +$FreeBSD$ + +Summarize scripts abilities and purposes. + +- mfc.awk: added by jmg + +Takes in a commit message and generates the proper (hopefully) update -j lines +and commit line to do the MFC. + +- mfc.sh: added by des + +A simple shell script to help MFC an entire directory to a branch where it +does not already exist. + +- mfc.pl: added by flz + +A perl script that takes a message-id, a commit mail or a query string and +generates a patchset along with a commit message and a commit script if the +user has commit rights. diff --git a/tools/tools/mfc/mfc.pl b/tools/tools/mfc/mfc.pl new file mode 100644 index 0000000..7bc1997 --- /dev/null +++ b/tools/tools/mfc/mfc.pl @@ -0,0 +1,330 @@ +#! /usr/bin/env perl +# +# mfc - perl script to generate patchsets from commit mail or message-id. +# +# Copyright (c) 2006 Florent Thoumie <flz@FreeBSD.org> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# This perl scripts only uses programs that are part of the base system. +# Since some people use NO_FOO options, here's the list of used programs : +# - cvs +# - fetch +# - perl (with getopt module) +# - nc +# - mkdir, cat, chmod, grep (hopefully everybody has them) +# +# This script is using 3 environment variables : +# - MFCHOME: directory where patches, scripts and commit message will be stored. +# - MFCCVSROOT: alternative CVSROOT used to generate diffs for new/dead files. +# - MFCLOGIN: define this to your freefall login if you have commit rights. +# + +use strict; +use warnings; + +use Env; +use Env qw(MFCHOME MFCLOGIN MFCCVSROOT); +use Getopt::Std; + +my $mfchome = $MFCHOME ? $MFCHOME : "/var/tmp/mfc"; +my $mfclogin = $MFCLOGIN ? $MFCLOGIN : ""; +my $cvsroot = $MFCCVSROOT ? $MFCCVSROOT : ':pserver:anoncvs@anoncvs.at.FreeBSD.org:/home/ncvs'; + +my $version = "0.3"; +my %opt; +my $commit_author; +my $commit_date; +my %mfc_files = ( ); +my %new_files = ( ); +my %dead_files = ( ); +my @logmsg = ( ); +my @commitmail = ( ); +my $commiturl; +my $answer; +my $mfc_func = \&mfc_headers; + +my $first_log_line = 1; + +sub init() +{ + # Look for pre-requisites. + my @reqs = ( "fetch", "cvs", "nc", "mkdir", "cat", "chmod", "grep" ); + my $cmd; + foreach (@reqs) { + $cmd = `which $_`; + die "$_ is missing. Please check pre-requisites." if ($cmd =~ /^$/); + } + + # Parse command-line options. + my $opt_string = 'f:hi:m:s:v'; + getopts( "$opt_string", \%opt ) or usage(); + usage() if !$opt{i} or $opt{h}; +} + +sub usage() +{ + print STDERR << "EOF"; +$0 version $version + +Usage: $0 [-v] -h + $0 [-v] -f file -i id + $0 [-v] -m msg-id -i id + $0 [-v] -s query -i id +Options: + -f file : commit mail file to use ('-' for stdin) + -h : this (help) message + -i id : identifier used to save commit log message and patch + -m msg-id : message-id referring to the original commit + -s query : search commit mail archives (a filename with his revision is a good search) + -v : be a little more verbose +Examples: + $0 -m 200601081417.k08EH4EN027418 -i uscanner + $0 -s "param.h 1.41" -i move_acpi + $0 -f commit.txt -i id + +Please report bugs to: Florent Thoumie <flz\@FreeBSD.org> +EOF + exit 1; +} + +sub previous_revision($) +{ + my ($rev) = @_; + my @rev; + + return 0 if ($rev =~ /^1\.1$/); + @rev = split '\.', $rev; + return undef unless @rev; + if ($rev[-1] == 1) { + pop @rev; + return &previous_revision(join ".", @rev); + } else { + $rev[-1]--; + return join ".", @rev; + } +} + +sub fetch_mail($) +{ + my $msgid = $_[0]; + my @years = ( "current", "2006", "2005", "2004", "2003", "2002", "2001", "2000", "1999", "1998", "1997", "1996", "1995", "1994" ); + my $url = ""; + + $msgid =~ s/<//; + $msgid =~ s/>//; + $msgid =~ s/@.*//; + + foreach (@years) { + $url = `echo "GET http://www.freebsd.org/cgi/mid.cgi?id=$msgid+$_/cvs-all&db=mid" | nc www.freebsd.org 80 | grep getmsg.cgi`; + last if (!($url =~ /^$/)); + } + if ($url =~ /^$/) { + print "No mail found for Message-Id <$msgid>.\n"; + exit 1; + } + $url =~ s/.*HREF="(.*)".*/$1+raw/; + $url =~ s/hub.freebsd.org/www.freebsd.org/; + return $url; +} + +sub search_mail($) +{ + my $query = $_[0]; + + $query =~ s/\s+/+/g; + + my $result = `echo "GET http://www.freebsd.org/cgi/search.cgi?words=$query&max=1&sort=score&index=recent&source=cvs-all HTTP/1.0" | nc www.freebsd.org 80 | grep getmsg.cgi`; + + $result =~ s/.*href="(.*)">.*/http:\/\/www.freebsd.org\/cgi\/$1+raw/; + if ($result =~ /^$/) { + print "No commit mail found for '$query'.\n"; + exit 1; + } + return $result; +} + +sub fetch_diff($) +{ + my $name = $_[0]; + my $old = previous_revision($mfc_files{$name}); + my $new = $mfc_files{$name}; + + if ($new_files{$name} or $dead_files{$name}) { + print " Generating diff for $name using cvs rdiff...\n"; + system("cvs -d $cvsroot rdiff -u -r$old -r$new $name >> $mfchome/$opt{i}/patch 2>/dev/null"); + } else { + print " Fetching diff for $name from cvsweb.freebsd.org...\n"; + system("fetch -q -o - \"http://www.freebsd.org/cgi/cvsweb.cgi/$name.diff?r1=$old&r2=$new\" >> $mfchome/$opt{i}/patch"); + } +} + +sub mfc_headers($) +{ + if ($_[0] =~ /^$/) { + $mfc_func = \&mfc_author; + } else { + # Nothing + } +} + +sub mfc_author($) +{ + if (!($_[0] =~ /^(\S+)\s+(\S+\s\S+\s\S+)$/)) { + die "Can't determine commit author and date."; + } + $commit_author = $1; + $commit_date = $2; + + $mfc_func = \&mfc_modified_files; +} + +sub mfc_modified_files($) +{ + if ($_[0] =~ /^\s+Log:/) { + $mfc_func = \&mfc_log; + } else { + # Nothing + } +} + +sub mfc_log($) +{ + if ($_[0] =~ /^\s*Revision\s+Changes\s+Path\s*$/) { + $mfc_func = \&mfc_revisions; + } else { + push(@logmsg, $_[0]); + } +} + +sub mfc_revisions($) +{ + my $name; + my $rev; + + return if ($_[0] =~ /^$/); + + $_[0] =~ /\s+(\S+)\s+\S+\s+\S+\s+(\S+)/; + $name = $2; + $rev = $1; + $mfc_files{$name} = $rev; + $new_files{$name} = "foo" if ($_[0] =~ /\(new\)$/); + $dead_files{$name} = "foo" if ($_[0] =~ /\(dead\)$/); +} + +init(); + +if ($opt{s}) { + print "Searching commit mail on www.freebsd.org...\n"; + $commiturl = search_mail($opt{s}); + print "Fetching commit mail from www.freebsd.org...\n"; + @commitmail = `fetch -q -o - $commiturl`; +} elsif ($opt{f}) { + open MAIL, $opt{f} || die "Can't open $opt{f} for reading."; + @commitmail = <MAIL>; + close MAIL; +} else { # $opt{m} + print "Fetching commit mail from www.freebsd.org...\n"; + $commiturl = fetch_mail($opt{m}); + @commitmail = `fetch -q -o - $commiturl`; +} + +$mfc_func->($_) foreach (@commitmail); + +die "Doesn't seem you gave me a real commit mail." if ($mfc_func == \&mfc_headers); +die "No file affected by commit?" if (scalar(keys(%mfc_files)) == 0); + +# Create directory and truncate patch file. +system("mkdir -p $mfchome/$opt{i}"); +system("cat /dev/null > $mfchome/$opt{i}/patch"); + +print "Committed by $commit_author on $commit_date.\n"; + +if ($opt{v} or $opt{s}) { + # Print files touched by commit. + print "Files touched by commit:\n"; + print " ", $_, " -> rev ", $mfc_files{$_}, "\n" foreach (keys(%mfc_files)); +} + +if ($opt{s}) { + print "Is it the commit you were looking for ? [Yn] "; + $answer = <STDIN>; + chomp($answer); + if ($answer =~ /^[Nn]$/) { + print "Sorry that I couldn't help you.\n"; + exit 0; + } +} + +# Generating patch. +print "Processing patch...\n"; +fetch_diff($_) foreach (keys(%mfc_files)); + +if ($mfclogin) { + # Create commit message from previous commit message. + print "Processing commit message...\n"; + # Chop empty lines Template lines like "Approved by: (might be dangerous)". + pop(@logmsg) while ($logmsg[$#logmsg] =~ /^\s*$/ or $logmsg[$#logmsg] =~ /^\s\s\w+(\s\w+)*:\s+\w+(\s+\w+)*/); + open MSG, "> $mfchome/$opt{i}/msg" || die "Can't open $mfchome/$opt{i}/msg for writing."; + print MSG "MFC:\n\n"; + + # Append merged file names and revisions to the commit message. + print MSG $_ foreach (@logmsg); + print MSG "\n"; + print MSG " ", $_, ": rev ", $mfc_files{$_}, "\n" foreach (keys(%mfc_files)); + close MSG; + + # Create commit script. + print "Processing commit script...\n"; + open SCRIPT, "> $mfchome/$opt{i}/script" || die "Can't open $mfchome/$opt{i}/script for writing."; + print SCRIPT "#! /bin/sh\n\n"; + print SCRIPT "# This script has been automatically generated by $0.\n\n"; + print SCRIPT "export CVSROOT=\"$mfclogin\@ncvs.freebsd.org:/home/ncvs\"\n\n"; + + if (scalar(keys(%new_files)) or scalar(keys(%dead_files))) { + if (scalar(keys(%new_files))) { + print SCRIPT "cvs add"; + print SCRIPT " \\\n $_" foreach (keys(%new_files)); + print SCRIPT "\n"; + } + if (scalar(keys(%dead_files))) { + print SCRIPT "cvs rm -f"; + print SCRIPT " \\\n $_" foreach (keys(%dead_files)); + print SCRIPT "\n"; + } + } + + print SCRIPT "cvs ci"; + print SCRIPT " \\\n $_" foreach (keys(%mfc_files)); + print SCRIPT "\n"; + + close SCRIPT; + system("chmod a+x $mfchome/$opt{i}/script"); +} + +print "Done, output directory is $mfchome/$opt{i}/\n"; + +exit 0; |