#
# Script for generating code review pages similar to those generated by
# ON's webrev tool
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License"). You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# FIXMEs:
# - require the target dir to be empty
# - breaks if you have a new subdir that is not under svn control
# - should have a way to exclude some or all not-svn-controlled files
use strict;
use Fcntl;
#
#
# creates the html report of changed in the current svn workspace (current dir)
#
# FIXME: would be nice to turn these into command line options
# max number of chars in each line, above which lines are wrapped in
# side-by-side diffs
my $SDIFF_MAX_LINE=80;
# number of lines of context in sdiffs
my $SDIFF_CONTEXT=20;
# Valid @FOO@ tags in the HTML templates:
#
# @TITLE@ - page title
# @AUTHOR@ - real name of the current user according to the passwd entry
# @COPYRIGHT@ - copyright statement (not implemented)
# @UNAME@ - current user name
#
# HTML page header template for index.html
my $index_page_header =
'<HTML>\n' .
' <HEAD>\n' .
' <TITLE>@TITLE@</TITLE>\n' .
' <META NAME="author" CONTENT="@AUTHOR@">\n' .
' <META NAME="generator" CONTENT="webrev for svn">\n' .
# ' <META NAME="copyright" CONTENT="@COPYRIGHT@">\n' .
' </HEAD>\n' .
' <BODY BGCOLOR="#FFFFFF">\n' .
' <FONT FACE="arial,sans">\n' .
' <CENTER><FONT SIZE=+1><B>@TITLE@</B></FONT></CENTER><P>\n';
# HTML page footer template for index.html
my $index_page_footer =
' </FONT>\n' .
' <HR SIZE=1 NOSHADE>\n' .
' <FONT FACE="arial,sans" SIZE="-2">\n' .
' Webrev report generated by @UNAME@@@HOSTNAME@ on @DATE@.\n' .
' </FONT>\n' .
' </BODY>\n' .
'</HTML>\n';
# HTML page header template for the diff pages
# HTML page footer template for the diff pages
# Map status to file name
my %file_status;
# Descriptions of file status flags
'A', 'New',
'C', '<FONT COLOR="#FF4444">Conflicted</FONT>',
'D', 'Deleted',
'G', 'Merged',
'I', 'Ignored',
'M', 'Modified',
'R', 'Replaced',
'?', '<FONT COLOR="#FF4444">Not under version control</FONT>',
'!', 'Missing');
# Map property change status to file name
# FIXME: currently these are not used, but should be.
my %file_prop;
# Descriptions of file status flags
'C', 'Conflicted',
'M', 'Modified');
my $scm;
my %file_hist;
my $overwrite = O_EXCL;
my $msg = shift;
exit (1);
}
my $msg = shift;
}
my $msg = shift;
}
# fill the %file_status map based on svn status / cvs status output
$file_status{$7} = $1;
$file_prop{$7} = $2;
$file_hist{$7} = $4;
} else {
}
}
# map CVS status names to svn status flags
'Locally Modified', 'M',
'Needs Merge', 'M',
'Needs Checkout', '!',
'File had conflicts on merge', 'C');
my @lines = `LC_ALL=C cvs -z3 status 2>&1 | egrep '(^\\? |^cvs status: Examining |Status:)' | grep -v Up-to-date`
}
}
my $f0 = $1;
}
} else {
}
} else {
}
}
}
}
# fill in values in the HTML templates
my $uname;
my $author;
my $hostname;
my $str = shift;
my $title = shift;
}
}
}
$str =~ s/\\n/\n/g;
return $str;
}
# replace html special chars with corresponding entities
my $str = shift;
$str =~ s/\t/ /g;
return $str;
}
my $webrev_dir = shift;
my $file = shift;
if ($? != 0) {
return 0;
}
return 1;
}
my $webrev_dir = shift;
my $file = shift;
if ($? != 0) {
}
}
my $webrev_dir = shift;
my $file = shift;
if ($? != 0) {
return undef;
}
if ($? != 0) {
return undef;
}
if ($? != 0) {
return undef;
}
system ("cd $webrev_dir/tmp && LC_ALL=C cvs -q -z3 -d $CVSROOT co -r$rev $REPO/$basename >/dev/null 2>&1 && mv $REPO/$basename $webrev_dir/$file/old.$basename && cd / && rm -rf $webrev_dir/tmp");
if ($? != 0) {
return undef;
}
}
}
# create the unified diff page and return the [udiff] link
my $webrev_dir = shift;
my $file = shift;
my @diff;
}
if ($? != 0) {
return undef;
}
} else {
}
}
}
# create the context diff page and return the [cdiff] link
my $webrev_dir = shift;
my $file = shift;
}
}
if ($? != 0) {
return undef;
}
} else {
}
}
}
# add a line to the array representing either the left of the right side
# of an sdiff. Lines are wrapped if longer than $SDIFF_MAX_LINE
# returns the number of lines actually added to the array
#
# $ref is a reference to the array
# $start is printed before the line
# $line is the line itself
# $end is printed to the end of the line
# $indent_len is the number of chars to indent wrapped lines (because of the
# line numbers
my $ref = shift;
my $start = shift;
my $line = shift;
my $end = shift;
my $indent_len = shift;
return 1;
}
my $l = 0;
$l++;
$l++;
}
$l++;
return $l;
}
my $ref = shift;
my $len = shift;
$len--;
}
# push (@$ref, "<PRE STYLE=\"margin: 1pt\">$line</PRE>");
}
my $ref = shift;
my $len = shift;
$len--;
}
}
# generate the sdiff page and return the [sdiff] link
my $webrev_dir = shift;
my $file = shift;
# we're going to work from a unified diff between the old and the new files
# make sure they exist
}
}
$total_lines++;
# the 1st 2 lines are the file names
# line numbers on the left and right side
my $left_line;
my $right_line;
# start of a block
next;
}
# new lines added to the file: print them on the right side in blue
# print an equal number of blank lines on the left side
next;
}
# lines deleted
my @dellines;
}
# if deleted lines are immediately followed by added lines,
# then some of the deleted lines are actually changed lines.
# print them in blue on both sides
my $line1 = $1;
$n1--;
$n2--;
$n1 = 0;
} else {
$n2 = 0;
}
} else {
# no deleted lines: print the new lines on the right side
}
}
# deleted lines remain, print them in brown on the left side
}
# unchanged (context) lines
} else {
next;
}
# fetch the next line if exists
}
}
# write out the report
if ($? != 0) {
return undef;
}
my $col = 1;
} else {
}
}
$col = 1;
} else {
}
}
}
my $webrev_dir = shift;
my $file = shift;
system ("rm -f $webrev_dir/$file/$basename.diff; svn --non-interactive diff $file > $webrev_dir/$file/$basename.diff");
system ("rm -f $webrev_dir/$file/$basename.diff; cvs -q diff -up $file > $webrev_dir/$file/$basename.diff");
}
if ($? != 0) {
return undef;
}
}
# map ChangeLog entries to files
my %changelog_entry;
# find updated ChangeLog files and extract the entries for each file
my @chlog_lines;
}
} else {
}
# * file: foo bar
my $entry = $1;
my $ecat = $1;
# read all lines until the next
# * file: foo bar
# entry
}
$ecat =~ s/^\s*\*\s*//;
# assign the same entry to each file listed with
# commas before the first :
$ecat = $2;
}
}
}
}
}
}
################ MAIN ###################################################
my $webrev_dir = shift;
if ($? != 0) {
}
print "Finding changed files...\n";
print "Reading ChangeLogs...\n";
my $total_new = 0;
my $total_deleted = 0;
my $total_changed = 0;
my $total_unchanged = 0;
my $total_non_svn = 0;
print "Processing files...\n";
$total_new += $lines;
$total_deleted += $lines;
next if -d $file;
$total_non_svn += $lines;
my $label;
my $changed_lines = `diff -c $webrev_dir/$file/old.$basename $webrev_dir/$file/new.$basename | grep '^! ' | wc -l`;
my $deleted_lines = `diff -c $webrev_dir/$file/old.$basename $webrev_dir/$file/new.$basename | grep '^- ' | wc -l`;
my $new_lines = `diff -c $webrev_dir/$file/old.$basename $webrev_dir/$file/new.$basename | grep '^+ ' | wc -l`;
print INDEX "$new_lines line(s) new / $deleted_lines line(s) deleted / $changed_lines line(s) updated / $unchanged_lines line(s) unchanged\n";
$total_new += $new_lines;
}
print INDEX $changelog_entry{$file};
}
}
print INDEX "<P><B>Total</B>: $total_new line(s) new / $total_deleted line(s) deleted / $total_changed line(s) updated / $total_unchanged line(s) unchanged<BR>\n";
}
print "Done.\n"
}
print "Run this script inside a Subversion or CVS controlled directory\n";
print "to create an html code review document.\n";
print "The argument is a directory where the output is written.\n";
print "The svn or cvs command must be in your PATH and should not\n";
exit(1);
}
if (-d '.svn') {
} elsif (-d 'CVS') {
} else {
}
}
}
}