summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/mfc/README19
-rw-r--r--tools/tools/mfc/mfc.pl330
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;
OpenPOWER on IntegriCloud