312N/A#!/bin/ksh -p
312N/A#
312N/A# CDDL HEADER START
312N/A#
312N/A# The contents of this file are subject to the terms of the
312N/A# Common Development and Distribution License (the "License").
312N/A# You may not use this file except in compliance with the License.
312N/A#
312N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
312N/A# or http://www.opensolaris.org/os/licensing.
312N/A# See the License for the specific language governing permissions
312N/A# and limitations under the License.
312N/A#
312N/A# When distributing Covered Code, include this CDDL HEADER in each
312N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
312N/A# If applicable, add the following below this CDDL HEADER, with the
312N/A# fields enclosed by brackets "[]" replaced with your own identifying
312N/A# information: Portions Copyright [yyyy] [name of copyright owner]
312N/A#
312N/A# CDDL HEADER END
312N/A#
607N/A# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
312N/A# Use is subject to license terms.
312N/A#
312N/A# This script takes a file list and a workspace and builds a set of html files
312N/A# suitable for doing a code review of source changes via a web page.
312N/A# Documentation is available via 'webrev -h'.
312N/A#
312N/A
607N/AWEBREV_UPDATED=23.18-hg+jbs
312N/A
312N/AHTML='<?xml version="1.0"?>
312N/A<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
312N/A "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
312N/A<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
312N/A
312N/AFRAMEHTML='<?xml version="1.0"?>
312N/A<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
312N/A "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
312N/A<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
312N/A
312N/ASTDHEAD='<meta http-equiv="cache-control" content="no-cache" />
312N/A<meta http-equiv="Pragma" content="no-cache" />
312N/A<meta http-equiv="Expires" content="-1" />
312N/A<!--
312N/A Note to customizers: the body of the webrev is IDed as SUNWwebrev
312N/A to allow easy overriding by users of webrev via the userContent.css
312N/A mechanism available in some browsers.
312N/A
312N/A For example, to have all "removed" information be red instead of
312N/A brown, set a rule in your userContent.css file like:
312N/A
312N/A body#SUNWwebrev span.removed { color: red ! important; }
312N/A-->
312N/A<style type="text/css" media="screen">
312N/Abody {
312N/A background-color: #eeeeee;
312N/A}
312N/Ahr {
312N/A border: none 0;
312N/A border-top: 1px solid #aaa;
312N/A height: 1px;
312N/A}
312N/Adiv.summary {
312N/A font-size: .8em;
312N/A border-bottom: 1px solid #aaa;
312N/A padding-left: 1em;
312N/A padding-right: 1em;
312N/A}
312N/Adiv.summary h2 {
312N/A margin-bottom: 0.3em;
312N/A}
312N/Adiv.summary table th {
312N/A text-align: right;
312N/A vertical-align: top;
312N/A white-space: nowrap;
312N/A}
312N/Aspan.lineschanged {
312N/A font-size: 0.7em;
312N/A}
312N/Aspan.oldmarker {
312N/A color: red;
312N/A font-size: large;
312N/A font-weight: bold;
312N/A}
312N/Aspan.newmarker {
312N/A color: green;
312N/A font-size: large;
312N/A font-weight: bold;
312N/A}
312N/Aspan.removed {
312N/A color: brown;
312N/A}
312N/Aspan.changed {
312N/A color: blue;
312N/A}
312N/Aspan.new {
312N/A color: blue;
312N/A font-weight: bold;
312N/A}
312N/Aa.print { font-size: x-small; }
312N/A
312N/A</style>
312N/A
312N/A<style type="text/css" media="print">
312N/Apre { font-size: 0.8em; font-family: courier, monospace; }
312N/Aspan.removed { color: #444; font-style: italic }
312N/Aspan.changed { font-weight: bold; }
312N/Aspan.new { font-weight: bold; }
312N/Aspan.newmarker { font-size: 1.2em; font-weight: bold; }
312N/Aspan.oldmarker { font-size: 1.2em; font-weight: bold; }
312N/Aa.print {display: none}
312N/Ahr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
312N/A</style>
312N/A'
312N/A
312N/A#
312N/A# UDiffs need a slightly different CSS rule for 'new' items (we don't
312N/A# want them to be bolded as we do in cdiffs or sdiffs).
312N/A#
312N/AUDIFFCSS='
312N/A<style type="text/css" media="screen">
312N/Aspan.new {
312N/A color: blue;
312N/A font-weight: normal;
312N/A}
312N/A</style>
312N/A'
312N/A
312N/A#
312N/A# input_cmd | html_quote | output_cmd
312N/A# or
312N/A# html_quote filename | output_cmd
312N/A#
312N/A# Make a piece of source code safe for display in an HTML <pre> block.
312N/A#
312N/Ahtml_quote()
312N/A{
312N/A sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
312N/A}
312N/A
312N/A#
312N/A# input_cmd | bug2url | output_cmd
312N/A#
312N/A# Scan for bugids and insert <a> links to the relevent bug database.
312N/A#
312N/Abug2url()
312N/A{
607N/A sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL$IDPREFIX'&\">&</a>|g'
312N/A}
312N/A
312N/A#
312N/A# input_cmd | sac2url | output_cmd
312N/A#
312N/A# Scan for ARC cases and insert <a> links to the relevent SAC database.
312N/A# This is slightly complicated because inside the SWAN, SAC cases are
312N/A# grouped by ARC: PSARC/2006/123. But on OpenSolaris.org, they are
312N/A# referenced as 2006/123 (without labelling the ARC).
312N/A#
312N/Asac2url()
312N/A{
312N/A if [[ -z $Oflag ]]; then
312N/A sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'\1/\2/\3\">\1 \2/\3</a>|g'
312N/A else
312N/A sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
312N/A fi
312N/A}
312N/A
312N/A#
312N/A# strip_unchanged <infile> | output_cmd
312N/A#
312N/A# Removes chunks of sdiff documents that have not changed. This makes it
312N/A# easier for a code reviewer to find the bits that have changed.
312N/A#
312N/A# Deleted lines of text are replaced by a horizontal rule. Some
312N/A# identical lines are retained before and after the changed lines to
312N/A# provide some context. The number of these lines is controlled by the
312N/A# variable C in the $AWK script below.
312N/A#
312N/A# The script detects changed lines as any line that has a "<span class="
312N/A# string embedded (unchanged lines have no particular class and are not
312N/A# part of a <span>). Blank lines (without a sequence number) are also
312N/A# detected since they flag lines that have been inserted or deleted.
312N/A#
312N/Astrip_unchanged()
312N/A{
312N/A $AWK '
312N/A BEGIN { C = c = 20 }
312N/A NF == 0 || /span class=/ {
312N/A if (c > C) {
312N/A c -= C
312N/A inx = 0
312N/A if (c > C) {
312N/A print "\n</pre><hr></hr><pre>"
312N/A inx = c % C
312N/A c = C
312N/A }
312N/A
312N/A for (i = 0; i < c; i++)
312N/A print ln[(inx + i) % C]
312N/A }
312N/A c = 0;
312N/A print
312N/A next
312N/A }
312N/A { if (c >= C) {
312N/A ln[c % C] = $0
312N/A c++;
312N/A next;
312N/A }
312N/A c++;
312N/A print
312N/A }
312N/A END { if (c > (C * 2)) print "\n</pre><hr></hr>" }
312N/A
312N/A ' $1
312N/A}
312N/A
312N/A#
312N/A# sdiff_to_html
312N/A#
312N/A# This function takes two files as arguments, obtains their diff, and
312N/A# processes the diff output to present the files as an HTML document with
312N/A# the files displayed side-by-side, differences shown in color. It also
312N/A# takes a delta comment, rendered as an HTML snippet, as the third
312N/A# argument. The function takes two files as arguments, then the name of
312N/A# file, the path, and the comment. The HTML will be delivered on stdout,
312N/A# e.g.
312N/A#
312N/A# $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
312N/A# new/usr/src/tools/scripts/webrev.sh \
312N/A# webrev.sh usr/src/tools/scripts \
607N/A# '<a href="https://jbs.oracle.com/bugs/browse/JDK-1234567">
607N/A# JDK-1234567</a> my bugid' > <file>.html
312N/A#
312N/A# framed_sdiff() is then called which creates $2.frames.html
312N/A# in the webrev tree.
312N/A#
312N/A# FYI: This function is rather unusual in its use of awk. The initial
312N/A# diff run produces conventional diff output showing changed lines mixed
312N/A# with editing codes. The changed lines are ignored - we're interested in
312N/A# the editing codes, e.g.
312N/A#
312N/A# 8c8
312N/A# 57a61
312N/A# 63c66,76
312N/A# 68,93d80
312N/A# 106d90
312N/A# 108,110d91
312N/A#
312N/A# These editing codes are parsed by the awk script and used to generate
312N/A# another awk script that generates HTML, e.g the above lines would turn
312N/A# into something like this:
312N/A#
312N/A# BEGIN { printf "<pre>\n" }
312N/A# function sp(n) {for (i=0;i<n;i++)printf "\n"}
312N/A# function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
312N/A# NR==8 {wl("#7A7ADD");next}
312N/A# NR==54 {wl("#7A7ADD");sp(3);next}
312N/A# NR==56 {wl("#7A7ADD");next}
312N/A# NR==57 {wl("black");printf "\n"; next}
312N/A# : :
312N/A#
312N/A# This script is then run on the original source file to generate the
312N/A# HTML that corresponds to the source file.
312N/A#
312N/A# The two HTML files are then combined into a single piece of HTML that
312N/A# uses an HTML table construct to present the files side by side. You'll
312N/A# notice that the changes are color-coded:
312N/A#
312N/A# black - unchanged lines
312N/A# blue - changed lines
312N/A# bold blue - new lines
312N/A# brown - deleted lines
312N/A#
312N/A# Blank lines are inserted in each file to keep unchanged lines in sync
312N/A# (side-by-side). This format is familiar to users of sdiff(1) or
312N/A# Teamware's filemerge tool.
312N/A#
312N/Asdiff_to_html()
312N/A{
312N/A diff -b $1 $2 > /tmp/$$.diffs
312N/A
312N/A TNAME=$3
312N/A TPATH=$4
312N/A COMMENT=$5
312N/A
312N/A #
312N/A # Now we have the diffs, generate the HTML for the old file.
312N/A #
312N/A $AWK '
312N/A BEGIN {
312N/A printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
312N/A printf "function removed() "
312N/A printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
312N/A printf "function changed() "
312N/A printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
312N/A printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
312N/A}
312N/A /^</ {next}
312N/A /^>/ {next}
312N/A /^---/ {next}
312N/A
312N/A {
312N/A split($1, a, /[cad]/) ;
312N/A if (index($1, "a")) {
312N/A if (a[1] == 0) {
312N/A n = split(a[2], r, /,/);
312N/A if (n == 1)
312N/A printf "BEGIN\t\t{sp(1)}\n"
312N/A else
312N/A printf "BEGIN\t\t{sp(%d)}\n",\
312N/A (r[2] - r[1]) + 1
312N/A next
312N/A }
312N/A
312N/A printf "NR==%s\t\t{", a[1]
312N/A n = split(a[2], r, /,/);
312N/A s = r[1];
312N/A if (n == 1)
312N/A printf "bl();printf \"\\n\"; next}\n"
312N/A else {
312N/A n = r[2] - r[1]
312N/A printf "bl();sp(%d);next}\n",\
312N/A (r[2] - r[1]) + 1
312N/A }
312N/A next
312N/A }
312N/A if (index($1, "d")) {
312N/A n = split(a[1], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A if (n == 1)
312N/A printf "NR==%s\t\t{removed(); next}\n" , n1
312N/A else
312N/A printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
312N/A next
312N/A }
312N/A if (index($1, "c")) {
312N/A n = split(a[1], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A final = n2
312N/A d1 = 0
312N/A if (n == 1)
312N/A printf "NR==%s\t\t{changed();" , n1
312N/A else {
312N/A d1 = n2 - n1
312N/A printf "NR==%s,NR==%s\t{changed();" , n1, n2
312N/A }
312N/A m = split(a[2], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A if (m > 1) {
312N/A d2 = n2 - n1
312N/A if (d2 > d1) {
312N/A if (n > 1) printf "if (NR==%d)", final
312N/A printf "sp(%d);", d2 - d1
312N/A }
312N/A }
312N/A printf "next}\n" ;
312N/A
312N/A next
312N/A }
312N/A }
312N/A
312N/A END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
312N/A ' /tmp/$$.diffs > /tmp/$$.file1
312N/A
312N/A #
312N/A # Now generate the HTML for the new file
312N/A #
312N/A $AWK '
312N/A BEGIN {
312N/A printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
312N/A printf "function new() "
312N/A printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
312N/A printf "function changed() "
312N/A printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
312N/A printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
312N/A }
312N/A
312N/A /^</ {next}
312N/A /^>/ {next}
312N/A /^---/ {next}
312N/A
312N/A {
312N/A split($1, a, /[cad]/) ;
312N/A if (index($1, "d")) {
312N/A if (a[2] == 0) {
312N/A n = split(a[1], r, /,/);
312N/A if (n == 1)
312N/A printf "BEGIN\t\t{sp(1)}\n"
312N/A else
312N/A printf "BEGIN\t\t{sp(%d)}\n",\
312N/A (r[2] - r[1]) + 1
312N/A next
312N/A }
312N/A
312N/A printf "NR==%s\t\t{", a[2]
312N/A n = split(a[1], r, /,/);
312N/A s = r[1];
312N/A if (n == 1)
312N/A printf "bl();printf \"\\n\"; next}\n"
312N/A else {
312N/A n = r[2] - r[1]
312N/A printf "bl();sp(%d);next}\n",\
312N/A (r[2] - r[1]) + 1
312N/A }
312N/A next
312N/A }
312N/A if (index($1, "a")) {
312N/A n = split(a[2], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A if (n == 1)
312N/A printf "NR==%s\t\t{new() ; next}\n" , n1
312N/A else
312N/A printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
312N/A next
312N/A }
312N/A if (index($1, "c")) {
312N/A n = split(a[2], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A final = n2
312N/A d2 = 0;
312N/A if (n == 1) {
312N/A final = n1
312N/A printf "NR==%s\t\t{changed();" , n1
312N/A } else {
312N/A d2 = n2 - n1
312N/A printf "NR==%s,NR==%s\t{changed();" , n1, n2
312N/A }
312N/A m = split(a[1], r, /,/);
312N/A n1 = r[1]
312N/A n2 = r[2]
312N/A if (m > 1) {
312N/A d1 = n2 - n1
312N/A if (d1 > d2) {
312N/A if (n > 1) printf "if (NR==%d)", final
312N/A printf "sp(%d);", d1 - d2
312N/A }
312N/A }
312N/A printf "next}\n" ;
312N/A next
312N/A }
312N/A }
312N/A END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
312N/A ' /tmp/$$.diffs > /tmp/$$.file2
312N/A
312N/A #
312N/A # Post-process the HTML files by running them back through $AWK
312N/A #
312N/A html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
312N/A
312N/A html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
312N/A
312N/A #
312N/A # Now combine into a valid HTML file and side-by-side into a table
312N/A #
312N/A print "$HTML<head>$STDHEAD"
312N/A print "<title>$WNAME Sdiff $TPATH </title>"
312N/A print "</head><body id=\"SUNWwebrev\">"
312N/A print "<h2>$TPATH/$TNAME</h2>"
312N/A print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
312N/A print "<pre>$COMMENT</pre>\n"
312N/A print "<table><tr valign=\"top\">"
312N/A print "<td><pre>"
312N/A
312N/A strip_unchanged /tmp/$$.file1.html
312N/A
312N/A print "</pre></td><td><pre>"
312N/A
312N/A strip_unchanged /tmp/$$.file2.html
312N/A
312N/A print "</pre></td>"
312N/A print "</tr></table>"
312N/A print "</body></html>"
312N/A
312N/A framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
312N/A "$COMMENT"
312N/A}
312N/A
312N/A
312N/A#
312N/A# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
312N/A#
312N/A# Expects lefthand and righthand side html files created by sdiff_to_html.
312N/A# We use insert_anchors() to augment those with HTML navigation anchors,
312N/A# and then emit the main frame. Content is placed into:
312N/A#
312N/A# $WDIR/DIR/$TNAME.lhs.html
312N/A# $WDIR/DIR/$TNAME.rhs.html
312N/A# $WDIR/DIR/$TNAME.frames.html
312N/A#
312N/A# NOTE: We rely on standard usage of $WDIR and $DIR.
312N/A#
312N/Afunction framed_sdiff
312N/A{
312N/A typeset TNAME=$1
312N/A typeset TPATH=$2
312N/A typeset lhsfile=$3
312N/A typeset rhsfile=$4
312N/A typeset comments=$5
312N/A typeset RTOP
312N/A
312N/A # Enable html files to access WDIR via a relative path.
312N/A RTOP=$(relative_dir $TPATH $WDIR)
312N/A
312N/A # Make the rhs/lhs files and output the frameset file.
312N/A print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
312N/A
312N/A cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
312N/A <script type="text/javascript" src="$RTOP/ancnav.js"></script>
312N/A </head>
312N/A <body id="SUNWwebrev" onkeypress="keypress(event);">
312N/A <a name="0"></a>
312N/A <pre>$comments</pre><hr></hr>
312N/A EOF
312N/A
312N/A cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
312N/A
312N/A insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
312N/A insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
312N/A
312N/A close='</body></html>'
312N/A
312N/A print $close >> $WDIR/$DIR/$TNAME.lhs.html
312N/A print $close >> $WDIR/$DIR/$TNAME.rhs.html
312N/A
312N/A print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
312N/A print "<title>$WNAME Framed-Sdiff " \
312N/A "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
312N/A cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
312N/A <frameset rows="*,60">
312N/A <frameset cols="50%,50%">
312N/A <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs" />
312N/A <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs" />
312N/A </frameset>
312N/A <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
312N/A marginheight="0" name="nav" />
312N/A <noframes>
312N/A <body id="SUNWwebrev">
312N/A Alas 'frames' webrev requires that your browser supports frames
312N/A and has the feature enabled.
312N/A </body>
312N/A </noframes>
312N/A </frameset>
312N/A </html>
312N/A EOF
312N/A}
312N/A
312N/A
312N/A#
312N/A# fix_postscript
312N/A#
312N/A# Merge codereview output files to a single conforming postscript file, by:
312N/A# - removing all extraneous headers/trailers
312N/A# - making the page numbers right
312N/A# - removing pages devoid of contents which confuse some
312N/A# postscript readers.
312N/A#
312N/A# From Casper.
312N/A#
312N/Afunction fix_postscript
312N/A{
312N/A infile=$1
312N/A
312N/A cat > /tmp/$$.crmerge.pl << \EOF
312N/A
312N/A print scalar(<>); # %!PS-Adobe---
312N/A print "%%Orientation: Landscape\n";
312N/A
312N/A $pno = 0;
312N/A $doprint = 1;
312N/A
312N/A $page = "";
312N/A
312N/A while (<>) {
312N/A next if (/^%%Pages:\s*\d+/);
312N/A
312N/A if (/^%%Page:/) {
312N/A if ($pno == 0 || $page =~ /\)S/) {
312N/A # Header or single page containing text
312N/A print "%%Page: ? $pno\n" if ($pno > 0);
312N/A print $page;
312N/A $pno++;
312N/A } else {
312N/A # Empty page, skip it.
312N/A }
312N/A $page = "";
312N/A $doprint = 1;
312N/A next;
312N/A }
312N/A
312N/A # Skip from %%Trailer of one document to Endprolog
312N/A # %%Page of the next
312N/A $doprint = 0 if (/^%%Trailer/);
312N/A $page .= $_ if ($doprint);
312N/A }
312N/A
312N/A if ($page =~ /\)S/) {
312N/A print "%%Page: ? $pno\n";
312N/A print $page;
312N/A } else {
312N/A $pno--;
312N/A }
312N/A print "%%Trailer\n%%Pages: $pno\n";
312N/AEOF
312N/A
312N/A $PERL /tmp/$$.crmerge.pl < $infile
312N/A}
312N/A
312N/A
312N/A#
312N/A# input_cmd | insert_anchors | output_cmd
312N/A#
312N/A# Flag blocks of difference with sequentially numbered invisible
312N/A# anchors. These are used to drive the frames version of the
312N/A# sdiffs output.
312N/A#
312N/A# NOTE: Anchor zero flags the top of the file irrespective of changes,
312N/A# an additional anchor is also appended to flag the bottom.
312N/A#
312N/A# The script detects changed lines as any line that has a "<span
312N/A# class=" string embedded (unchanged lines have no class set and are
312N/A# not part of a <span>. Blank lines (without a sequence number)
312N/A# are also detected since they flag lines that have been inserted or
312N/A# deleted.
312N/A#
312N/Afunction insert_anchors
312N/A{
312N/A $AWK '
312N/A function ia() {
312N/A # This should be able to be a singleton <a /> but that
312N/A # seems to trigger a bug in firefox a:hover rule processing
312N/A printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
312N/A }
312N/A
312N/A BEGIN {
312N/A anc=1;
312N/A inblock=1;
312N/A printf "<pre>\n";
312N/A }
312N/A NF == 0 || /^<span class=/ {
312N/A if (inblock == 0) {
312N/A ia();
312N/A inblock=1;
312N/A }
312N/A print;
312N/A next;
312N/A }
312N/A {
312N/A inblock=0;
312N/A print;
312N/A }
312N/A END {
312N/A ia();
312N/A
312N/A printf "<b style=\"font-size: large; color: red\">";
312N/A printf "--- EOF ---</b>"
312N/A for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
312N/A printf "</pre>"
312N/A printf "<form name=\"eof\">";
312N/A printf "<input name=\"value\" value=\"%d\" type=\"hidden\" />",
312N/A anc - 1;
312N/A printf "</form>";
312N/A }
312N/A ' $1
312N/A}
312N/A
312N/A
312N/A#
312N/A# relative_dir
312N/A#
312N/A# Print a relative return path from $1 to $2. For example if
312N/A# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
312N/A# this function would print "../../../../".
312N/A#
312N/A# In the event that $1 is not in $2 a warning is printed to stderr,
312N/A# and $2 is returned-- the result of this is that the resulting webrev
312N/A# is not relocatable.
312N/A#
312N/Afunction relative_dir
312N/A{
312N/A d1=$1
312N/A d2=$2
312N/A if [[ "$d1" == "." ]]; then
312N/A print "."
312N/A else
312N/A typeset cur="${d1##$d2?(/)}"
312N/A typeset ret=""
312N/A if [[ $d2 == $cur ]]; then # Should never happen.
312N/A # Should never happen.
312N/A print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
312N/A print -u2 "to \"$2\". Check input paths. Framed webrev "
312N/A print -u2 "will not be relocatable!"
312N/A print $2
312N/A return
312N/A fi
312N/A
312N/A while [[ -n ${cur} ]];
312N/A do
312N/A cur=${cur%%*(/)*([!/])}
312N/A if [[ -z $ret ]]; then
312N/A ret=".."
312N/A else
312N/A ret="../$ret"
312N/A fi
312N/A done
312N/A print $ret
312N/A fi
312N/A}
312N/A
312N/A
312N/A#
312N/A# frame_nav_js
312N/A#
312N/A# Emit javascript for frame navigation
312N/A#
312N/Afunction frame_nav_js
312N/A{
312N/Acat << \EOF
312N/Avar myInt;
312N/Avar scrolling=0;
312N/Avar sfactor = 3;
312N/Avar scount=10;
312N/A
312N/Afunction scrollByPix() {
312N/A if (scount<=0) {
312N/A sfactor*=1.2;
312N/A scount=10;
312N/A }
312N/A parent.lhs.scrollBy(0,sfactor);
312N/A parent.rhs.scrollBy(0,sfactor);
312N/A scount--;
312N/A}
312N/A
312N/Afunction scrollToAnc(num) {
312N/A
312N/A // Update the value of the anchor in the form which we use as
312N/A // storage for this value. setAncValue() will take care of
312N/A // correcting for overflow and underflow of the value and return
312N/A // us the new value.
312N/A num = setAncValue(num);
312N/A
312N/A // Set location and scroll back a little to expose previous
312N/A // lines.
312N/A //
312N/A // Note that this could be improved: it is possible although
312N/A // complex to compute the x and y position of an anchor, and to
312N/A // scroll to that location directly.
312N/A //
312N/A parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
312N/A parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
312N/A
312N/A parent.lhs.scrollBy(0,-30);
312N/A parent.rhs.scrollBy(0,-30);
312N/A}
312N/A
312N/Afunction getAncValue()
312N/A{
312N/A return (parseInt(parent.nav.document.diff.real.value));
312N/A}
312N/A
312N/Afunction setAncValue(val)
312N/A{
312N/A if (val <= 0) {
312N/A val = 0;
312N/A parent.nav.document.diff.real.value = val;
312N/A parent.nav.document.diff.display.value = "BOF";
312N/A return (val);
312N/A }
312N/A
312N/A //
312N/A // The way we compute the max anchor value is to stash it
312N/A // inline in the left and right hand side pages-- it's the same
312N/A // on each side, so we pluck from the left.
312N/A //
312N/A maxval = parent.lhs.document.eof.value.value;
312N/A if (val < maxval) {
312N/A parent.nav.document.diff.real.value = val;
312N/A parent.nav.document.diff.display.value = val.toString();
312N/A return (val);
312N/A }
312N/A
312N/A // this must be: val >= maxval
312N/A val = maxval;
312N/A parent.nav.document.diff.real.value = val;
312N/A parent.nav.document.diff.display.value = "EOF";
312N/A return (val);
312N/A}
312N/A
312N/Afunction stopScroll() {
312N/A if (scrolling==1) {
312N/A clearInterval(myInt);
312N/A scrolling=0;
312N/A }
312N/A}
312N/A
312N/Afunction startScroll() {
312N/A stopScroll();
312N/A scrolling=1;
312N/A myInt=setInterval("scrollByPix()",10);
312N/A}
312N/A
312N/Afunction handlePress(b) {
312N/A
312N/A switch (b) {
312N/A case 1 :
312N/A scrollToAnc(-1);
312N/A break;
312N/A case 2 :
312N/A scrollToAnc(getAncValue() - 1);
312N/A break;
312N/A case 3 :
312N/A sfactor=-3;
312N/A startScroll();
312N/A break;
312N/A case 4 :
312N/A sfactor=3;
312N/A startScroll();
312N/A break;
312N/A case 5 :
312N/A scrollToAnc(getAncValue() + 1);
312N/A break;
312N/A case 6 :
312N/A scrollToAnc(999999);
312N/A break;
312N/A }
312N/A}
312N/A
312N/Afunction handleRelease(b) {
312N/A stopScroll();
312N/A}
312N/A
312N/Afunction keypress(ev) {
312N/A var keynum;
312N/A var keychar;
312N/A
312N/A if (window.event) { // IE
312N/A keynum = ev.keyCode;
312N/A } else if (ev.which) { // non-IE
312N/A keynum = ev.which;
312N/A }
312N/A
312N/A keychar = String.fromCharCode(keynum);
312N/A
312N/A if (keychar == "k") {
312N/A handlePress(2);
312N/A return (0);
312N/A } else if (keychar == "j" || keychar == " ") {
312N/A handlePress(5);
312N/A return (0);
312N/A }
312N/A return (1);
312N/A}
312N/A
312N/Afunction ValidateDiffNum(){
312N/A val = parent.nav.document.diff.display.value;
312N/A if (val == "EOF") {
312N/A scrollToAnc(999999);
312N/A return;
312N/A }
312N/A
312N/A if (val == "BOF") {
312N/A scrollToAnc(0);
312N/A return;
312N/A }
312N/A
312N/A i=parseInt(val);
312N/A if (isNaN(i)) {
312N/A parent.nav.document.diff.display.value = getAncValue();
312N/A } else {
312N/A scrollToAnc(i);
312N/A }
312N/A return false;
312N/A}
312N/A
312N/AEOF
312N/A}
312N/A
312N/A#
312N/A# frame_navigation
312N/A#
312N/A# Output anchor navigation file for framed sdiffs.
312N/A#
312N/Afunction frame_navigation
312N/A{
312N/A print "$HTML<head>$STDHEAD"
312N/A
312N/A cat << \EOF
312N/A<title>Anchor Navigation</title>
312N/A<meta http-equiv="Content-Script-Type" content="text/javascript" />
312N/A<meta http-equiv="Content-Type" content="text/html" />
312N/A
312N/A<style type="text/css">
312N/A div.button td { padding-left: 5px; padding-right: 5px;
312N/A background-color: #eee; text-align: center;
312N/A border: 1px #444 outset; cursor: pointer; }
312N/A div.button a { font-weight: bold; color: black }
312N/A div.button td:hover { background: #ffcc99; }
312N/A</style>
312N/AEOF
312N/A
312N/A print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
312N/A
312N/A cat << \EOF
312N/A</head>
312N/A<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
312N/A onkeypress="keypress(event);">
312N/A <noscript lang="javascript">
312N/A <center>
312N/A <p><big>Framed Navigation controls require Javascript</big><br />
312N/A Either this browser is incompatable or javascript is not enabled</p>
312N/A </center>
312N/A </noscript>
312N/A <table width="100%" border="0" align="center">
312N/A <tr>
312N/A <td valign="middle" width="25%">Diff navigation:
312N/A Use 'j' and 'k' for next and previous diffs; or use buttons
312N/A at right</td>
312N/A <td align="center" valign="top" width="50%">
312N/A <div class="button">
312N/A <table border="0" align="center">
312N/A <tr>
312N/A <td>
312N/A <a onMouseDown="handlePress(1);return true;"
312N/A onMouseUp="handleRelease(1);return true;"
312N/A onMouseOut="handleRelease(1);return true;"
312N/A onClick="return false;"
312N/A title="Go to Beginning Of file">BOF</a></td>
312N/A <td>
312N/A <a onMouseDown="handlePress(3);return true;"
312N/A onMouseUp="handleRelease(3);return true;"
312N/A onMouseOut="handleRelease(3);return true;"
312N/A title="Scroll Up: Press and Hold to accelerate"
312N/A onClick="return false;">Scroll Up</a></td>
312N/A <td>
312N/A <a onMouseDown="handlePress(2);return true;"
312N/A onMouseUp="handleRelease(2);return true;"
312N/A onMouseOut="handleRelease(2);return true;"
312N/A title="Go to previous Diff"
312N/A onClick="return false;">Prev Diff</a>
312N/A </td></tr>
312N/A
312N/A <tr>
312N/A <td>
312N/A <a onMouseDown="handlePress(6);return true;"
312N/A onMouseUp="handleRelease(6);return true;"
312N/A onMouseOut="handleRelease(6);return true;"
312N/A onClick="return false;"
312N/A title="Go to End Of File">EOF</a></td>
312N/A <td>
312N/A <a onMouseDown="handlePress(4);return true;"
312N/A onMouseUp="handleRelease(4);return true;"
312N/A onMouseOut="handleRelease(4);return true;"
312N/A title="Scroll Down: Press and Hold to accelerate"
312N/A onClick="return false;">Scroll Down</a></td>
312N/A <td>
312N/A <a onMouseDown="handlePress(5);return true;"
312N/A onMouseUp="handleRelease(5);return true;"
312N/A onMouseOut="handleRelease(5);return true;"
312N/A title="Go to next Diff"
312N/A onClick="return false;">Next Diff</a></td>
312N/A </tr>
312N/A </table>
312N/A </div>
312N/A </td>
312N/A <th valign="middle" width="25%">
312N/A <form action="" name="diff" onsubmit="return ValidateDiffNum();">
312N/A <input name="display" value="BOF" size="8" type="text" />
312N/A <input name="real" value="0" size="8" type="hidden" />
312N/A </form>
312N/A </th>
312N/A </tr>
312N/A </table>
312N/A </body>
312N/A</html>
312N/AEOF
312N/A}
312N/A
312N/A
312N/A
312N/A#
312N/A# diff_to_html <filename> <filepath> { U | C } <comment>
312N/A#
312N/A# Processes the output of diff to produce an HTML file representing either
312N/A# context or unified diffs.
312N/A#
312N/Adiff_to_html()
312N/A{
312N/A TNAME=$1
312N/A TPATH=$2
312N/A DIFFTYPE=$3
312N/A COMMENT=$4
312N/A
312N/A print "$HTML<head>$STDHEAD"
312N/A print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
312N/A
312N/A if [[ $DIFFTYPE == "U" ]]; then
312N/A print "$UDIFFCSS"
312N/A fi
312N/A
312N/A cat <<-EOF
312N/A </head>
312N/A <body id="SUNWwebrev">
312N/A <h2>$TPATH</h2>
312N/A <a class="print" href="javascript:print()">Print this page</a>
312N/A <pre>$COMMENT</pre>
312N/A <pre>
312N/AEOF
312N/A
312N/A html_quote | $AWK '
312N/A /^--- new/ { next }
312N/A /^\+\+\+ new/ { next }
312N/A /^--- old/ { next }
312N/A /^\*\*\* old/ { next }
312N/A /^\*\*\*\*/ { next }
312N/A /^-------/ { printf "<center><h1>%s</h1></center>\n", $0; next }
312N/A /^\@\@.*\@\@$/ { printf "</pre><hr /><pre>\n";
312N/A printf "<span class=\"newmarker\">%s</span>\n", $0;
312N/A next}
312N/A
312N/A /^\*\*\*/ { printf "<hr /><span class=\"oldmarker\">%s</span>\n", $0;
312N/A next}
312N/A /^---/ { printf "<span class=\"newmarker\">%s</span>\n", $0;
312N/A next}
312N/A /^\+/ {printf "<span class=\"new\">%s</span>\n", $0; next}
312N/A /^!/ {printf "<span class=\"changed\">%s</span>\n", $0; next}
312N/A /^-/ {printf "<span class=\"removed\">%s</span>\n", $0; next}
312N/A {printf "%s\n", $0; next}
312N/A '
312N/A
312N/A print "</pre></body></html>\n"
312N/A}
312N/A
312N/A
312N/A#
312N/A# source_to_html { new | old } <filename>
312N/A#
312N/A# Process a plain vanilla source file to transform it into an HTML file.
312N/A#
312N/Asource_to_html()
312N/A{
312N/A WHICH=$1
312N/A TNAME=$2
312N/A
312N/A print "$HTML<head>$STDHEAD"
312N/A print "<title>$WHICH $TNAME</title>"
312N/A print "<body id=\"SUNWwebrev\">"
312N/A print "<pre>"
312N/A html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
312N/A print "</pre></body></html>"
312N/A}
312N/A
312N/A#
312N/A# teamwarecomments {text|html} parent-file child-file
312N/A#
312N/A# Find the first delta in the child that's not in the parent. Get the
312N/A# newest delta from the parent, get all deltas from the child starting
312N/A# with that delta, and then get all info starting with the second oldest
312N/A# delta in that list (the first delta unique to the child).
312N/A#
312N/A# This code adapted from Bill Shannon's "spc" script
312N/A#
312N/Acomments_from_teamware()
312N/A{
312N/A fmt=$1
312N/A pfile=$PWS/$2
312N/A cfile=$CWS/$3
312N/A
312N/A psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
312N/A if [[ -z "$psid" ]]; then
312N/A psid=1.1
312N/A fi
312N/A
312N/A set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
312N/A N=${#sids[@]}
312N/A
312N/A nawkprg='
312N/A /^COMMENTS:/ {p=1; next}
312N/A /^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
312N/A NF == 0u { next }
312N/A {if (p==0) next; print $0 }'
312N/A
312N/A if [[ $N -ge 2 ]]; then
312N/A sid1=${sids[$((N-2))]} # Gets 2nd to last sid
312N/A
312N/A if [[ $fmt == "text" ]]; then
312N/A $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \
312N/A $AWK "$nawkprg"
312N/A return
312N/A fi
312N/A
312N/A $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \
312N/A html_quote | bug2url | sac2url | $AWK "$nawkprg"
312N/A fi
312N/A}
312N/A
312N/A#
312N/A# wxcomments {text|html} filepath
312N/A#
312N/A# Given the pathname of a file, find its location in a "wx" active file
312N/A# list and print the following sccs comment. Output is either text or
312N/A# HTML; if the latter, embedded bugids (sequence of 5 or more digits) are
312N/A# turned into URLs.
312N/A#
312N/Acomments_from_wx()
312N/A{
312N/A typeset fmt=$1
312N/A typeset p=$2
312N/A
312N/A comm=`$AWK '
312N/A $1 == "'$p'" {
312N/A do getline ; while (NF > 0)
312N/A getline
312N/A while (NF > 0) { print ; getline }
312N/A exit
312N/A }' < $wxfile`
312N/A
312N/A if [[ $fmt == "text" ]]; then
312N/A print "$comm"
312N/A return
312N/A fi
312N/A
312N/A print "$comm" | html_quote | bug2url | sac2url
312N/A}
312N/A
312N/Acomments_from_mercurial()
312N/A{
312N/A fmt=$1
312N/A pfile=$PWS/$2
312N/A cfile=$CWS/$3
312N/A
312N/A logdir=`dirname $cfile`
312N/A logf=`basename $cfile`
312N/A if [ -d $logdir ]; then
312N/A ( cd $logdir;
312N/A active=`hg status $logf 2>/dev/null`
312N/A # If the output from 'hg status' is not empty, it means the file
312N/A # hasn't been committed, so don't fetch comments.
312N/A if [[ -z $active ]] ; then
312N/A if [[ -n $ALL_CREV ]]; then
312N/A rev_opt=
312N/A for rev in $ALL_CREV; do
312N/A rev_opt="$rev_opt --rev $rev"
312N/A done
312N/A comm=`hg log $rev_opt --follow --template 'rev {rev} : {desc}\n' $logf`
312N/A elif [[ -n $FIRST_CREV ]]; then
312N/A comm=`hg log --rev $FIRST_CREV:tip --follow --template 'rev {rev} : {desc}\n' $logf`
312N/A else
312N/A comm=`hg log -l1 --follow --template 'rev {rev} : {desc}\n' $logf`
312N/A fi
312N/A else
312N/A comm=""
312N/A fi
312N/A if [[ $fmt == "text" ]]; then
312N/A print "$comm"
312N/A return
312N/A fi
607N/A
312N/A print "$comm" | html_quote | bug2url | sac2url
312N/A )
312N/A fi
312N/A}
312N/A
312N/A
312N/A#
312N/A# getcomments {text|html} filepath parentpath
312N/A#
312N/A# Fetch the comments depending on what SCM mode we're in.
312N/A#
312N/Agetcomments()
312N/A{
312N/A typeset fmt=$1
312N/A typeset p=$2
312N/A typeset pp=$3
312N/A
312N/A if [[ -n $wxfile ]]; then
312N/A comments_from_wx $fmt $p
312N/A else
312N/A if [[ $SCM_MODE == "teamware" ]]; then
312N/A comments_from_teamware $fmt $pp $p
312N/A elif [[ $SCM_MODE == "mercurial" ]]; then
312N/A comments_from_mercurial $fmt $pp $p
312N/A fi
312N/A fi
312N/A}
312N/A
312N/A#
312N/A# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
312N/A#
312N/A# Print out Code Inspection figures similar to sccs-prt(1) format.
312N/A#
312N/Afunction printCI
312N/A{
312N/A integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
312N/A typeset str
312N/A if (( tot == 1 )); then
312N/A str="line"
312N/A else
312N/A str="lines"
312N/A fi
312N/A printf '%d %s changed: %d ins; %d del; %d mod; %d unchg' \
312N/A $tot $str $ins $del $mod $unc
312N/A}
312N/A
312N/A
312N/A#
312N/A# difflines <oldfile> <newfile>
312N/A#
312N/A# Calculate and emit number of added, removed, modified and unchanged lines,
312N/A# and total lines changed, the sum of added + removed + modified.
312N/A#
312N/Afunction difflines
312N/A{
312N/A integer tot mod del ins unc err
312N/A typeset filename
312N/A
312N/A eval $( diff -e $1 $2 | $AWK '
312N/A # Change range of lines: N,Nc
312N/A /^[0-9]*,[0-9]*c$/ {
312N/A n=split(substr($1,1,length($1)-1), counts, ",");
312N/A if (n != 2) {
312N/A error=2
312N/A exit;
312N/A }
312N/A #
312N/A # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
312N/A # following would be 5 - 3 = 2! Hence +1 for correction.
312N/A #
312N/A r=(counts[2]-counts[1])+1;
312N/A
312N/A #
312N/A # Now count replacement lines: each represents a change instead
312N/A # of a delete, so increment c and decrement r.
312N/A #
312N/A while (getline != /^\.$/) {
312N/A c++;
312N/A r--;
312N/A }
312N/A #
312N/A # If there were more replacement lines than original lines,
312N/A # then r will be negative; in this case there are no deletions,
312N/A # but there are r changes that should be counted as adds, and
312N/A # since r is negative, subtract it from a and add it to c.
312N/A #
312N/A if (r < 0) {
312N/A a-=r;
312N/A c+=r;
312N/A }
312N/A
312N/A #
312N/A # If there were more original lines than replacement lines, then
312N/A # r will be positive; in this case, increment d by that much.
312N/A #
312N/A if (r > 0) {
312N/A d+=r;
312N/A }
312N/A next;
312N/A }
312N/A
312N/A # Change lines: Nc
312N/A /^[0-9].*c$/ {
312N/A # The first line is a replacement; any more are additions.
312N/A if (getline != /^\.$/) {
312N/A c++;
312N/A while (getline != /^\.$/) a++;
312N/A }
312N/A next;
312N/A }
312N/A
312N/A # Add lines: both Na and N,Na
312N/A /^[0-9].*a$/ {
312N/A while (getline != /^\.$/) a++;
312N/A next;
312N/A }
312N/A
312N/A # Delete range of lines: N,Nd
312N/A /^[0-9]*,[0-9]*d$/ {
312N/A n=split(substr($1,1,length($1)-1), counts, ",");
312N/A if (n != 2) {
312N/A error=2
312N/A exit;
312N/A }
312N/A #
312N/A # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
312N/A # following would be 5 - 3 = 2! Hence +1 for correction.
312N/A #
312N/A r=(counts[2]-counts[1])+1;
312N/A d+=r;
312N/A next;
312N/A }
312N/A
312N/A # Delete line: Nd. For example 10d says line 10 is deleted.
312N/A /^[0-9]*d$/ {d++; next}
312N/A
312N/A # Should not get here!
312N/A {
312N/A error=1;
312N/A exit;
312N/A }
312N/A
312N/A # Finish off - print results
312N/A END {
312N/A printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
312N/A (c+d+a), c, d, a, error);
312N/A }' )
312N/A
312N/A # End of $AWK, Check to see if any trouble occurred.
312N/A if (( $? > 0 || err > 0 )); then
312N/A print "Unexpected Error occurred reading" \
312N/A "\`diff -e $1 $2\`: \$?=$?, err=" $err
312N/A return
312N/A fi
312N/A
312N/A # Accumulate totals
312N/A (( TOTL += tot ))
312N/A (( TMOD += mod ))
312N/A (( TDEL += del ))
312N/A (( TINS += ins ))
312N/A # Calculate unchanged lines
312N/A unc=`wc -l < $1`
312N/A if (( unc > 0 )); then
312N/A (( unc -= del + mod ))
312N/A (( TUNC += unc ))
312N/A fi
312N/A # print summary
312N/A print "<span class=\"lineschanged\">\c"
312N/A printCI $tot $ins $del $mod $unc
312N/A print "</span>"
312N/A}
312N/A
312N/A
312N/A#
312N/A# flist_from_wx
312N/A#
312N/A# Sets up webrev to source its information from a wx-formatted file.
312N/A# Sets the global 'wxfile' variable.
312N/A#
312N/Afunction flist_from_wx
312N/A{
312N/A typeset argfile=$1
312N/A if [[ -n ${argfile%%/*} ]]; then
312N/A #
312N/A # If the wx file pathname is relative then make it absolute
312N/A # because the webrev does a "cd" later on.
312N/A #
312N/A wxfile=$PWD/$argfile
312N/A else
312N/A wxfile=$argfile
312N/A fi
312N/A
312N/A $AWK '{ c = 1; print;
312N/A while (getline) {
312N/A if (NF == 0) { c = -c; continue }
312N/A if (c > 0) print
312N/A }
312N/A }' $wxfile > $FLIST
312N/A
312N/A print " Done."
312N/A}
312N/A
312N/A#
312N/A# flist_from_teamware [ <args-to-putback-n> ]
312N/A#
312N/A# Generate the file list by extracting file names from a putback -n. Some
312N/A# names may come from the "update/create" messages and others from the
312N/A# "currently checked out" warning. Renames are detected here too. Extract
312N/A# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
312N/A# -n as well, but remove them if they are already defined.
312N/A#
312N/Afunction flist_from_teamware
312N/A{
312N/A if [[ -n $codemgr_parent ]]; then
312N/A if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
312N/A print -u2 "parent $codemgr_parent doesn't look like a" \
312N/A "valid teamware workspace"
312N/A exit 1
312N/A fi
312N/A parent_args="-p $codemgr_parent"
312N/A fi
312N/A
312N/A print " File list from: 'putback -n $parent_args $*' ... \c"
312N/A
312N/A putback -n $parent_args $* 2>&1 |
312N/A $AWK '
312N/A /^update:|^create:/ {print $2}
312N/A /^Parent workspace:/ {printf("CODEMGR_PARENT=%s\n",$3)}
312N/A /^Child workspace:/ {printf("CODEMGR_WS=%s\n",$3)}
312N/A /^The following files are currently checked out/ {p = 1; next}
312N/A NF == 0 {p=0 ; next}
312N/A /^rename/ {old=$3}
312N/A $1 == "to:" {print $2, old}
312N/A /^"/ {next}
312N/A p == 1 {print $1}' |
312N/A sort -r -k 1,1 -u | sort > $FLIST
312N/A
312N/A print " Done."
312N/A}
312N/A
312N/Afunction outgoing_from_mercurial_forest
312N/A{
312N/A hg foutgoing --template 'rev: {rev}\n' $OUTPWS | $FILTER | $AWK '
312N/A BEGIN {ntree=0}
312N/A /^comparing/ {next}
312N/A /^no changes/ {next}
312N/A /^searching/ {next}
312N/A /^\[.*\]$/ {tree=substr($1,2,length($1)-2);
312N/A trees[ntree++] = tree;
312N/A revs[tree]=-1;
312N/A next}
312N/A /^rev:/ {rev=$2+0;
312N/A if (revs[tree] == -1 || rev < revs[tree])
312N/A { revs[tree] = rev; };
312N/A next;}
312N/A END {for (tree in trees)
312N/A { rev=revs[trees[tree]];
607N/A if (rev > 0)
312N/A {printf("%s %d\n",trees[tree],rev-1)}
312N/A }}' | while read LINE
312N/A do
312N/A set - $LINE
312N/A TREE=$1
312N/A REV=$2
312N/A A=`hg -R $CWS/$TREE log --rev $REV --template '{node}'`
312N/A FSTAT_OPT="--rev $A"
312N/A print "Revision: $A $REV" >> $FLIST
312N/A treestatus $TREE
312N/A done
312N/A}
312N/A
312N/Afunction flist_from_mercurial_forest
312N/A{
312N/A rm -f $FLIST
312N/A if [ -z "$Nflag" ]; then
312N/A print " File list from hg foutgoing $PWS ..."
312N/A outgoing_from_mercurial_forest
312N/A HG_LIST_FROM_COMMIT=1
312N/A fi
312N/A if [ ! -f $FLIST ]; then
312N/A # hg commit hasn't been run see what is lying around
312N/A print "\n No outgoing, perhaps you haven't commited."
312N/A print " File list from hg fstatus -mard ...\c"
312N/A FSTAT_OPT=
312N/A fstatus
312N/A HG_LIST_FROM_COMMIT=0
312N/A fi
312N/A print " Done."
312N/A}
312N/A
312N/A#
312N/A# Used when dealing with the result of 'hg foutgoing'
312N/A# When now go down the tree and generate the change list
312N/A#
312N/Afunction treestatus
312N/A{
312N/A TREE=$1
312N/A HGCMD="hg -R $CWS/$TREE status $FSTAT_OPT"
607N/A
312N/A $HGCMD -mdn 2>/dev/null | $FILTER | while read F
312N/A do
312N/A echo $TREE/$F
312N/A done >> $FLIST
312N/A
312N/A # Then all the added files
312N/A # But some of these could have been "moved" or renamed ones
312N/A # so let's make sure we get the proper info
312N/A # hg status -aC will produce something like:
312N/A # A subdir/File3
312N/A # A subdir/File4
312N/A # File4
312N/A # A subdir/File5
312N/A # The first and last are simple addition while the middle one
312N/A # is a move/rename
312N/A
312N/A $HGCMD -aC | $FILTER | while read LINE; do
312N/A ldone=""
312N/A while [ -z "$ldone" ]; do
312N/A ldone="1"
312N/A set - $LINE
312N/A if [ $# -eq 2 -a "$1" == "A" ]; then
312N/A AFILE=$2
312N/A if read LINE2; then
312N/A set - $LINE2
312N/A if [ $# -eq 1 ]; then
312N/A echo $TREE/$AFILE $TREE/$1 >>$FLIST
312N/A elif [ $# -eq 2 ]; then
312N/A echo $TREE/$AFILE >>$FLIST
312N/A LINE=$LINE2
312N/A ldone=""
312N/A fi
312N/A else
312N/A echo $TREE/$AFILE >>$FLIST
312N/A fi
312N/A fi
312N/A done
312N/A done
312N/A $HGCMD -rn | $FILTER | while read RFILE; do
312N/A grep "$TREE/$RFILE" $FLIST >/dev/null
312N/A if [ $? -eq 1 ]; then
312N/A echo $TREE/$RFILE >>$FLIST
312N/A fi
312N/A done
312N/A}
312N/A
312N/Afunction fstatus
312N/A{
312N/A #
312N/A # forest extension is still being changed. For instance the output
312N/A # of fstatus used to no prepend the tree path to filenames, but
312N/A # this has changed recently. AWK code below does try to handle both
312N/A # cases
312N/A #
312N/A hg fstatus -mdn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
312N/A /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
312N/A $1 != "" {n=index($1,tree);
312N/A if (n == 0)
312N/A { printf("%s/%s\n",tree,$1)}
312N/A else
312N/A { printf("%s\n",$1)}}' >> $FLIST
312N/A
312N/A #
312N/A # There is a bug in the output of fstatus -aC on recent versions: it
312N/A # inserts a space between the name of the tree and the filename of the
312N/A # old file. e.g.:
312N/A #
312N/A # $ hg fstatus -aC
312N/A # [.]
312N/A #
312N/A # [MyWS]
312N/A # A MyWS/subdir/File2
312N/A # MyWS/ File2
312N/A #
312N/A # [MyWS2]
312N/A #
312N/A
312N/A hg fstatus -aC $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
312N/A /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
312N/A /^A .*/ {n=index($2,tree);
312N/A if (n == 0)
312N/A { printf("A %s/%s\n",tree,$2)}
312N/A else
607N/A { printf("A %s\n",$2)};
312N/A next}
312N/A /^ / {n=index($1,tree);
312N/A if (n == 0)
312N/A { printf("%s/%s\n",tree,$1)}
312N/A else
312N/A { if (NF == 2)
312N/A printf("%s/%s\n",tree,$2)
312N/A else
312N/A printf("%s\n",$1)
312N/A };
312N/A next}
312N/A ' | while read LINE; do
312N/A ldone=""
312N/A while [ -z "$ldone" ]; do
312N/A ldone="1"
312N/A set - $LINE
312N/A if [ $# -eq 2 -a "$1" == "A" ]; then
312N/A AFILE=$2
312N/A if read LINE2; then
312N/A set - $LINE2
312N/A if [ $# -eq 1 ]; then
312N/A echo $AFILE $1 >>$FLIST
312N/A elif [ $# -eq 2 ]; then
312N/A echo $AFILE >>$FLIST
312N/A LINE=$LINE2
312N/A ldone=""
312N/A fi
312N/A else
312N/A echo $AFILE >>$FLIST
312N/A fi
312N/A fi
312N/A done
312N/A done
312N/A hg fstatus -rn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
312N/A /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
312N/A $1 != "" {n=index($1,tree);
312N/A if (n == 0)
312N/A { printf("%s/%s\n",tree,$1)}
312N/A else
312N/A { printf("%s\n",$1)}}' | while read RFILE; do
312N/A grep "$RFILE" $FLIST >/dev/null
312N/A if [ $? -eq 1 ]; then
312N/A echo $RFILE >>$FLIST
312N/A fi
312N/A done
312N/A}
312N/A
312N/A#
312N/A# flist_from_mercurial $PWS
312N/A#
312N/A# Only local file based repositories are supported at present
312N/A# since even though we can determine the list from the parent finding
312N/A# the changes is harder.
312N/A#
312N/A# We first look for any outgoing files, this is for when the user has
312N/A# run hg commit. If we don't find any then we look with hg status.
312N/A#
312N/A# We need at least one of default-push or default paths set in .hg/hgrc
312N/A# If neither are set we don't know who to compare with.
312N/A
607N/Afunction flist_from_mercurial
312N/A{
312N/A# if [ "${PWS##ssh://}" != "$PWS" -o \
312N/A# "${PWS##http://}" != "$PWS" -o \
312N/A# "${PWS##https://}" != "$PWS" ]; then
312N/A# print "Remote Mercurial repositories not currently supported."
312N/A# print "Set default and/or default-push to a local repository"
312N/A# exit
312N/A# fi
312N/A if [[ -n $forestflag ]]; then
312N/A HG_LIST_FROM_COMMIT=
312N/A flist_from_mercurial_forest
312N/A else
312N/A STATUS_REV=
312N/A if [[ -n $rflag ]]; then
312N/A STATUS_REV="--rev $PARENT_REV"
312N/A elif [[ -n $OUTREV ]]; then
312N/A STATUS_REV="--rev $OUTREV"
312N/A else
312N/A # hg commit hasn't been run see what is lying around
312N/A print "\n No outgoing, perhaps you haven't commited."
312N/A fi
312N/A # First let's list all the modified or deleted files
312N/A
312N/A hg status $STATUS_REV -mdn | $FILTER > $FLIST
312N/A
312N/A # Then all the added files
312N/A # But some of these could have been "moved" or renamed ones
312N/A # so let's make sure we get the proper info
312N/A # hg status -aC will produce something like:
312N/A # A subdir/File3
312N/A # A subdir/File4
312N/A # File4
312N/A # A subdir/File5
312N/A # The first and last are simple addition while the middle one
312N/A # is a move/rename
312N/A
312N/A hg status $STATUS_REV -aC | $FILTER >$FLIST.temp
312N/A while read LINE; do
312N/A ldone=""
312N/A while [ -z "$ldone" ]; do
312N/A ldone="1"
312N/A set - $LINE
312N/A if [ $# -eq 2 -a "$1" == "A" ]; then
312N/A AFILE=$2
312N/A if read LINE2; then
312N/A set - $LINE2
312N/A if [ $# -eq 1 ]; then
312N/A echo $AFILE $1 >>$FLIST
312N/A elif [ $# -eq 2 ]; then
312N/A echo $AFILE >>$FLIST
312N/A LINE=$LINE2
312N/A ldone=""
312N/A fi
312N/A else
312N/A echo $AFILE >>$FLIST
312N/A fi
312N/A fi
312N/A done
312N/A done < $FLIST.temp
312N/A hg status $STATUS_REV -rn | $FILTER > $FLIST.temp
312N/A while read RFILE; do
312N/A grep "$RFILE" $FLIST >/dev/null
312N/A if [ $? -eq 1 ]; then
312N/A echo $RFILE >>$FLIST
312N/A fi
312N/A done < $FLIST.temp
312N/A rm -f $FLIST.temp
312N/A fi
312N/A}
312N/A
312N/Afunction env_from_flist
312N/A{
312N/A [[ -r $FLIST ]] || return
312N/A
312N/A #
312N/A # Use "eval" to set env variables that are listed in the file
312N/A # list. Then copy those into our local versions of those
312N/A # variables if they have not been set already.
312N/A #
312N/A eval `sed -e "s/#.*$//" $FLIST | grep = `
312N/A
312N/A [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
312N/A
312N/A #
312N/A # Check to see if CODEMGR_PARENT is set in the flist file.
312N/A #
312N/A [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
312N/A codemgr_parent=$CODEMGR_PARENT
312N/A}
312N/A
312N/A#
312N/A# detect_scm
312N/A#
312N/A# We dynamically test the SCM type; this allows future extensions to
312N/A# new SCM types
312N/A#
312N/Afunction detect_scm
312N/A{
312N/A #
312N/A # If CODEMGR_WS is specified in the flist file, we assume teamware.
312N/A #
312N/A if [[ -r $FLIST ]]; then
312N/A egrep '^CODEMGR_WS=' $FLIST > /dev/null 2>&1
312N/A if [[ $? -eq 0 ]]; then
312N/A print "teamware"
312N/A return
312N/A fi
312N/A fi
312N/A
312N/A #
312N/A # The presence of $CODEMGR_WS and a Codemgr_wsdata directory
312N/A # is our clue that this is a teamware workspace.
312N/A # Same if true if current directory has a Codemgr_wsdata sub-dir
312N/A #
312N/A if [[ -z "$CODEMGR_WS" ]]; then
312N/A CODEMGR_WS=`workspace name 2>/dev/null`
312N/A fi
312N/A
312N/A if [[ -n $CODEMGR_WS && -d "$CODEMGR_WS/Codemgr_wsdata" ]]; then
312N/A print "teamware"
312N/A elif [[ -d $PWD/Codemgr_wsdata ]]; then
312N/A print "teamware"
312N/A elif hg root >/dev/null ; then
312N/A print "mercurial"
312N/A else
312N/A print "unknown"
312N/A fi
312N/A}
312N/A
312N/A#
312N/A# Extract the parent workspace from the Codemgr_wsdata/parent file
312N/A#
312N/Afunction parent_from_teamware
312N/A{
312N/A if [[ -f "$1/Codemgr_wsdata/parent" ]]; then
312N/A tail -1 "$1/Codemgr_wsdata/parent"
312N/A fi
312N/A}
312N/A
312N/Afunction look_for_prog
312N/A{
312N/A typeset path
312N/A typeset ppath
312N/A typeset progname=$1
312N/A
312N/A DEVTOOLS=
312N/A OS=`uname`
312N/A if [[ "$OS" == "SunOS" ]]; then
312N/A DEVTOOLS="/java/devtools/`uname -p`/bin"
312N/A elif [[ "$OS" == "Linux" ]]; then
312N/A DEVTOOLS="/java/devtools/linux/bin"
312N/A fi
607N/A
312N/A ppath=$PATH
312N/A ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
312N/A ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
312N/A ppath=$ppath:/opt/onbld/bin/`uname -p`
312N/A ppath=$ppath:/java/devtools/share/bin:$DEVTOOLS
312N/A
312N/A PATH=$ppath prog=`whence $progname`
312N/A if [[ -n $prog ]]; then
312N/A print $prog
312N/A fi
312N/A}
312N/A
312N/Afunction build_old_new_teamware
312N/A{
312N/A # If the child's version doesn't exist then
312N/A # get a readonly copy.
312N/A
312N/A if [[ ! -f $F && -f SCCS/s.$F ]]; then
312N/A $SCCS get -s $F
312N/A fi
312N/A
312N/A #
312N/A # Snag new version of file.
312N/A #
312N/A rm -f $newdir/$DIR/$F
312N/A cp $F $newdir/$DIR/$F
312N/A
312N/A #
312N/A # Get the parent's version of the file. First see whether the
312N/A # child's version is checked out and get the parent's version
312N/A # with keywords expanded or unexpanded as appropriate.
312N/A #
312N/A if [ -f $PWS/$PDIR/SCCS/s.$PF -o \
312N/A -f $PWS/$PDIR/SCCS/p.$PF ]; then
312N/A rm -f $olddir/$PDIR/$PF
312N/A if [ -f SCCS/p.$F ]; then
312N/A $SCCS get -s -p -k $PWS/$PDIR/$PF \
312N/A > $olddir/$PDIR/$PF
312N/A else
312N/A $SCCS get -s -p $PWS/$PDIR/$PF \
312N/A > $olddir/$PDIR/$PF
312N/A fi
312N/A else
312N/A if [[ -f $PWS/$PDIR/$PF ]]; then
312N/A # Parent is not a real workspace, but just a raw
312N/A # directory tree - use the file that's there as
312N/A # the old file.
312N/A
312N/A rm -f $olddir/$DIR/$F
312N/A cp $PWS/$PDIR/$PF $olddir/$DIR/$F
312N/A fi
312N/A fi
312N/A}
312N/A
312N/A#
312N/A# Find the parent for $1
312N/A#
312N/Afunction find_outrev
312N/A{
312N/A crev=$1
312N/A prev=`hg log -r $crev --template '{parents}\n'`
312N/A if [[ -z "$prev" ]]
312N/A then
312N/A # No specific parent means previous changeset is parent
312N/A prev=`expr $crev - 1`
312N/A else
312N/A # Format is either of the following two:
312N/A # 546:7df6fcf1183b
312N/A # 548:16f1915bb5cd 547:ffaa4e775815
312N/A prev=`echo $prev | sed -e 's/\([0-9]*\):.*/\1/'`
312N/A fi
312N/A print $prev
312N/A}
312N/A
312N/Afunction extract_ssh_infos
312N/A{
312N/A CMD=$1
312N/A if expr "$CMD" : 'ssh://[^/]*@' >/dev/null; then
312N/A ssh_user=`echo $CMD | sed -e 's/ssh:\/\/\(.*\)@.*/\1/'`
312N/A ssh_host=`echo $CMD | sed -e 's/ssh:\/\/.*@\([^/]*\)\/.*/\1/'`
312N/A ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/.*@[^/]*\/\(.*\)/\1/'`
312N/A else
312N/A ssh_user=
312N/A ssh_host=`echo $CMD | sed -e 's/ssh:\/\/\([^/]*\)\/.*/\1/'`
312N/A ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/[^/]*\/\(.*\)/\1/'`
312N/A fi
607N/A
312N/A}
312N/A
312N/Afunction build_old_new_mercurial
312N/A{
312N/A olddir=$1
312N/A newdir=$2
312N/A DIR=$3
312N/A F=$4
312N/A #
312N/A # new version of the file.
312N/A #
312N/A rm -rf $newdir/$DIR/$F
312N/A if [ -f $F ]; then
312N/A cp $F $newdir/$DIR/$F
312N/A fi
312N/A
312N/A #
312N/A # Old version of the file.
312N/A #
312N/A rm -rf $olddir/$DIR/$F
312N/A
312N/A if [ -n "$PWS" ]; then
312N/A if expr "$PWS" : 'ssh://' >/dev/null
312N/A then
312N/A extract_ssh_infos $PWS
312N/A if [ -n "$ssh_user" ]; then
312N/A parent="ssh -l $ssh_user $ssh_host hg -R $ssh_dir --cwd $ssh_dir"
312N/A else
312N/A parent="ssh $ssh_host hg -R $ssh_dir --cwd $ssh_dir"
312N/A fi
312N/A else
312N/A parent="hg -R $PWS --cwd $PWS"
312N/A fi
312N/A else
312N/A parent=""
312N/A fi
312N/A
312N/A if [ -z "$rename" ]; then
312N/A if [ -n "$rflag" ]; then
312N/A parentrev=$PARENT_REV
312N/A elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then
312N/A parentrev=$OUTREV
312N/A else
312N/A if [[ -n $HG_BRANCH ]]; then
312N/A parentrev=$HG_BRANCH
312N/A else
312N/A parentrev="tip"
312N/A fi
312N/A fi
312N/A
312N/A if [ -n "$parentrev" ]; then
312N/A if [ -z "$parent" ]; then
312N/A hg cat --rev $parentrev --output $olddir/$DIR/$F $F 2>/dev/null
312N/A else
312N/A # when specifying a workspace we have to provide
312N/A # the full path
312N/A $parent cat --rev $parentrev --output $olddir/$DIR/$F $DIR/$F 2>/dev/null
312N/A fi
312N/A fi
312N/A else
312N/A # It's a rename (or a move), so let's make sure we move
312N/A # to the right directory first, then restore it once done
312N/A current_dir=`pwd`
312N/A cd $CWS/$PDIR
312N/A if [ -n "$rflag" ]; then
312N/A parentrev=$PARENT_REV
312N/A elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then
312N/A parentrev=$OUTREV
312N/A fi
312N/A if [ -z "$parentrev" ]; then
312N/A parentrev=`hg log -l1 $PF | $AWK -F: '/changeset/ {print $2}'`
312N/A fi
312N/A if [ -n "$parentrev" ]; then
312N/A mkdir -p $olddir/$PDIR
312N/A if [ -z "$parent" ]; then
312N/A hg cat --rev $parentrev --output $olddir/$PDIR/$PF $PF 2>/dev/null
312N/A else
312N/A $parent cat --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null
312N/A fi
312N/A fi
312N/A cd $current_dir
312N/A fi
312N/A}
312N/A
312N/Afunction build_old_new
312N/A{
312N/A if [[ $SCM_MODE == "teamware" ]]; then
312N/A build_old_new_teamware $@
312N/A fi
312N/A
312N/A if [[ $SCM_MODE == "mercurial" ]]; then
312N/A build_old_new_mercurial $@
312N/A fi
312N/A}
312N/A
312N/A
312N/A#
312N/A# Usage message.
312N/A#
312N/Afunction usage
312N/A{
312N/A print "Usage:\twebrev [common-options]
312N/A webrev [common-options] ( <file> | - )
312N/A webrev [common-options] -w <wx file>
312N/A webrev [common-options] -l [arguments to 'putback']
312N/A
312N/AOptions:
312N/A -v: Print the version of this tool.
312N/A -b: Do not ignore changes in the amount of white space.
312N/A -c <CR#>: Include link to CR (aka bugid) in the main page.
312N/A -O: Print bugids/arc cases suitable for OpenJDK.
312N/A -i <filename>: Include <filename> in the index.html file.
312N/A -o <outdir>: Output webrev to specified directory.
312N/A -p <compare-against>: Use specified parent wkspc or basis for comparison
312N/A -w <wxfile>: Use specified wx active file.
312N/A -u <username>: Use that username instead of 'guessing' one.
312N/A -m: Forces the use of Mercurial
312N/A -t: Forces the use of Teamware
312N/A
312N/AMercurial only options:
312N/A -r rev: Compare against a specified revision
312N/A -N: Skip 'hg outgoing', use only 'hg status'
312N/A -f: Use the forest extension
312N/A
312N/AEnvironment:
312N/A WDIR: Control the output directory.
312N/A WEBREV_BUGURL: Control the URL prefix for bugids.
312N/A WEBREV_SACURL: Control the URL prefix for ARC cases.
312N/A
312N/ASCM Environment:
312N/A Teamware: CODEMGR_WS: Workspace location.
312N/A Teamware: CODEMGR_PARENT: Parent workspace location.
312N/A
312N/A"
312N/A
312N/A exit 2
312N/A}
312N/A
312N/A#
312N/A#
312N/A# Main program starts here
312N/A#
312N/A#
312N/ALANG="C"
312N/ALC_ALL="C"
312N/Aexport LANG LC_ALL
312N/Atrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
312N/A
312N/Aset +o noclobber
312N/A
312N/A[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
312N/A[[ -z $WX ]] && WX=`look_for_prog wx`
312N/A[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
312N/A[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
312N/A[[ -z $PERL ]] && PERL=`look_for_prog perl`
312N/A[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
312N/A[[ -z $AWK ]] && AWK=`look_for_prog nawk`
312N/A[[ -z $AWK ]] && AWK=`look_for_prog gawk`
312N/A[[ -z $AWK ]] && AWK=`look_for_prog awk`
312N/A[[ -z $WSPACE ]] && WSPACE=`look_for_prog workspace`
312N/A[[ -z $JAR ]] && JAR=`look_for_prog jar`
312N/A[[ -z $ZIP ]] && ZIP=`look_for_prog zip`
312N/A[[ -z $GETENT ]] && GETENT=`look_for_prog getent`
312N/A[[ -z $WGET ]] && WGET=`look_for_prog wget`
312N/A
312N/Aif uname | grep CYGWIN >/dev/null
312N/Athen
312N/A ISWIN=1
312N/A # Under windows mercurial outputs '\' instead of '/'
312N/A FILTER="tr '\\\\' '/'"
312N/Aelse
312N/A FILTER="cat"
312N/Afi
312N/A
312N/Aif [[ ! -x $PERL ]]; then
312N/A print -u2 "Error: No perl interpreter found. Exiting."
312N/A exit 1
312N/Afi
312N/A
312N/A#
312N/A# These aren't fatal, but we want to note them to the user.
312N/A# We don't warn on the absence of 'wx' until later when we've
312N/A# determined that we actually need to try to invoke it.
312N/A#
312N/A# [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
312N/A# [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
312N/A# [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
312N/A
312N/A# Declare global total counters.
312N/Ainteger TOTL TINS TDEL TMOD TUNC
312N/A
312N/Aflist_mode=
312N/Aflist_file=
312N/Abflag=
312N/Aiflag=
312N/Aoflag=
312N/Apflag=
312N/Auflag=
312N/Alflag=
312N/Awflag=
312N/AOflag=
312N/Arflag=
312N/ANflag=
312N/Aforestflag=
312N/Awhile getopts "c:i:o:p:r:u:lmtwONvfb" opt
312N/Ado
312N/A case $opt in
312N/A b) bflag=1;;
312N/A
312N/A i) iflag=1
312N/A INCLUDE_FILE=$OPTARG;;
312N/A
312N/A o) oflag=1
312N/A WDIR=$OPTARG;;
312N/A
312N/A p) pflag=1
312N/A codemgr_parent=$OPTARG;;
312N/A
312N/A u) uflag=1
312N/A username=$OPTARG;;
312N/A
312N/A c) if [[ -z $CRID ]]; then
312N/A CRID=$OPTARG
312N/A else
312N/A CRID="$CRID $OPTARG"
312N/A fi;;
312N/A
312N/A m) SCM_MODE="mercurial";;
312N/A
312N/A t) SCM_MODE="teamware";;
312N/A
312N/A #
312N/A # If -l has been specified, we need to abort further options
312N/A # processing, because subsequent arguments are going to be
312N/A # arguments to 'putback -n'.
312N/A #
312N/A l) lflag=1
312N/A break;;
312N/A
312N/A w) wflag=1;;
312N/A
312N/A O) Oflag=1;;
312N/A
312N/A N) Nflag=1;;
312N/A
312N/A f) forestflag=1;;
312N/A
312N/A r) rflag=1
312N/A PARENT_REV=$OPTARG;;
312N/A
312N/A v) print "$0 version: $WEBREV_UPDATED";;
607N/A
312N/A
312N/A ?) usage;;
312N/A esac
312N/Adone
312N/A
312N/AFLIST=/tmp/$$.flist
312N/A
312N/Aif [[ -n $wflag && -n $lflag ]]; then
312N/A usage
312N/Afi
312N/A
312N/Aif [[ -n $forestflag && -n $rflag ]]; then
312N/A print "The -r <rev> flag is incompatible with the use of forests"
312N/A exit 2
312N/Afi
312N/A
312N/A#
312N/A# If this manually set as the parent, and it appears to be an earlier webrev,
312N/A# then note that fact and set the parent to the raw_files/new subdirectory.
312N/A#
312N/Aif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
312N/A parent_webrev="$codemgr_parent"
312N/A codemgr_parent="$codemgr_parent/raw_files/new"
312N/Afi
312N/A
312N/Aif [[ -z $wflag && -z $lflag ]]; then
312N/A shift $(($OPTIND - 1))
312N/A
312N/A if [[ $1 == "-" ]]; then
312N/A cat > $FLIST
312N/A flist_mode="stdin"
312N/A flist_done=1
312N/A shift
312N/A elif [[ -n $1 ]]; then
312N/A if [[ ! -r $1 ]]; then
312N/A print -u2 "$1: no such file or not readable"
312N/A usage
312N/A fi
312N/A cat $1 > $FLIST
312N/A flist_mode="file"
312N/A flist_file=$1
312N/A flist_done=1
312N/A shift
312N/A else
312N/A flist_mode="auto"
312N/A fi
312N/Afi
312N/A
312N/A#
312N/A# Before we go on to further consider -l and -w, work out which SCM we think
312N/A# is in use.
312N/A#
312N/Aif [[ -z $SCM_MODE ]]; then
312N/A SCM_MODE=`detect_scm $FLIST`
312N/Afi
312N/Aif [[ $SCM_MODE == "unknown" ]]; then
312N/A print -u2 "Unable to determine SCM type currently in use."
312N/A print -u2 "For teamware: webrev looks for \$CODEMGR_WS either in"
312N/A print -u2 " the environment or in the file list."
312N/A print -u2 "For mercurial: webrev runs 'hg root'."
312N/A exit 1
312N/Afi
312N/A
312N/Aprint -u2 " SCM detected: $SCM_MODE"
312N/A
312N/A
312N/Aif [[ $SCM_MODE == "mercurial" ]]; then
312N/A #
312N/A # determine Workspace and parent workspace paths
312N/A #
312N/A CWS=`hg root | $FILTER`
312N/A if [[ -n $pflag && -z "$PWS" ]]; then
312N/A OUTPWS=$codemgr_parent
312N/A # Let's try to expand it if it's an alias defined in [paths]
312N/A tmp=`hg path $OUTPWS 2>/dev/null | $FILTER`
312N/A if [[ -n $tmp ]]; then
312N/A OUTPWS="$tmp"
312N/A fi
312N/A if [[ -n $rflag ]]; then
312N/A if expr "$codemgr_parent" : 'ssh://.*' >/dev/null; then
312N/A PWS=$codemgr_parent
312N/A else
312N/A PWS=`hg -R "$codemgr_parent" root 2>/dev/null | $FILTER`
312N/A fi
312N/A fi
312N/A fi
312N/A #
312N/A # OUTPWS is the parent repository to use when using 'hg outgoing'
312N/A #
312N/A if [[ -z $Nflag ]]; then
312N/A if [[ -n $forestflag ]]; then
312N/A #
312N/A # for forest we have to rely on properly set default and
312N/A # default-push because they can be different from the top one.
312N/A # unless of course it was explicitely speficied with -p
312N/A if [[ -z $pflag ]]; then
312N/A OUTPWS=
312N/A fi
312N/A else
312N/A #
312N/A # Unfortunately mercurial is bugged and doesn't handle
312N/A # aliases correctly in 'hg path default'
312N/A # So let's do it ourselves. Sigh...
312N/A if [[ -z "$OUTPWS" ]]; then
312N/A OUTPWS=`grep default-push $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER`
312N/A fi
312N/A # Still empty, means no default-push
312N/A if [[ -z "$OUTPWS" ]]; then
312N/A OUTPWS=`grep 'default =' $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER`
312N/A fi
312N/A # Let's try to expand it if it's an alias defined in [paths]
312N/A tmp=`hg path $OUTPWS 2>/dev/null | $FILTER`
312N/A if [[ -n $tmp ]]; then
312N/A OUTPWS="$tmp"
312N/A fi
312N/A fi
312N/A fi
312N/A #
312N/A # OUTPWS may contain username:password, let's make sure we remove the
312N/A # sensitive information before we print out anything in the HTML
312N/A #
312N/A OUTPWS2=$OUTPWS
312N/A if [[ -n $OUTPWS ]]; then
312N/A if [[ `expr "$OUTPWS" : '.*://[^/]*@.*'` -gt 0 ]]; then
312N/A # Remove everything between '://' and '@'
312N/A OUTPWS2=`echo $OUTPWS | sed -e 's/\(.*:\/\/\).*@\(.*\)/\1\2/'`
312N/A fi
312N/A fi
312N/A
312N/A if [[ -z $HG_BRANCH ]]; then
312N/A HG_BRANCH=`hg branch`
312N/A if [ "$HG_BRANCH" == "default" ]; then
312N/A #
312N/A # 'default' means no particular branch, so let's cancel that
312N/A #
312N/A HG_BRANCH=
312N/A fi
312N/A fi
312N/A
312N/A if [[ -z $forestflag ]]; then
312N/A if [[ -z $Nflag ]]; then
312N/A #
312N/A # If no "-N", always do "hg outgoing" against parent
312N/A # repository to determine list of outgoing revisions.
312N/A #
312N/A ALL_CREV=`hg outgoing -q --template '{rev}\n' $OUTPWS | sort -n`
312N/A if [[ -n $ALL_CREV ]]; then
312N/A FIRST_CREV=`echo "$ALL_CREV" | head -1`
312N/A #
312N/A # If no "-r", choose revision to compare against by
312N/A # finding the latest revision not in the outgoing list.
312N/A #
312N/A if [[ -z $rflag ]]; then
312N/A OUTREV=`find_outrev "$FIRST_CREV"`
312N/A if [[ -n $OUTREV ]]; then
312N/A HG_LIST_FROM_COMMIT=1
312N/A fi
312N/A fi
312N/A fi
312N/A elif [[ -n $rflag ]]; then
312N/A #
312N/A # If skipping "hg outgoing" but still comparing against a
312N/A # specific revision (not the tip), set revision for comment
312N/A # accumulation.
312N/A #
312N/A FIRST_CREV=`hg log --rev $PARENT_REV --template '{rev}'`
312N/A FIRST_CREV=`expr $FIRST_CREV + 1`
312N/A fi
312N/A fi
312N/A #Let's check if a merge is needed, if so, issue a warning
312N/A PREV=`hg parent | grep '^tag:.*tip$'`
312N/A if [[ -z $PREV ]]; then
312N/A print "WARNING: parent rev is not tip. Maybe an update or merge is needed"
312N/A fi
312N/Afi
312N/A
312N/Aif [[ -n $lflag ]]; then
312N/A #
312N/A # If the -l flag is given instead of the name of a file list,
312N/A # then generate the file list by extracting file names from a
312N/A # putback -n.
312N/A #
312N/A shift $(($OPTIND - 1))
312N/A if [[ $SCM_MODE == "teamware" ]]; then
312N/A flist_from_teamware "$*"
312N/A elif [[ $SCM_MODE == "mercurial" ]]; then
312N/A flist_from_mercurial
312N/A fi
312N/A flist_done=1
312N/A shift $#
312N/A
312N/Aelif [[ -n $wflag ]]; then
312N/A #
312N/A # If the -w is given then assume the file list is in Bonwick's "wx"
312N/A # command format, i.e. pathname lines alternating with SCCS comment
312N/A # lines with blank lines as separators. Use the SCCS comments later
312N/A # in building the index.html file.
312N/A #
312N/A shift $(($OPTIND - 1))
312N/A wxfile=$1
312N/A if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
312N/A if [[ -r $CODEMGR_WS/wx/active ]]; then
312N/A wxfile=$CODEMGR_WS/wx/active
312N/A fi
312N/A fi
312N/A
312N/A [[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
312N/A "be auto-detected (check \$CODEMGR_WS)" && exit 1
312N/A
312N/A print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
312N/A flist_from_wx $wxfile
312N/A flist_done=1
312N/A if [[ -n "$*" ]]; then
312N/A shift
312N/A fi
312N/Aelif [[ $flist_mode == "stdin" ]]; then
312N/A print -u2 " File list from: standard input"
312N/Aelif [[ $flist_mode == "file" ]]; then
312N/A print -u2 " File list from: $flist_file"
312N/Afi
312N/A
312N/Aif [[ $# -gt 0 ]]; then
312N/A print -u2 "WARNING: unused arguments: $*"
312N/Afi
312N/A
312N/Aif [[ $SCM_MODE == "teamware" ]]; then
312N/A #
312N/A # Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
312N/A # be set in a number of ways, in decreasing precedence:
312N/A #
312N/A # 1) on the command line (only for the parent)
312N/A # 2) in the user environment
312N/A # 3) in the flist
312N/A # 4) automatically based on the workspace (only for the parent)
312N/A #
312N/A
312N/A #
312N/A # Here is case (2): the user environment
312N/A #
312N/A [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
312N/A [[ -z $codemgr_ws && -n $WSPACE ]] && codemgr_ws=`$WSPACE name`
607N/A
312N/A if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
312N/A print -u2 "$codemgr_ws: no such workspace"
312N/A exit 1
312N/A fi
312N/A
312N/A [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
312N/A codemgr_parent=$CODEMGR_PARENT
312N/A
312N/A if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
312N/A print -u2 "$codemgr_parent: no such directory"
312N/A exit 1
312N/A fi
312N/A
312N/A #
312N/A # If we're in auto-detect mode and we haven't already gotten the file
312N/A # list, then see if we can get it by probing for wx.
312N/A #
312N/A if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
312N/A if [[ ! -x $WX ]]; then
312N/A print -u2 "WARNING: wx not found!"
312N/A fi
312N/A
312N/A #
312N/A # We need to use wx list -w so that we get renamed files, etc.
312N/A # but only if a wx active file exists-- otherwise wx will
312N/A # hang asking us to initialize our wx information.
312N/A #
312N/A if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
312N/A print -u2 " File list from: 'wx list -w' ... \c"
312N/A $WX list -w > $FLIST
312N/A $WX comments > /tmp/$$.wx_comments
312N/A wxfile=/tmp/$$.wx_comments
312N/A print -u2 "done"
312N/A flist_done=1
312N/A fi
312N/A fi
312N/A
312N/A #
312N/A # If by hook or by crook we've gotten a file list by now (perhaps
312N/A # from the command line), eval it to extract environment variables from
312N/A # it: This is step (3).
312N/A #
312N/A env_from_flist
312N/A
312N/A #
312N/A # Continuing step (3): If we still have no file list, we'll try to get
312N/A # it from teamware.
312N/A #
312N/A if [[ -z $flist_done ]]; then
312N/A flist_from_teamware
312N/A env_from_flist
312N/A fi
312N/A
312N/A if [[ -z $codemgr_ws && -d $PWD/Codemgr_wsdata ]]; then
312N/A codemgr_ws=$PWD
312N/A fi
312N/A #
312N/A # Observe true directory name of CODEMGR_WS, as used later in
312N/A # webrev title.
312N/A #
312N/A if [[ -n $codemgr_ws ]]; then
312N/A codemgr_ws=$(cd $codemgr_ws;print $PWD)
312N/A fi
312N/A
312N/A if [[ -n $codemgr_parent ]]; then
312N/A codemgr_parent=$(cd $codemgr_parent;print $PWD)
312N/A fi
312N/A
312N/A #
312N/A # (4) If we still don't have a value for codemgr_parent, get it
312N/A # from workspace.
312N/A #
312N/A [[ -z $codemgr_parent && -n $WSPACE ]] && codemgr_parent=`$WSPACE parent`
312N/A [[ -z $codemgr_parent ]] && codemgr_parent=`parent_from_teamware $codemgr_ws`
312N/A
312N/A if [[ ! -d $codemgr_parent ]]; then
312N/A print -u2 "$CODEMGR_PARENT: no such parent workspace"
312N/A exit 1
312N/A fi
312N/A
312N/A #
312N/A # Reset CODEMGR_WS to make sure teamware commands are happy.
312N/A #
312N/A CODEMGR_WS=$codemgr_ws
312N/A CWS=$codemgr_ws
312N/A PWS=$codemgr_parent
312N/Aelif [[ $SCM_MODE == "mercurial" ]]; then
312N/A if [[ -z $flist_done ]]; then
312N/A flist_from_mercurial $PWS
312N/A fi
312N/Afi
312N/A
312N/A#
312N/A# If the user didn't specify a -i option, check to see if there is a
312N/A# webrev-info file in the workspace directory.
312N/A#
312N/Aif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
312N/A iflag=1
312N/A INCLUDE_FILE="$CWS/webrev-info"
312N/Afi
312N/A
312N/Aif [[ -n $iflag ]]; then
312N/A if [[ ! -r $INCLUDE_FILE ]]; then
312N/A print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
312N/A "not readable."
312N/A exit 1
312N/A else
312N/A #
312N/A # $INCLUDE_FILE may be a relative path, and the script alters
312N/A # PWD, so we just stash a copy in /tmp.
312N/A #
312N/A cp $INCLUDE_FILE /tmp/$$.include
312N/A fi
312N/Afi
312N/A
312N/A#
312N/A# Output directory.
312N/A#
312N/Aif [[ -z $WDIR ]]; then
312N/A WDIR=$CWS/webrev
312N/Aelse
312N/A # If the output directory doesn't end with '/webrev' or '/webrev/'
312N/A # then add '/webrev'. This is for backward compatibility
312N/A if ! expr $WDIR : '.*/webrev/\?$' >/dev/null
312N/A then
312N/A WDIR=$WDIR/webrev
312N/A fi
312N/Afi
312N/A# WDIR=${WDIR:-$CWS/webrev}
312N/A
312N/A#
312N/A# Name of the webrev, derived from the workspace name; in the
312N/A# future this could potentially be an option.
312N/A#
312N/A# Let's keep what's after the last '/'
312N/AWNAME=${CWS##*/}
312N/A
312N/A#
312N/A# If WDIR doesn't start with '/' or 'x:' prepend the current dir
312N/A#
312N/Aif [ ${WDIR%%/*} ]; then
312N/A if [[ -n $ISWIN ]]; then
312N/A if [ ${WDIR%%[A-Za-z]:*} ]; then
312N/A WDIR=$PWD/$WDIR
312N/A fi
312N/A else
312N/A WDIR=$PWD/$WDIR
312N/A fi
312N/Afi
312N/A
312N/Aif [[ ! -d $WDIR ]]; then
312N/A mkdir -p $WDIR
312N/A [[ $? != 0 ]] && exit 1
312N/Afi
312N/A
312N/A#
312N/A# Summarize what we're going to do.
312N/A#
312N/Aprint " Workspace: $CWS"
312N/Aif [[ -n $parent_webrev ]]; then
312N/A print "Compare against: webrev at $parent_webrev"
312N/Aelif [[ -n $OUTPWS2 ]]; then
312N/A print "Compare against: $OUTPWS2"
312N/Afi
312N/Aif [[ -n $HG_BRANCH ]]; then
312N/A print " Branch: $HG_BRANCH"
312N/Afi
312N/Aif [[ -n $rflag ]]; then
312N/A print "Compare against version: $PARENT_REV"
312N/Afi
312N/A[[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE"
312N/Aprint " Output to: $WDIR"
312N/A
312N/A#
312N/A# Save the file list in the webrev dir
312N/A#
312N/A[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
312N/A
312N/A#
312N/A# Bug IDs will be replaced by a URL. Order of precedence
312N/A# is: default location, $WEBREV_BUGURL, the -O flag.
312N/A#
607N/ABUGURL='https://jbs.oracle.com/bugs/browse/'
312N/A[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
607N/Aif [[ -n "$Oflag" ]]; then
607N/A CRID=`echo $CRID | sed -e 's/JDK-//'`
312N/A BUGURL='http://bugs.sun.com/bugdatabase/view_bug.do?bug_id='
607N/A IDPREFIX=''
607N/Aelse
607N/A IDPREFIX='JDK-'
607N/Afi
607N/A
312N/A
312N/A#
312N/A# Likewise, ARC cases will be replaced by a URL. Order of precedence
312N/A# is: default, $WEBREV_SACURL, the -O flag.
312N/A#
312N/A# Note that -O also triggers different substitution behavior for
312N/A# SACURL. See sac2url().
312N/A#
312N/ASACURL='http://sac.eng.sun.com'
312N/A[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
312N/A[[ -n $Oflag ]] && \
312N/A SACURL='http://www.opensolaris.org/os/community/arc/caselog'
312N/A
312N/Arm -f $WDIR/$WNAME.patch
312N/Arm -f $WDIR/$WNAME.ps
312N/Arm -f $WDIR/$WNAME.pdf
312N/A
312N/Atouch $WDIR/$WNAME.patch
312N/A
312N/Aprint " Output Files:"
312N/A
312N/A#
312N/A# Clean up the file list: Remove comments, blank lines and env variables.
312N/A#
312N/Ased -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean
312N/AFLIST=/tmp/$$.flist.clean
312N/A
312N/A#
312N/A# Clean up residual raw files
312N/A#
312N/Aif [ -d $WDIR/raw_files ]; then
312N/A rm -rf $WDIR/raw_files 2>/dev/null
312N/Afi
312N/A
312N/A#
312N/A# Should we ignore changes in white spaces when generating diffs?
607N/A#
312N/Aif [[ -n $bflag ]]; then
312N/A DIFFOPTS="-t"
312N/Aelse
312N/A DIFFOPTS="-bt"
312N/Afi
312N/A#
312N/A# First pass through the files: generate the per-file webrev HTML-files.
312N/A#
312N/Awhile read LINE
312N/Ado
312N/A set - $LINE
312N/A P=$1
312N/A
312N/A if [[ $1 == "Revision:" ]]; then
312N/A OUTREV=$2
312N/A continue
312N/A fi
312N/A #
312N/A # Normally, each line in the file list is just a pathname of a
312N/A # file that has been modified or created in the child. A file
312N/A # that is renamed in the child workspace has two names on the
312N/A # line: new name followed by the old name.
312N/A #
312N/A oldname=""
312N/A oldpath=""
312N/A rename=
312N/A if [[ $# -eq 2 ]]; then
312N/A PP=$2 # old filename
312N/A oldname=" (was $PP)"
312N/A oldpath="$PP"
312N/A rename=1
312N/A PDIR=${PP%/*}
312N/A if [[ $PDIR == $PP ]]; then
312N/A PDIR="." # File at root of workspace
312N/A fi
312N/A
312N/A PF=${PP##*/}
312N/A
312N/A DIR=${P%/*}
312N/A if [[ $DIR == $P ]]; then
312N/A DIR="." # File at root of workspace
312N/A fi
312N/A
312N/A F=${P##*/}
312N/A else
312N/A DIR=${P%/*}
312N/A if [[ "$DIR" == "$P" ]]; then
312N/A DIR="." # File at root of workspace
312N/A fi
312N/A
312N/A F=${P##*/}
312N/A
312N/A PP=$P
312N/A PDIR=$DIR
312N/A PF=$F
312N/A fi
312N/A
312N/A # Make the webrev directory if necessary as it may have been
312N/A # removed because it was empty
312N/A if [ ! -d $CWS/$DIR ]; then
312N/A mkdir -p $CWS/$DIR
312N/A fi
312N/A
312N/A COMM=`getcomments html $P $PP`
312N/A
312N/A print "\t$P$oldname\n\t\t\c"
312N/A
312N/A # Make the webrev mirror directory if necessary
312N/A mkdir -p $WDIR/$DIR
312N/A
312N/A # cd to the directory so the names are short
312N/A cd $CWS/$DIR
312N/A
312N/A #
312N/A # If we're in OpenSolaris mode, we enforce a minor policy:
312N/A # help to make sure the reviewer doesn't accidentally publish
312N/A # source which is in usr/closed/*
312N/A #
312N/A if [[ -n $Oflag ]]; then
312N/A pclosed=${P##usr/closed/}
312N/A if [[ $pclosed != $P ]]; then
312N/A print "*** Omitting closed source for OpenSolaris" \
312N/A "mode review"
312N/A continue
312N/A fi
312N/A fi
312N/A
312N/A #
312N/A # We stash old and new files into parallel directories in /tmp
312N/A # and do our diffs there. This makes it possible to generate
312N/A # clean looking diffs which don't have absolute paths present.
312N/A #
312N/A olddir=$WDIR/raw_files/old
312N/A newdir=$WDIR/raw_files/new
312N/A mkdir -p $olddir
312N/A mkdir -p $newdir
312N/A mkdir -p $olddir/$PDIR
312N/A mkdir -p $newdir/$DIR
312N/A
312N/A build_old_new $olddir $newdir $DIR $F
312N/A
312N/A if [[ ! -f $F && ! -f $olddir/$DIR/$F ]]; then
312N/A print "*** Error: file not in parent or child"
312N/A continue
312N/A fi
312N/A
312N/A cd $WDIR/raw_files
312N/A ofile=old/$PDIR/$PF
312N/A nfile=new/$DIR/$F
312N/A
312N/A mv_but_nodiff=
312N/A cmp $ofile $nfile > /dev/null 2>&1
312N/A if [[ $? == 0 && $rename == 1 ]]; then
312N/A mv_but_nodiff=1
312N/A fi
312N/A
312N/A #
312N/A # Cleaning up
312N/A #
312N/A rm -f $WDIR/$DIR/$F.cdiff.html
312N/A rm -f $WDIR/$DIR/$F.udiff.html
312N/A rm -f $WDIR/$DIR/$F.wdiff.html
312N/A rm -f $WDIR/$DIR/$F.sdiff.html
312N/A rm -f $WDIR/$DIR/$F-.html
312N/A rm -f $WDIR/$DIR/$F.html
312N/A
312N/A its_a_jar=
783N/A if expr $F : '.*\.jar' \| $F : '.*\.zip' >/dev/null; then
312N/A its_a_jar=1
783N/A # It's a JAR or ZIP file, let's do it differently
312N/A if [[ -z $JAR ]]; then
783N/A print "No access to jar, so can't produce diffs for jar or zip files"
312N/A else
312N/A if [ -f $ofile ]; then
312N/A $JAR -tvf $ofile >"$ofile".lst
312N/A fi
312N/A if [ -f $nfile ]; then
312N/A $JAR -tvf $nfile >"$nfile".lst
312N/A fi
312N/A
312N/A if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
312N/A
312N/A ${CDIFFCMD:-diff -bt -C 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.cdiff
312N/A diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
312N/A > $WDIR/$DIR/$F.cdiff.html
312N/A print " cdiffs\c"
312N/A
312N/A ${UDIFFCMD:-diff -bt -U 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.udiff
312N/A diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
312N/A > $WDIR/$DIR/$F.udiff.html
312N/A
312N/A print " udiffs\c"
312N/A
312N/A if [[ -x $WDIFF ]]; then
312N/A $WDIFF -c "$COMM" \
312N/A -t "$WNAME Wdiff $DIR/$F" $ofile.lst $nfile.lst > \
312N/A $WDIR/$DIR/$F.wdiff.html 2>/dev/null
312N/A if [[ $? -eq 0 ]]; then
312N/A print " wdiffs\c"
312N/A else
312N/A print " wdiffs[fail]\c"
312N/A fi
312N/A fi
312N/A
312N/A sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
312N/A > $WDIR/$DIR/$F.sdiff.html
312N/A print " sdiffs\c"
312N/A
312N/A print " frames\c"
312N/A
312N/A rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
312N/A
312N/A difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count
312N/A
312N/A elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
312N/A # renamed file: may also have differences
312N/A difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count
312N/A elif [[ -f $nfile ]]; then
312N/A # new file: count added lines
312N/A difflines /dev/null $nfile.lst > $WDIR/$DIR/$F.count
312N/A elif [[ -f $ofile ]]; then
312N/A # old file: count deleted lines
312N/A difflines $ofile.lst /dev/null > $WDIR/$DIR/$F.count
312N/A fi
312N/A fi
312N/A else
607N/A
312N/A #
312N/A # If we have old and new versions of the file then run the
312N/A # appropriate diffs. This is complicated by a couple of factors:
312N/A #
312N/A # - renames must be handled specially: we emit a 'remove'
312N/A # diff and an 'add' diff
312N/A # - new files and deleted files must be handled specially
312N/A # - Solaris patch(1m) can't cope with file creation
312N/A # (and hence renames) as of this writing.
312N/A # - To make matters worse, gnu patch doesn't interpret the
312N/A # output of Solaris diff properly when it comes to
312N/A # adds and deletes. We need to do some "cleansing"
312N/A # transformations:
312N/A # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@
312N/A # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@
312N/A #
312N/A cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
312N/A cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
312N/A
312N/A rm -f $WDIR/$DIR/$F.patch
312N/A if [[ -z $rename ]]; then
312N/A if [ ! -f $ofile ]; then
312N/A diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
312N/A > $WDIR/$DIR/$F.patch
312N/A elif [ ! -f $nfile ]; then
312N/A diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
312N/A > $WDIR/$DIR/$F.patch
312N/A else
312N/A diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
312N/A fi
312N/A else
312N/A diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
312N/A > $WDIR/$DIR/$F.patch
312N/A
312N/A diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
312N/A >> $WDIR/$DIR/$F.patch
312N/A
312N/A fi
312N/A
312N/A
312N/A #
312N/A # Tack the patch we just made onto the accumulated patch for the
312N/A # whole wad.
312N/A #
312N/A cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
312N/A
312N/A print " patch\c"
312N/A
312N/A if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
312N/A
312N/A ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
312N/A diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
312N/A > $WDIR/$DIR/$F.cdiff.html
312N/A print " cdiffs\c"
312N/A
312N/A ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
312N/A diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
312N/A > $WDIR/$DIR/$F.udiff.html
312N/A
312N/A print " udiffs\c"
312N/A
312N/A if [[ -x $WDIFF ]]; then
312N/A $WDIFF -c "$COMM" \
312N/A -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
312N/A $WDIR/$DIR/$F.wdiff.html 2>/dev/null
312N/A if [[ $? -eq 0 ]]; then
312N/A print " wdiffs\c"
312N/A else
312N/A print " wdiffs[fail]\c"
312N/A fi
312N/A fi
312N/A
312N/A sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
312N/A > $WDIR/$DIR/$F.sdiff.html
312N/A print " sdiffs\c"
312N/A
312N/A print " frames\c"
312N/A
312N/A rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
312N/A
312N/A difflines $ofile $nfile > $WDIR/$DIR/$F.count
312N/A
312N/A elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
312N/A # renamed file: may also have differences
312N/A difflines $ofile $nfile > $WDIR/$DIR/$F.count
312N/A elif [[ -f $nfile ]]; then
312N/A # new file: count added lines
312N/A difflines /dev/null $nfile > $WDIR/$DIR/$F.count
312N/A elif [[ -f $ofile ]]; then
312N/A # old file: count deleted lines
312N/A difflines $ofile /dev/null > $WDIR/$DIR/$F.count
312N/A fi
312N/A fi
312N/A #
312N/A # Now we generate the postscript for this file. We generate diffs
312N/A # only in the event that there is delta, or the file is new (it seems
312N/A # tree-killing to print out the contents of deleted files).
312N/A #
312N/A if [[ -f $nfile ]]; then
312N/A ocr=$ofile
312N/A [[ ! -f $ofile ]] && ocr=/dev/null
312N/A
312N/A if [[ -z $mv_but_nodiff ]]; then
312N/A textcomm=`getcomments text $P $PP`
312N/A if [[ -x $CODEREVIEW ]]; then
312N/A $CODEREVIEW -y "$textcomm" \
312N/A -e $ocr $nfile \
312N/A > /tmp/$$.psfile 2>/dev/null &&
312N/A cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
312N/A if [[ $? -eq 0 ]]; then
312N/A print " ps\c"
312N/A else
312N/A print " ps[fail]\c"
312N/A fi
312N/A fi
312N/A fi
312N/A fi
312N/A
312N/A if [[ -f $ofile && -z $mv_but_nodiff ]]; then
312N/A if [[ -n $its_a_jar ]]; then
312N/A source_to_html Old $P < $ofile.lst > $WDIR/$DIR/$F-.html
312N/A else
312N/A source_to_html Old $P < $ofile > $WDIR/$DIR/$F-.html
312N/A fi
312N/A print " old\c"
312N/A fi
312N/A
312N/A if [[ -f $nfile ]]; then
312N/A if [[ -n $its_a_jar ]]; then
312N/A source_to_html New $P < $nfile.lst > $WDIR/$DIR/$F.html
312N/A else
312N/A source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
312N/A fi
312N/A print " new\c"
312N/A fi
312N/A
312N/A print
312N/Adone < $FLIST
312N/A
312N/Aframe_nav_js > $WDIR/ancnav.js
312N/Aframe_navigation > $WDIR/ancnav.html
312N/A
312N/Aif [[ -f $WDIR/$WNAME.ps && -x $CODEREVIEW && -x $PS2PDF ]]; then
312N/A print " Generating PDF: \c"
312N/A fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
312N/A print "Done."
312N/Afi
312N/A
312N/A# Now build the index.html file that contains
312N/A# links to the source files and their diffs.
312N/A
312N/Acd $CWS
312N/A
312N/A# Save total changed lines for Code Inspection.
312N/Aprint "$TOTL" > $WDIR/TotalChangedLines
312N/A
312N/Aprint " index.html: \c"
312N/AINDEXFILE=$WDIR/index.html
312N/Aexec 3<&1 # duplicate stdout to FD3.
312N/Aexec 1<&- # Close stdout.
312N/Aexec > $INDEXFILE # Open stdout to index file.
312N/A
312N/Aprint "$HTML<head>"
312N/Aprint "<meta name=\"scm\" content=\"$SCM_MODE\" />"
312N/Aprint "$STDHEAD"
312N/Aprint "<title>$WNAME</title>"
312N/Aprint "</head>"
312N/Aprint "<body id=\"SUNWwebrev\">"
312N/Aprint "<div class=\"summary\">"
312N/Aprint "<h2>Code Review for $WNAME</h2>"
312N/A
312N/Aprint "<table>"
312N/A
312N/Aif [[ -z $uflag ]]
312N/Athen
312N/A if [[ $SCM_MODE == "mercurial" ]]
312N/A then
312N/A #
312N/A # Let's try to extract the user name from the .hgrc file
312N/A #
312N/A username=`grep '^username' $HOME/.hgrc | sed 's/^username[ ]*=[ ]*\(.*\)/\1/'`
312N/A fi
312N/A
312N/A if [[ -z $username ]]
312N/A then
312N/A #
312N/A # Figure out the username and gcos name. To maintain compatibility
312N/A # with passwd(4), we must support '&' substitutions.
312N/A #
312N/A username=`id | cut -d '(' -f 2 | cut -d ')' -f 1`
312N/A if [[ -x $GETENT ]]; then
312N/A realname=`$GETENT passwd $username | cut -d':' -f 5 | cut -d ',' -f 1`
312N/A fi
312N/A userupper=`print "$username" | sed 's/\<./\u&/g'`
312N/A realname=`print $realname | sed s/\&/$userupper/`
312N/A fi
312N/Afi
312N/A
312N/Adate="on `date`"
312N/A
312N/Aif [[ -n "$username" && -n "$realname" ]]; then
312N/A print "<tr><th>Prepared by:</th>"
312N/A print "<td>$realname ($username) $date</td></tr>"
312N/Aelif [[ -n "$username" ]]; then
312N/A print "<tr><th>Prepared by:</th><td>$username $date</td></tr>"
312N/Afi
312N/A
312N/Aprint "<tr><th>Workspace:</th><td>$CWS</td></tr>"
312N/Aif [[ -n $parent_webrev ]]; then
312N/A print "<tr><th>Compare against:</th><td>"
312N/A print "webrev at $parent_webrev"
312N/Aelse
312N/A if [[ -n $OUTPWS2 ]]; then
312N/A print "<tr><th>Compare against:</th><td>"
312N/A print "$OUTPWS2"
312N/A fi
312N/Afi
312N/Aprint "</td></tr>"
312N/Aif [[ -n $rflag ]]; then
312N/A print "<tr><th>Compare against version:</th><td>$PARENT_REV</td></tr>"
312N/Aelif [[ -n $OUTREV ]]; then
312N/A if [[ -z $forestflag ]]; then
312N/A print "<tr><th>Compare against version:</th><td>$OUTREV</td></tr>"
312N/A fi
312N/Afi
312N/Aif [[ -n $HG_BRANCH ]]; then
312N/A print "<tr><th>Branch:</th><td>$HG_BRANCH</td></tr>"
312N/Afi
312N/A
312N/Aprint "<tr><th>Summary of changes:</th><td>"
312N/AprintCI $TOTL $TINS $TDEL $TMOD $TUNC
312N/Aprint "</td></tr>"
312N/A
312N/Aif [[ -f $WDIR/$WNAME.patch ]]; then
312N/A print "<tr><th>Patch of changes:</th><td>"
312N/A print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
312N/Afi
312N/Aif [[ -f $WDIR/$WNAME.pdf ]]; then
312N/A print "<tr><th>Printable review:</th><td>"
312N/A print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
312N/Afi
312N/A
312N/Aif [[ -n "$iflag" ]]; then
312N/A print "<tr><th>Author comments:</th><td><div>"
312N/A cat /tmp/$$.include
312N/A print "</div></td></tr>"
312N/Afi
312N/A# Add links to referenced CRs, if any
312N/A# external URL has a <title> like:
312N/A# <title>Bug ID: 6641309 Wrong Cookie separator used in HttpURLConnection</title>
312N/A# while internal URL has <title> like:
607N/A# <title>[#JDK-6641309] Wrong Cookie separator used in HttpURLConnection</title>
312N/A#
312N/Aif [[ -n $CRID ]]; then
312N/A for id in $CRID
312N/A do
607N/A if [[ -z "$Oflag" ]]; then
607N/A #add "JDK-" to raw bug id for jbs links.
607N/A id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'`
607N/A fi
312N/A print "<tr><th>Bug id:</th><td>"
312N/A url="${BUGURL}${id}"
607N/A if [[ -n "$Oflag" ]]; then
607N/A cleanup='s/Bug ID: \([0-9]\{5,\}\) \(.*\)/JDK-\1 : \2/'
607N/A else
607N/A cleanup='s|\[#\(JDK-[0-9]\{5,\}\)\] \(.*\)|\1 : \2|'
312N/A fi
607N/A if [[ -n $WGET ]]; then
607N/A msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '<title>' | sed 's/<title>\(.*\)<\/title>/\1/' | sed "$cleanup" | html_quote`
312N/A fi
607N/A if [[ -z $msg ]]; then
607N/A msg="${id}"
607N/A fi
607N/A
607N/A print "<a href=\"$url\">$msg</a>"
607N/A
312N/A print "</td></tr>"
312N/A done
312N/Afi
312N/Aprint "<tr><th>Legend:</th><td>"
312N/Aprint "<b>Modified file</b><br><font color=red><b>Deleted file</b></font><br><font color=green><b>New file</b></font></td></tr>"
312N/Aprint "</table>"
312N/Aprint "</div>"
312N/A
312N/A#
312N/A# Second pass through the files: generate the rest of the index file
312N/A#
312N/Awhile read LINE
312N/Ado
312N/A set - $LINE
312N/A if [[ $1 == "Revision:" ]]; then
312N/A FIRST_CREV=`expr $3 + 1`
312N/A continue
312N/A fi
312N/A P=$1
312N/A
312N/A if [[ $# == 2 ]]; then
312N/A PP=$2
312N/A oldname=" <i>(was $PP)</i>"
312N/A
312N/A else
312N/A PP=$P
312N/A oldname=""
312N/A fi
312N/A
312N/A DIR=${P%/*}
312N/A if [[ $DIR == $P ]]; then
312N/A DIR="." # File at root of workspace
312N/A fi
312N/A
312N/A # Avoid processing the same file twice.
312N/A # It's possible for renamed files to
312N/A # appear twice in the file list
312N/A
312N/A F=$WDIR/$P
312N/A
312N/A print "<p><code>"
312N/A
312N/A # If there's a diffs file, make diffs links
312N/A
312N/A NODIFFS=
312N/A if [[ -f $F.cdiff.html ]]; then
312N/A print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
312N/A print "<a href=\"$P.udiff.html\">Udiffs</a>"
312N/A
312N/A if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
312N/A print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
312N/A fi
312N/A
312N/A print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
312N/A
312N/A print "<a href=\"$P.frames.html\">Frames</a>"
312N/A else
312N/A NODIFFS=1
312N/A print " ------ ------ ------"
312N/A
312N/A if [[ -x $WDIFF ]]; then
312N/A print " ------"
312N/A fi
312N/A
312N/A print " ------"
312N/A fi
312N/A
312N/A # If there's an old file, make the link
312N/A
312N/A NOOLD=
312N/A if [[ -f $F-.html ]]; then
312N/A print "<a href=\"$P-.html\">Old</a>"
312N/A else
312N/A NOOLD=1
312N/A print " ---"
312N/A fi
312N/A
312N/A # If there's an new file, make the link
312N/A
312N/A NONEW=
312N/A if [[ -f $F.html ]]; then
312N/A print "<a href=\"$P.html\">New</a>"
312N/A else
312N/A NONEW=1
312N/A print " ---"
312N/A fi
312N/A
312N/A if [[ -f $F.patch ]]; then
312N/A print "<a href=\"$P.patch\">Patch</a>"
312N/A else
312N/A print " -----"
312N/A fi
312N/A
312N/A if [[ -f $WDIR/raw_files/new/$P ]]; then
312N/A print "<a href=\"raw_files/new/$P\">Raw</a>"
312N/A else
312N/A print " ---"
312N/A fi
312N/A print "</code>"
312N/A if [[ -n $NODIFFS && -z $oldname ]]; then
312N/A if [[ -n $NOOLD ]]; then
312N/A print "<font color=green><b>$P</b></font>"
312N/A elif [[ -n $NONEW ]]; then
312N/A print "<font color=red><b>$P</b></font>"
312N/A fi
312N/A else
312N/A print "<b>$P</b> $oldname"
312N/A fi
312N/A
312N/A #
312N/A # Check for usr/closed
312N/A #
312N/A if [ ! -z "$Oflag" ]; then
312N/A if [[ $P == usr/closed/* ]]; then
312N/A print "&nbsp;&nbsp;<i>Closed source: omitted from" \
312N/A "this review</i>"
312N/A fi
312N/A fi
312N/A
312N/A print "</p><blockquote>\c"
312N/A # Insert delta comments if any
312N/A comments=`getcomments html $P $PP`
312N/A if [ -n "$comments" ]; then
312N/A print "<pre>$comments</pre>"
312N/A fi
312N/A
312N/A # Add additional comments comment
312N/A
312N/A print "<!-- Add comments to explain changes in $P here -->"
312N/A
312N/A # Add count of changes.
312N/A
312N/A if [[ -f $F.count ]]; then
312N/A cat $F.count
312N/A rm $F.count
312N/A fi
312N/A print "</blockquote>"
312N/Adone < $FLIST
312N/A
312N/Aprint
312N/Aprint
312N/Aprint "<hr />"
312N/Aprint "<p style=\"font-size: small\">"
312N/Aprint "This code review page was prepared using <b>$0</b>"
312N/Aprint "(vers $WEBREV_UPDATED)."
312N/Aprint "</body>"
312N/Aprint "</html>"
312N/A
312N/Aif [[ -n $ZIP ]]; then
312N/A # Let's generate a zip file for convenience
312N/A cd $WDIR/..
312N/A if [ -f webrev.zip ]; then
312N/A rm webrev.zip
312N/A fi
312N/A $ZIP -r webrev webrev >/dev/null 2>&1
312N/Afi
312N/A
312N/Aexec 1<&- # Close FD 1.
312N/Aexec 1<&3 # dup FD 3 to restore stdout.
312N/Aexec 3<&- # close FD 3.
312N/A
312N/Aprint "Done."
312N/Aprint "Output to: $WDIR"