aoqi@0: #!/bin/ksh -p aoqi@0: # aoqi@0: # CDDL HEADER START aoqi@0: # aoqi@0: # The contents of this file are subject to the terms of the aoqi@0: # Common Development and Distribution License (the "License"). aoqi@0: # You may not use this file except in compliance with the License. aoqi@0: # aoqi@0: # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE aoqi@0: # or http://www.opensolaris.org/os/licensing. aoqi@0: # See the License for the specific language governing permissions aoqi@0: # and limitations under the License. aoqi@0: # aoqi@0: # When distributing Covered Code, include this CDDL HEADER in each aoqi@0: # file and include the License file at usr/src/OPENSOLARIS.LICENSE. aoqi@0: # If applicable, add the following below this CDDL HEADER, with the aoqi@0: # fields enclosed by brackets "[]" replaced with your own identifying aoqi@0: # information: Portions Copyright [yyyy] [name of copyright owner] aoqi@0: # aoqi@0: # CDDL HEADER END aoqi@0: # aoqi@0: # Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: # Use is subject to license terms. aoqi@0: # aoqi@0: # This script takes a file list and a workspace and builds a set of html files aoqi@0: # suitable for doing a code review of source changes via a web page. aoqi@0: # Documentation is available via 'webrev -h'. aoqi@0: # aoqi@0: aoqi@0: WEBREV_UPDATED=25.1-hg+openjdk.java.net aoqi@0: aoqi@0: HTML=' aoqi@0: aoqi@0: \n' aoqi@0: aoqi@0: FRAMEHTML=' aoqi@0: aoqi@0: \n' aoqi@0: aoqi@0: STDHEAD=' aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: ' aoqi@0: aoqi@0: # aoqi@0: # UDiffs need a slightly different CSS rule for 'new' items (we don't aoqi@0: # want them to be bolded as we do in cdiffs or sdiffs). aoqi@0: # aoqi@0: UDIFFCSS=' aoqi@0: aoqi@0: ' aoqi@0: aoqi@0: # aoqi@0: # input_cmd | html_quote | output_cmd aoqi@0: # or aoqi@0: # html_quote filename | output_cmd aoqi@0: # aoqi@0: # Make a piece of source code safe for display in an HTML
 block.
aoqi@0: #
aoqi@0: html_quote()
aoqi@0: {
aoqi@0: 	sed -e "s/&/\&/g" -e "s/&#\([x]*[0-9A-Fa-f]\{2,5\}\);/\&#\1;/g" -e "s//\>/g" "$@" | expand
aoqi@0: }
aoqi@0: 
aoqi@0: #
aoqi@0: # input_cmd | html_quote | output_cmd
aoqi@0: # or
aoqi@0: # html_dequote filename | output_cmd
aoqi@0: #
aoqi@0: # Replace HTML entities with literals
aoqi@0: #
aoqi@0: html_dequote()
aoqi@0: {
aoqi@0: 	sed -e "s/"/\"/g" -e "s/'/\'/g" -e "s/&/\&/g" -e "s/</<'/g" -e "s/>/>/g" "$@" | expand
aoqi@0: }
aoqi@0: 
aoqi@0: #
aoqi@0: # input_cmd | bug2url | output_cmd
aoqi@0: #
aoqi@0: # Scan for bugids and insert  links to the relevent bug database.
aoqi@0: #
aoqi@0: bug2url()
aoqi@0: {
aoqi@0: 	sed -e 's|[0-9]\{5,\}|&|g'
aoqi@0: }
aoqi@0: 
aoqi@0: #
aoqi@0: # strip_unchanged  | output_cmd
aoqi@0: #
aoqi@0: # Removes chunks of sdiff documents that have not changed. This makes it
aoqi@0: # easier for a code reviewer to find the bits that have changed.
aoqi@0: #
aoqi@0: # Deleted lines of text are replaced by a horizontal rule. Some
aoqi@0: # identical lines are retained before and after the changed lines to
aoqi@0: # provide some context.  The number of these lines is controlled by the
aoqi@0: # variable C in the $AWK script below.
aoqi@0: #
aoqi@0: # The script detects changed lines as any line that has a "
"
aoqi@0: 				inx = c % C
aoqi@0: 				c = C
aoqi@0: 			}
aoqi@0: 
aoqi@0: 			for (i = 0; i < c; i++)
aoqi@0: 				print ln[(inx + i) % C]
aoqi@0: 		}
aoqi@0: 		c = 0;
aoqi@0: 		print
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	{	if (c >= C) {
aoqi@0: 			ln[c % C] = $0
aoqi@0: 			c++;
aoqi@0: 			next;
aoqi@0: 		}
aoqi@0: 		c++;
aoqi@0: 		print
aoqi@0: 	}
aoqi@0: 	END	{ if (c > (C * 2)) print "\n

" } aoqi@0: aoqi@0: ' $1 aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # sdiff_to_html aoqi@0: # aoqi@0: # This function takes two files as arguments, obtains their diff, and aoqi@0: # processes the diff output to present the files as an HTML document with aoqi@0: # the files displayed side-by-side, differences shown in color. It also aoqi@0: # takes a delta comment, rendered as an HTML snippet, as the third aoqi@0: # argument. The function takes two files as arguments, then the name of aoqi@0: # file, the path, and the comment. The HTML will be delivered on stdout, aoqi@0: # e.g. aoqi@0: # aoqi@0: # $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \ aoqi@0: # new/usr/src/tools/scripts/webrev.sh \ aoqi@0: # webrev.sh usr/src/tools/scripts \ aoqi@0: # ' aoqi@0: # JDK-1234567 my bugid' > .html aoqi@0: # aoqi@0: # framed_sdiff() is then called which creates $2.frames.html aoqi@0: # in the webrev tree. aoqi@0: # aoqi@0: # FYI: This function is rather unusual in its use of awk. The initial aoqi@0: # diff run produces conventional diff output showing changed lines mixed aoqi@0: # with editing codes. The changed lines are ignored - we're interested in aoqi@0: # the editing codes, e.g. aoqi@0: # aoqi@0: # 8c8 aoqi@0: # 57a61 aoqi@0: # 63c66,76 aoqi@0: # 68,93d80 aoqi@0: # 106d90 aoqi@0: # 108,110d91 aoqi@0: # aoqi@0: # These editing codes are parsed by the awk script and used to generate aoqi@0: # another awk script that generates HTML, e.g the above lines would turn aoqi@0: # into something like this: aoqi@0: # aoqi@0: # BEGIN { printf "
\n" }
aoqi@0: #      function sp(n) {for (i=0;i%4d %s \n", n, NR, $0}
aoqi@0: #      NR==8           {wl("#7A7ADD");next}
aoqi@0: #      NR==54          {wl("#7A7ADD");sp(3);next}
aoqi@0: #      NR==56          {wl("#7A7ADD");next}
aoqi@0: #      NR==57          {wl("black");printf "\n"; next}
aoqi@0: #        :               :
aoqi@0: #
aoqi@0: #  This script is then run on the original source file to generate the
aoqi@0: #  HTML that corresponds to the source file.
aoqi@0: #
aoqi@0: #  The two HTML files are then combined into a single piece of HTML that
aoqi@0: #  uses an HTML table construct to present the files side by side.  You'll
aoqi@0: #  notice that the changes are color-coded:
aoqi@0: #
aoqi@0: #   black     - unchanged lines
aoqi@0: #   blue      - changed lines
aoqi@0: #   bold blue - new lines
aoqi@0: #   brown     - deleted lines
aoqi@0: #
aoqi@0: #  Blank lines are inserted in each file to keep unchanged lines in sync
aoqi@0: #  (side-by-side).  This format is familiar to users of sdiff(1) or
aoqi@0: #  Teamware's filemerge tool.
aoqi@0: #
aoqi@0: sdiff_to_html()
aoqi@0: {
aoqi@0: 	diff -b $1 $2 > /tmp/$$.diffs
aoqi@0: 
aoqi@0: 	TNAME=$3
aoqi@0: 	TPATH=$4
aoqi@0: 	COMMENT=$5
aoqi@0: 
aoqi@0: 	#
aoqi@0: 	#  Now we have the diffs, generate the HTML for the old file.
aoqi@0: 	#
aoqi@0: 	$AWK '
aoqi@0: 	BEGIN	{
aoqi@0: 		printf "function sp(n) {for (i=0;i%%4d %%s\\n\", NR, $0}\n"
aoqi@0: 		printf "function changed() "
aoqi@0: 		printf "{printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0: 		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0: }
aoqi@0: 	/^/	{next}
aoqi@0: 	/^---/	{next}
aoqi@0: 
aoqi@0: 	{
aoqi@0: 	split($1, a, /[cad]/) ;
aoqi@0: 	if (index($1, "a")) {
aoqi@0: 		if (a[1] == 0) {
aoqi@0: 			n = split(a[2], r, /,/);
aoqi@0: 			if (n == 1)
aoqi@0: 				printf "BEGIN\t\t{sp(1)}\n"
aoqi@0: 			else
aoqi@0: 				printf "BEGIN\t\t{sp(%d)}\n",\
aoqi@0: 				(r[2] - r[1]) + 1
aoqi@0: 			next
aoqi@0: 		}
aoqi@0: 
aoqi@0: 		printf "NR==%s\t\t{", a[1]
aoqi@0: 		n = split(a[2], r, /,/);
aoqi@0: 		s = r[1];
aoqi@0: 		if (n == 1)
aoqi@0: 			printf "bl();printf \"\\n\"; next}\n"
aoqi@0: 		else {
aoqi@0: 			n = r[2] - r[1]
aoqi@0: 			printf "bl();sp(%d);next}\n",\
aoqi@0: 			(r[2] - r[1]) + 1
aoqi@0: 		}
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	if (index($1, "d")) {
aoqi@0: 		n = split(a[1], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		if (n == 1)
aoqi@0: 			printf "NR==%s\t\t{removed(); next}\n" , n1
aoqi@0: 		else
aoqi@0: 			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	if (index($1, "c")) {
aoqi@0: 		n = split(a[1], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		final = n2
aoqi@0: 		d1 = 0
aoqi@0: 		if (n == 1)
aoqi@0: 			printf "NR==%s\t\t{changed();" , n1
aoqi@0: 		else {
aoqi@0: 			d1 = n2 - n1
aoqi@0: 			printf "NR==%s,NR==%s\t{changed();" , n1, n2
aoqi@0: 		}
aoqi@0: 		m = split(a[2], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		if (m > 1) {
aoqi@0: 			d2  = n2 - n1
aoqi@0: 			if (d2 > d1) {
aoqi@0: 				if (n > 1) printf "if (NR==%d)", final
aoqi@0: 				printf "sp(%d);", d2 - d1
aoqi@0: 			}
aoqi@0: 		}
aoqi@0: 		printf "next}\n" ;
aoqi@0: 
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	}
aoqi@0: 
aoqi@0: 	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
aoqi@0: 	' /tmp/$$.diffs > /tmp/$$.file1
aoqi@0: 
aoqi@0: 	#
aoqi@0: 	#  Now generate the HTML for the new file
aoqi@0: 	#
aoqi@0: 	$AWK '
aoqi@0: 	BEGIN	{
aoqi@0: 		printf "function sp(n) {for (i=0;i%%4d %%s\\n\", NR, $0}\n"
aoqi@0: 		printf "function changed() "
aoqi@0: 		printf "{printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0: 		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0: 	}
aoqi@0: 
aoqi@0: 	/^/	{next}
aoqi@0: 	/^---/	{next}
aoqi@0: 
aoqi@0: 	{
aoqi@0: 	split($1, a, /[cad]/) ;
aoqi@0: 	if (index($1, "d")) {
aoqi@0: 		if (a[2] == 0) {
aoqi@0: 			n = split(a[1], r, /,/);
aoqi@0: 			if (n == 1)
aoqi@0: 				printf "BEGIN\t\t{sp(1)}\n"
aoqi@0: 			else
aoqi@0: 				printf "BEGIN\t\t{sp(%d)}\n",\
aoqi@0: 				(r[2] - r[1]) + 1
aoqi@0: 			next
aoqi@0: 		}
aoqi@0: 
aoqi@0: 		printf "NR==%s\t\t{", a[2]
aoqi@0: 		n = split(a[1], r, /,/);
aoqi@0: 		s = r[1];
aoqi@0: 		if (n == 1)
aoqi@0: 			printf "bl();printf \"\\n\"; next}\n"
aoqi@0: 		else {
aoqi@0: 			n = r[2] - r[1]
aoqi@0: 			printf "bl();sp(%d);next}\n",\
aoqi@0: 			(r[2] - r[1]) + 1
aoqi@0: 		}
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	if (index($1, "a")) {
aoqi@0: 		n = split(a[2], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		if (n == 1)
aoqi@0: 			printf "NR==%s\t\t{new() ; next}\n" , n1
aoqi@0: 		else
aoqi@0: 			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	if (index($1, "c")) {
aoqi@0: 		n = split(a[2], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		final = n2
aoqi@0: 		d2 = 0;
aoqi@0: 		if (n == 1) {
aoqi@0: 			final = n1
aoqi@0: 			printf "NR==%s\t\t{changed();" , n1
aoqi@0: 		} else {
aoqi@0: 			d2 = n2 - n1
aoqi@0: 			printf "NR==%s,NR==%s\t{changed();" , n1, n2
aoqi@0: 		}
aoqi@0: 		m = split(a[1], r, /,/);
aoqi@0: 		n1 = r[1]
aoqi@0: 		n2 = r[2]
aoqi@0: 		if (m > 1) {
aoqi@0: 			d1  = n2 - n1
aoqi@0: 			if (d1 > d2) {
aoqi@0: 				if (n > 1) printf "if (NR==%d)", final
aoqi@0: 				printf "sp(%d);", d1 - d2
aoqi@0: 			}
aoqi@0: 		}
aoqi@0: 		printf "next}\n" ;
aoqi@0: 		next
aoqi@0: 	}
aoqi@0: 	}
aoqi@0: 	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
aoqi@0: 	' /tmp/$$.diffs > /tmp/$$.file2
aoqi@0: 
aoqi@0: 	#
aoqi@0: 	# Post-process the HTML files by running them back through $AWK
aoqi@0: 	#
aoqi@0: 	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
aoqi@0: 
aoqi@0: 	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
aoqi@0: 
aoqi@0: 	#
aoqi@0: 	# Now combine into a valid HTML file and side-by-side into a table
aoqi@0: 	#
aoqi@0: 	print "$HTML$STDHEAD"
aoqi@0: 	print "$WNAME Sdiff $TPATH "
aoqi@0: 	print ""
aoqi@0: 	print "

$TPATH/$TNAME

" aoqi@0: print "Print this page" aoqi@0: print "
$COMMENT
\n" aoqi@0: print "" aoqi@0: print "" aoqi@0: print "
"
aoqi@0: 
aoqi@0: 	strip_unchanged /tmp/$$.file1.html
aoqi@0: 
aoqi@0: 	print "
"
aoqi@0: 
aoqi@0: 	strip_unchanged /tmp/$$.file2.html
aoqi@0: 
aoqi@0: 	print "
" aoqi@0: print "" aoqi@0: aoqi@0: framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \ aoqi@0: "$COMMENT" aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # framed_sdiff aoqi@0: # aoqi@0: # Expects lefthand and righthand side html files created by sdiff_to_html. aoqi@0: # We use insert_anchors() to augment those with HTML navigation anchors, aoqi@0: # and then emit the main frame. Content is placed into: aoqi@0: # aoqi@0: # $WDIR/DIR/$TNAME.lhs.html aoqi@0: # $WDIR/DIR/$TNAME.rhs.html aoqi@0: # $WDIR/DIR/$TNAME.frames.html aoqi@0: # aoqi@0: # NOTE: We rely on standard usage of $WDIR and $DIR. aoqi@0: # aoqi@0: function framed_sdiff aoqi@0: { aoqi@0: typeset TNAME=$1 aoqi@0: typeset TPATH=$2 aoqi@0: typeset lhsfile=$3 aoqi@0: typeset rhsfile=$4 aoqi@0: typeset comments=$5 aoqi@0: typeset RTOP aoqi@0: aoqi@0: # Enable html files to access WDIR via a relative path. aoqi@0: RTOP=$(relative_dir $TPATH $WDIR) aoqi@0: aoqi@0: # Make the rhs/lhs files and output the frameset file. aoqi@0: print "$HTML$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html aoqi@0: aoqi@0: cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
$comments

aoqi@0: EOF aoqi@0: aoqi@0: cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html aoqi@0: aoqi@0: insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html aoqi@0: insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html aoqi@0: aoqi@0: close='' aoqi@0: aoqi@0: print $close >> $WDIR/$DIR/$TNAME.lhs.html aoqi@0: print $close >> $WDIR/$DIR/$TNAME.rhs.html aoqi@0: aoqi@0: print "$FRAMEHTML$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html aoqi@0: print "$WNAME Framed-Sdiff " \ aoqi@0: "$TPATH/$TNAME " >> $WDIR/$DIR/$TNAME.frames.html aoqi@0: cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: <body id="SUNWwebrev"> aoqi@0: Alas 'frames' webrev requires that your browser supports frames aoqi@0: and has the feature enabled. aoqi@0: </body> aoqi@0: aoqi@0: aoqi@0: aoqi@0: EOF aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # fix_postscript aoqi@0: # aoqi@0: # Merge codereview output files to a single conforming postscript file, by: aoqi@0: # - removing all extraneous headers/trailers aoqi@0: # - making the page numbers right aoqi@0: # - removing pages devoid of contents which confuse some aoqi@0: # postscript readers. aoqi@0: # aoqi@0: # From Casper. aoqi@0: # aoqi@0: function fix_postscript aoqi@0: { aoqi@0: infile=$1 aoqi@0: aoqi@0: cat > /tmp/$$.crmerge.pl << \EOF aoqi@0: aoqi@0: print scalar(<>); # %!PS-Adobe--- aoqi@0: print "%%Orientation: Landscape\n"; aoqi@0: aoqi@0: $pno = 0; aoqi@0: $doprint = 1; aoqi@0: aoqi@0: $page = ""; aoqi@0: aoqi@0: while (<>) { aoqi@0: next if (/^%%Pages:\s*\d+/); aoqi@0: aoqi@0: if (/^%%Page:/) { aoqi@0: if ($pno == 0 || $page =~ /\)S/) { aoqi@0: # Header or single page containing text aoqi@0: print "%%Page: ? $pno\n" if ($pno > 0); aoqi@0: print $page; aoqi@0: $pno++; aoqi@0: } else { aoqi@0: # Empty page, skip it. aoqi@0: } aoqi@0: $page = ""; aoqi@0: $doprint = 1; aoqi@0: next; aoqi@0: } aoqi@0: aoqi@0: # Skip from %%Trailer of one document to Endprolog aoqi@0: # %%Page of the next aoqi@0: $doprint = 0 if (/^%%Trailer/); aoqi@0: $page .= $_ if ($doprint); aoqi@0: } aoqi@0: aoqi@0: if ($page =~ /\)S/) { aoqi@0: print "%%Page: ? $pno\n"; aoqi@0: print $page; aoqi@0: } else { aoqi@0: $pno--; aoqi@0: } aoqi@0: print "%%Trailer\n%%Pages: $pno\n"; aoqi@0: EOF aoqi@0: aoqi@0: $PERL /tmp/$$.crmerge.pl < $infile aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # input_cmd | insert_anchors | output_cmd aoqi@0: # aoqi@0: # Flag blocks of difference with sequentially numbered invisible aoqi@0: # anchors. These are used to drive the frames version of the aoqi@0: # sdiffs output. aoqi@0: # aoqi@0: # NOTE: Anchor zero flags the top of the file irrespective of changes, aoqi@0: # an additional anchor is also appended to flag the bottom. aoqi@0: # aoqi@0: # The script detects changed lines as any line that has a "", anc, anc++; aoqi@0: } aoqi@0: aoqi@0: BEGIN { aoqi@0: anc=1; aoqi@0: inblock=1; aoqi@0: printf "
\n";
aoqi@0: 	}
aoqi@0: 	NF == 0 || /^";
aoqi@0: 		printf "--- EOF ---"
aoqi@0:         	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
aoqi@0: 		printf "
" aoqi@0: printf "
"; aoqi@0: printf "", aoqi@0: anc - 1; aoqi@0: printf "
"; aoqi@0: } aoqi@0: ' $1 aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # relative_dir aoqi@0: # aoqi@0: # Print a relative return path from $1 to $2. For example if aoqi@0: # $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview, aoqi@0: # this function would print "../../../../". aoqi@0: # aoqi@0: # In the event that $1 is not in $2 a warning is printed to stderr, aoqi@0: # and $2 is returned-- the result of this is that the resulting webrev aoqi@0: # is not relocatable. aoqi@0: # aoqi@0: function relative_dir aoqi@0: { aoqi@0: d1=$1 aoqi@0: d2=$2 aoqi@0: if [[ "$d1" == "." ]]; then aoqi@0: print "." aoqi@0: else aoqi@0: typeset cur="${d1##$d2?(/)}" aoqi@0: typeset ret="" aoqi@0: if [[ $d2 == $cur ]]; then # Should never happen. aoqi@0: # Should never happen. aoqi@0: print -u2 "\nWARNING: relative_dir: \"$1\" not relative " aoqi@0: print -u2 "to \"$2\". Check input paths. Framed webrev " aoqi@0: print -u2 "will not be relocatable!" aoqi@0: print $2 aoqi@0: return aoqi@0: fi aoqi@0: aoqi@0: while [[ -n ${cur} ]]; aoqi@0: do aoqi@0: cur=${cur%%*(/)*([!/])} aoqi@0: if [[ -z $ret ]]; then aoqi@0: ret=".." aoqi@0: else aoqi@0: ret="../$ret" aoqi@0: fi aoqi@0: done aoqi@0: print $ret aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # frame_nav_js aoqi@0: # aoqi@0: # Emit javascript for frame navigation aoqi@0: # aoqi@0: function frame_nav_js aoqi@0: { aoqi@0: cat << \EOF aoqi@0: var myInt; aoqi@0: var scrolling=0; aoqi@0: var sfactor = 3; aoqi@0: var scount=10; aoqi@0: aoqi@0: function scrollByPix() { aoqi@0: if (scount<=0) { aoqi@0: sfactor*=1.2; aoqi@0: scount=10; aoqi@0: } aoqi@0: parent.lhs.scrollBy(0,sfactor); aoqi@0: parent.rhs.scrollBy(0,sfactor); aoqi@0: scount--; aoqi@0: } aoqi@0: aoqi@0: function scrollToAnc(num) { aoqi@0: aoqi@0: // Update the value of the anchor in the form which we use as aoqi@0: // storage for this value. setAncValue() will take care of aoqi@0: // correcting for overflow and underflow of the value and return aoqi@0: // us the new value. aoqi@0: num = setAncValue(num); aoqi@0: aoqi@0: // Set location and scroll back a little to expose previous aoqi@0: // lines. aoqi@0: // aoqi@0: // Note that this could be improved: it is possible although aoqi@0: // complex to compute the x and y position of an anchor, and to aoqi@0: // scroll to that location directly. aoqi@0: // aoqi@0: parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num); aoqi@0: parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num); aoqi@0: aoqi@0: parent.lhs.scrollBy(0,-30); aoqi@0: parent.rhs.scrollBy(0,-30); aoqi@0: } aoqi@0: aoqi@0: function getAncValue() aoqi@0: { aoqi@0: return (parseInt(parent.nav.document.diff.real.value)); aoqi@0: } aoqi@0: aoqi@0: function setAncValue(val) aoqi@0: { aoqi@0: if (val <= 0) { aoqi@0: val = 0; aoqi@0: parent.nav.document.diff.real.value = val; aoqi@0: parent.nav.document.diff.display.value = "BOF"; aoqi@0: return (val); aoqi@0: } aoqi@0: aoqi@0: // aoqi@0: // The way we compute the max anchor value is to stash it aoqi@0: // inline in the left and right hand side pages-- it's the same aoqi@0: // on each side, so we pluck from the left. aoqi@0: // aoqi@0: maxval = parent.lhs.document.eof.value.value; aoqi@0: if (val < maxval) { aoqi@0: parent.nav.document.diff.real.value = val; aoqi@0: parent.nav.document.diff.display.value = val.toString(); aoqi@0: return (val); aoqi@0: } aoqi@0: aoqi@0: // this must be: val >= maxval aoqi@0: val = maxval; aoqi@0: parent.nav.document.diff.real.value = val; aoqi@0: parent.nav.document.diff.display.value = "EOF"; aoqi@0: return (val); aoqi@0: } aoqi@0: aoqi@0: function stopScroll() { aoqi@0: if (scrolling==1) { aoqi@0: clearInterval(myInt); aoqi@0: scrolling=0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: function startScroll() { aoqi@0: stopScroll(); aoqi@0: scrolling=1; aoqi@0: myInt=setInterval("scrollByPix()",10); aoqi@0: } aoqi@0: aoqi@0: function handlePress(b) { aoqi@0: aoqi@0: switch (b) { aoqi@0: case 1 : aoqi@0: scrollToAnc(-1); aoqi@0: break; aoqi@0: case 2 : aoqi@0: scrollToAnc(getAncValue() - 1); aoqi@0: break; aoqi@0: case 3 : aoqi@0: sfactor=-3; aoqi@0: startScroll(); aoqi@0: break; aoqi@0: case 4 : aoqi@0: sfactor=3; aoqi@0: startScroll(); aoqi@0: break; aoqi@0: case 5 : aoqi@0: scrollToAnc(getAncValue() + 1); aoqi@0: break; aoqi@0: case 6 : aoqi@0: scrollToAnc(999999); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: function handleRelease(b) { aoqi@0: stopScroll(); aoqi@0: } aoqi@0: aoqi@0: function keypress(ev) { aoqi@0: var keynum; aoqi@0: var keychar; aoqi@0: aoqi@0: if (window.event) { // IE aoqi@0: keynum = ev.keyCode; aoqi@0: } else if (ev.which) { // non-IE aoqi@0: keynum = ev.which; aoqi@0: } aoqi@0: aoqi@0: keychar = String.fromCharCode(keynum); aoqi@0: aoqi@0: if (keychar == "k") { aoqi@0: handlePress(2); aoqi@0: return (0); aoqi@0: } else if (keychar == "j" || keychar == " ") { aoqi@0: handlePress(5); aoqi@0: return (0); aoqi@0: } aoqi@0: return (1); aoqi@0: } aoqi@0: aoqi@0: function ValidateDiffNum(){ aoqi@0: val = parent.nav.document.diff.display.value; aoqi@0: if (val == "EOF") { aoqi@0: scrollToAnc(999999); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: if (val == "BOF") { aoqi@0: scrollToAnc(0); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: i=parseInt(val); aoqi@0: if (isNaN(i)) { aoqi@0: parent.nav.document.diff.display.value = getAncValue(); aoqi@0: } else { aoqi@0: scrollToAnc(i); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: EOF aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # frame_navigation aoqi@0: # aoqi@0: # Output anchor navigation file for framed sdiffs. aoqi@0: # aoqi@0: function frame_navigation aoqi@0: { aoqi@0: print "$HTML$STDHEAD" aoqi@0: aoqi@0: cat << \EOF aoqi@0: Anchor Navigation aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: EOF aoqi@0: aoqi@0: print "" aoqi@0: aoqi@0: cat << \EOF aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
Diff navigation: aoqi@0: Use 'j' and 'k' for next and previous diffs; or use buttons aoqi@0: at right aoqi@0:
aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: BOF aoqi@0: Scroll Up aoqi@0: Prev Diff aoqi@0:
aoqi@0: EOF aoqi@0: Scroll Down aoqi@0: Next Diff
aoqi@0:
aoqi@0:
aoqi@0:
aoqi@0: aoqi@0: aoqi@0:
aoqi@0:
aoqi@0: aoqi@0: aoqi@0: EOF aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # diff_to_html { U | C } aoqi@0: # aoqi@0: # Processes the output of diff to produce an HTML file representing either aoqi@0: # context or unified diffs. aoqi@0: # aoqi@0: diff_to_html() aoqi@0: { aoqi@0: TNAME=$1 aoqi@0: TPATH=$2 aoqi@0: DIFFTYPE=$3 aoqi@0: COMMENT=$4 aoqi@0: aoqi@0: print "$HTML$STDHEAD" aoqi@0: print "$WNAME ${DIFFTYPE}diff $TPATH" aoqi@0: aoqi@0: if [[ $DIFFTYPE == "U" ]]; then aoqi@0: print "$UDIFFCSS" aoqi@0: fi aoqi@0: aoqi@0: cat <<-EOF aoqi@0: aoqi@0: aoqi@0:

$TPATH

aoqi@0: Print this page aoqi@0:
$COMMENT
aoqi@0:
aoqi@0: EOF
aoqi@0: 
aoqi@0: 	html_quote | $AWK '
aoqi@0: 	/^--- new/	{ next }
aoqi@0: 	/^\+\+\+ new/	{ next }
aoqi@0: 	/^--- old/	{ next }
aoqi@0: 	/^\*\*\* old/	{ next }
aoqi@0: 	/^\*\*\*\*/	{ next }
aoqi@0: 	/^-------/	{ printf "

%s

\n", $0; next } aoqi@0: /^\@\@.*\@\@$/ { printf "

\n";
aoqi@0: 			  printf "%s\n", $0;
aoqi@0: 			  next}
aoqi@0: 
aoqi@0: 	/^\*\*\*/	{ printf "
%s\n", $0; aoqi@0: next} aoqi@0: /^---/ { printf "%s\n", $0; aoqi@0: next} aoqi@0: /^\+/ {printf "%s\n", $0; next} aoqi@0: /^!/ {printf "%s\n", $0; next} aoqi@0: /^-/ {printf "%s\n", $0; next} aoqi@0: {printf "%s\n", $0; next} aoqi@0: ' aoqi@0: aoqi@0: print "
\n" aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # source_to_html { new | old } aoqi@0: # aoqi@0: # Process a plain vanilla source file to transform it into an HTML file. aoqi@0: # aoqi@0: source_to_html() aoqi@0: { aoqi@0: WHICH=$1 aoqi@0: TNAME=$2 aoqi@0: aoqi@0: print "$HTML$STDHEAD" aoqi@0: print "$WHICH $TNAME" aoqi@0: print "" aoqi@0: print "
"
aoqi@0: 	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
aoqi@0: 	print "
" aoqi@0: } aoqi@0: aoqi@0: comments_from_mercurial() aoqi@0: { aoqi@0: fmt=$1 aoqi@0: pfile=$PWS/$2 aoqi@0: cfile=$CWS/$3 aoqi@0: aoqi@0: logdir=`dirname $cfile` aoqi@0: logf=`basename $cfile` aoqi@0: if [ -d $logdir ]; then aoqi@0: ( cd $logdir; aoqi@0: active=`hg status $logf 2>/dev/null` aoqi@0: # If the output from 'hg status' is not empty, it means the file aoqi@0: # hasn't been committed, so don't fetch comments. aoqi@0: if [[ -z $active ]] ; then aoqi@0: if [[ -n $ALL_CREV ]]; then aoqi@0: rev_opt= aoqi@0: for rev in $ALL_CREV; do aoqi@0: rev_opt="$rev_opt --rev $rev" aoqi@0: done aoqi@0: comm=`hg log $rev_opt --follow --template 'rev {rev} : {desc}\n' $logf` aoqi@0: elif [[ -n $FIRST_CREV ]]; then aoqi@0: comm=`hg log --rev $FIRST_CREV:tip --follow --template 'rev {rev} : {desc}\n' $logf` aoqi@0: else aoqi@0: comm=`hg log -l1 --follow --template 'rev {rev} : {desc}\n' $logf` aoqi@0: fi aoqi@0: else aoqi@0: comm="" aoqi@0: fi aoqi@0: if [[ $fmt == "text" ]]; then aoqi@0: print "$comm" aoqi@0: return aoqi@0: fi aoqi@0: aoqi@0: print "$comm" | html_quote | bug2url aoqi@0: ) aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # getcomments {text|html} filepath parentpath aoqi@0: # aoqi@0: # Fetch the comments depending on what SCM mode we're in. aoqi@0: # aoqi@0: getcomments() aoqi@0: { aoqi@0: typeset fmt=$1 aoqi@0: typeset p=$2 aoqi@0: typeset pp=$3 aoqi@0: aoqi@0: comments_from_mercurial $fmt $pp $p aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # printCI aoqi@0: # aoqi@0: # Print out Code Inspection figures similar to sccs-prt(1) format. aoqi@0: # aoqi@0: function printCI aoqi@0: { aoqi@0: integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5 aoqi@0: typeset str aoqi@0: if (( tot == 1 )); then aoqi@0: str="line" aoqi@0: else aoqi@0: str="lines" aoqi@0: fi aoqi@0: printf '%d %s changed: %d ins; %d del; %d mod; %d unchg' \ aoqi@0: $tot $str $ins $del $mod $unc aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # difflines aoqi@0: # aoqi@0: # Calculate and emit number of added, removed, modified and unchanged lines, aoqi@0: # and total lines changed, the sum of added + removed + modified. aoqi@0: # aoqi@0: function difflines aoqi@0: { aoqi@0: integer tot mod del ins unc err aoqi@0: typeset filename aoqi@0: aoqi@0: eval $( diff -e $1 $2 | $AWK ' aoqi@0: # Change range of lines: N,Nc aoqi@0: /^[0-9]*,[0-9]*c$/ { aoqi@0: n=split(substr($1,1,length($1)-1), counts, ","); aoqi@0: if (n != 2) { aoqi@0: error=2 aoqi@0: exit; aoqi@0: } aoqi@0: # aoqi@0: # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines. aoqi@0: # following would be 5 - 3 = 2! Hence +1 for correction. aoqi@0: # aoqi@0: r=(counts[2]-counts[1])+1; aoqi@0: aoqi@0: # aoqi@0: # Now count replacement lines: each represents a change instead aoqi@0: # of a delete, so increment c and decrement r. aoqi@0: # aoqi@0: while (getline != /^\.$/) { aoqi@0: c++; aoqi@0: r--; aoqi@0: } aoqi@0: # aoqi@0: # If there were more replacement lines than original lines, aoqi@0: # then r will be negative; in this case there are no deletions, aoqi@0: # but there are r changes that should be counted as adds, and aoqi@0: # since r is negative, subtract it from a and add it to c. aoqi@0: # aoqi@0: if (r < 0) { aoqi@0: a-=r; aoqi@0: c+=r; aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # If there were more original lines than replacement lines, then aoqi@0: # r will be positive; in this case, increment d by that much. aoqi@0: # aoqi@0: if (r > 0) { aoqi@0: d+=r; aoqi@0: } aoqi@0: next; aoqi@0: } aoqi@0: aoqi@0: # Change lines: Nc aoqi@0: /^[0-9].*c$/ { aoqi@0: # The first line is a replacement; any more are additions. aoqi@0: if (getline != /^\.$/) { aoqi@0: c++; aoqi@0: while (getline != /^\.$/) a++; aoqi@0: } aoqi@0: next; aoqi@0: } aoqi@0: aoqi@0: # Add lines: both Na and N,Na aoqi@0: /^[0-9].*a$/ { aoqi@0: while (getline != /^\.$/) a++; aoqi@0: next; aoqi@0: } aoqi@0: aoqi@0: # Delete range of lines: N,Nd aoqi@0: /^[0-9]*,[0-9]*d$/ { aoqi@0: n=split(substr($1,1,length($1)-1), counts, ","); aoqi@0: if (n != 2) { aoqi@0: error=2 aoqi@0: exit; aoqi@0: } aoqi@0: # aoqi@0: # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines. aoqi@0: # following would be 5 - 3 = 2! Hence +1 for correction. aoqi@0: # aoqi@0: r=(counts[2]-counts[1])+1; aoqi@0: d+=r; aoqi@0: next; aoqi@0: } aoqi@0: aoqi@0: # Delete line: Nd. For example 10d says line 10 is deleted. aoqi@0: /^[0-9]*d$/ {d++; next} aoqi@0: aoqi@0: # Should not get here! aoqi@0: { aoqi@0: error=1; aoqi@0: exit; aoqi@0: } aoqi@0: aoqi@0: # Finish off - print results aoqi@0: END { aoqi@0: printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n", aoqi@0: (c+d+a), c, d, a, error); aoqi@0: }' ) aoqi@0: aoqi@0: # End of $AWK, Check to see if any trouble occurred. aoqi@0: if (( $? > 0 || err > 0 )); then aoqi@0: print "Unexpected Error occurred reading" \ aoqi@0: "\`diff -e $1 $2\`: \$?=$?, err=" $err aoqi@0: return aoqi@0: fi aoqi@0: aoqi@0: # Accumulate totals aoqi@0: (( TOTL += tot )) aoqi@0: (( TMOD += mod )) aoqi@0: (( TDEL += del )) aoqi@0: (( TINS += ins )) aoqi@0: # Calculate unchanged lines aoqi@0: unc=`wc -l < $1` aoqi@0: if (( unc > 0 )); then aoqi@0: (( unc -= del + mod )) aoqi@0: (( TUNC += unc )) aoqi@0: fi aoqi@0: # print summary aoqi@0: print "\c" aoqi@0: printCI $tot $ins $del $mod $unc aoqi@0: print "" aoqi@0: } aoqi@0: aoqi@0: function outgoing_from_mercurial_forest aoqi@0: { aoqi@0: hg foutgoing --template 'rev: {rev}\n' $OUTPWS | $FILTER | $AWK ' aoqi@0: BEGIN {ntree=0} aoqi@0: /^comparing/ {next} aoqi@0: /^no changes/ {next} aoqi@0: /^searching/ {next} aoqi@0: /^\[.*\]$/ {tree=substr($1,2,length($1)-2); aoqi@0: trees[ntree++] = tree; aoqi@0: revs[tree]=-1; aoqi@0: next} aoqi@0: /^rev:/ {rev=$2+0; aoqi@0: if (revs[tree] == -1 || rev < revs[tree]) aoqi@0: { revs[tree] = rev; }; aoqi@0: next;} aoqi@0: END {for (tree in trees) aoqi@0: { rev=revs[trees[tree]]; aoqi@0: if (rev > 0) aoqi@0: {printf("%s %d\n",trees[tree],rev-1)} aoqi@0: }}' | while read LINE aoqi@0: do aoqi@0: set - $LINE aoqi@0: TREE=$1 aoqi@0: REV=$2 aoqi@0: A=`hg -R $CWS/$TREE log --rev $REV --template '{node}'` aoqi@0: FSTAT_OPT="--rev $A" aoqi@0: print "Revision: $A $REV" >> $FLIST aoqi@0: treestatus $TREE aoqi@0: done aoqi@0: } aoqi@0: aoqi@0: function flist_from_mercurial_forest aoqi@0: { aoqi@0: rm -f $FLIST aoqi@0: if [ -z "$Nflag" ]; then aoqi@0: print " File list from hg foutgoing $PWS ..." aoqi@0: outgoing_from_mercurial_forest aoqi@0: HG_LIST_FROM_COMMIT=1 aoqi@0: fi aoqi@0: if [ ! -f $FLIST ]; then aoqi@0: # hg commit hasn't been run see what is lying around aoqi@0: print "\n No outgoing, perhaps you haven't commited." aoqi@0: print " File list from hg fstatus -mard ...\c" aoqi@0: FSTAT_OPT= aoqi@0: fstatus aoqi@0: HG_LIST_FROM_COMMIT= aoqi@0: fi aoqi@0: print " Done." aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # Used when dealing with the result of 'hg foutgoing' aoqi@0: # When now go down the tree and generate the change list aoqi@0: # aoqi@0: function treestatus aoqi@0: { aoqi@0: TREE=$1 aoqi@0: HGCMD="hg -R $CWS/$TREE status $FSTAT_OPT" aoqi@0: aoqi@0: $HGCMD -mdn 2>/dev/null | $FILTER | while read F aoqi@0: do aoqi@0: echo $TREE/$F aoqi@0: done >> $FLIST aoqi@0: aoqi@0: # Then all the added files aoqi@0: # But some of these could have been "moved" or renamed ones or copied ones aoqi@0: # so let's make sure we get the proper info aoqi@0: # hg status -aC will produce something like: aoqi@0: # A subdir/File3 aoqi@0: # A subdir/File4 aoqi@0: # File4 aoqi@0: # A subdir/File5 aoqi@0: # The first and last are simple addition while the middle one aoqi@0: # is a move/rename or a copy. We can't distinguish from a rename vs a copy aoqi@0: # without also getting the status of removed files. The middle case above aoqi@0: # is a rename if File4 is also shown a being removed. If File4 is not a aoqi@0: # removed file, then the middle case is a copy from File4 to subdir/File4 aoqi@0: # FIXME - we're not distinguishing copy from rename aoqi@0: $HGCMD -aC | $FILTER | while read LINE; do aoqi@0: ldone="" aoqi@0: while [ -z "$ldone" ]; do aoqi@0: ldone="1" aoqi@0: set - $LINE aoqi@0: if [ $# -eq 2 -a "$1" == "A" ]; then aoqi@0: AFILE=$2 aoqi@0: if read LINE2; then aoqi@0: set - $LINE2 aoqi@0: if [ $# -eq 1 ]; then aoqi@0: echo $TREE/$AFILE $TREE/$1 >>$FLIST aoqi@0: elif [ $# -eq 2 ]; then aoqi@0: echo $TREE/$AFILE >>$FLIST aoqi@0: LINE=$LINE2 aoqi@0: ldone="" aoqi@0: fi aoqi@0: else aoqi@0: echo $TREE/$AFILE >>$FLIST aoqi@0: fi aoqi@0: fi aoqi@0: done aoqi@0: done aoqi@0: $HGCMD -rn | $FILTER | while read RFILE; do aoqi@0: grep "$TREE/$RFILE" $FLIST >/dev/null aoqi@0: if [ $? -eq 1 ]; then aoqi@0: echo $TREE/$RFILE >>$FLIST aoqi@0: fi aoqi@0: done aoqi@0: } aoqi@0: aoqi@0: function fstatus aoqi@0: { aoqi@0: # aoqi@0: # forest extension is still being changed. For instance the output aoqi@0: # of fstatus used to no prepend the tree path to filenames, but aoqi@0: # this has changed recently. AWK code below does try to handle both aoqi@0: # cases aoqi@0: # aoqi@0: hg fstatus -mdn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' aoqi@0: /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} aoqi@0: $1 != "" {n=index($1,tree); aoqi@0: if (n == 0) aoqi@0: { printf("%s/%s\n",tree,$1)} aoqi@0: else aoqi@0: { printf("%s\n",$1)}}' >> $FLIST aoqi@0: aoqi@0: # aoqi@0: # There is a bug in the output of fstatus -aC on recent versions: it aoqi@0: # inserts a space between the name of the tree and the filename of the aoqi@0: # old file. e.g.: aoqi@0: # aoqi@0: # $ hg fstatus -aC aoqi@0: # [.] aoqi@0: # aoqi@0: # [MyWS] aoqi@0: # A MyWS/subdir/File2 aoqi@0: # MyWS/ File2 aoqi@0: # aoqi@0: # [MyWS2] aoqi@0: # aoqi@0: aoqi@0: hg fstatus -aC $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' aoqi@0: /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} aoqi@0: /^A .*/ {n=index($2,tree); aoqi@0: if (n == 0) aoqi@0: { printf("A %s/%s\n",tree,$2)} aoqi@0: else aoqi@0: { printf("A %s\n",$2)}; aoqi@0: next} aoqi@0: /^ / {n=index($1,tree); aoqi@0: if (n == 0) aoqi@0: { printf("%s/%s\n",tree,$1)} aoqi@0: else aoqi@0: { if (NF == 2) aoqi@0: printf("%s/%s\n",tree,$2) aoqi@0: else aoqi@0: printf("%s\n",$1) aoqi@0: }; aoqi@0: next} aoqi@0: ' | while read LINE; do aoqi@0: ldone="" aoqi@0: while [ -z "$ldone" ]; do aoqi@0: ldone="1" aoqi@0: set - $LINE aoqi@0: if [ $# -eq 2 -a "$1" == "A" ]; then aoqi@0: AFILE=$2 aoqi@0: if read LINE2; then aoqi@0: set - $LINE2 aoqi@0: if [ $# -eq 1 ]; then aoqi@0: echo $AFILE $1 >>$FLIST aoqi@0: elif [ $# -eq 2 ]; then aoqi@0: echo $AFILE >>$FLIST aoqi@0: LINE=$LINE2 aoqi@0: ldone="" aoqi@0: fi aoqi@0: else aoqi@0: echo $AFILE >>$FLIST aoqi@0: fi aoqi@0: fi aoqi@0: done aoqi@0: done aoqi@0: hg fstatus -rn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' aoqi@0: /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} aoqi@0: $1 != "" {n=index($1,tree); aoqi@0: if (n == 0) aoqi@0: { printf("%s/%s\n",tree,$1)} aoqi@0: else aoqi@0: { printf("%s\n",$1)}}' | while read RFILE; do aoqi@0: grep "$RFILE" $FLIST >/dev/null aoqi@0: if [ $? -eq 1 ]; then aoqi@0: echo $RFILE >>$FLIST aoqi@0: fi aoqi@0: done aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # flist_from_mercurial $PWS aoqi@0: # aoqi@0: # Only local file based repositories are supported at present aoqi@0: # since even though we can determine the list from the parent finding aoqi@0: # the changes is harder. aoqi@0: # aoqi@0: # We first look for any outgoing files, this is for when the user has aoqi@0: # run hg commit. If we don't find any then we look with hg status. aoqi@0: # aoqi@0: # We need at least one of default-push or default paths set in .hg/hgrc aoqi@0: # If neither are set we don't know who to compare with. aoqi@0: aoqi@0: function flist_from_mercurial aoqi@0: { aoqi@0: # if [ "${PWS##ssh://}" != "$PWS" -o \ aoqi@0: # "${PWS##http://}" != "$PWS" -o \ aoqi@0: # "${PWS##https://}" != "$PWS" ]; then aoqi@0: # print "Remote Mercurial repositories not currently supported." aoqi@0: # print "Set default and/or default-push to a local repository" aoqi@0: # exit aoqi@0: # fi aoqi@0: if [[ -n $forestflag ]]; then aoqi@0: HG_LIST_FROM_COMMIT= aoqi@0: flist_from_mercurial_forest aoqi@0: else aoqi@0: STATUS_REV= aoqi@0: if [[ -n $rflag ]]; then aoqi@0: STATUS_REV="--rev $PARENT_REV" aoqi@0: elif [[ -n $OUTREV ]]; then aoqi@0: STATUS_REV="--rev $OUTREV" aoqi@0: else aoqi@0: # hg commit hasn't been run see what is lying around aoqi@0: print "\n No outgoing, perhaps you haven't commited." aoqi@0: fi aoqi@0: # First let's list all the modified or deleted files aoqi@0: aoqi@0: hg status $STATUS_REV -mdn | $FILTER > $FLIST aoqi@0: aoqi@0: # Then all the added files aoqi@0: # But some of these could have been "moved" or renamed ones aoqi@0: # so let's make sure we get the proper info aoqi@0: # hg status -aC will produce something like: aoqi@0: # A subdir/File3 aoqi@0: # A subdir/File4 aoqi@0: # File4 aoqi@0: # A subdir/File5 aoqi@0: # The first and last are simple addition while the middle one aoqi@0: # is a move/rename or a copy. We can't distinguish from a rename vs a copy aoqi@0: # without also getting the status of removed files. The middle case above aoqi@0: # is a rename if File4 is also shown a being removed. If File4 is not a aoqi@0: # removed file, then the middle case is a copy from File4 to subdir/File4 aoqi@0: # FIXME - we're not distinguishing copy from rename aoqi@0: aoqi@0: hg status $STATUS_REV -aC | $FILTER >$FLIST.temp aoqi@0: while read LINE; do aoqi@0: ldone="" aoqi@0: while [ -z "$ldone" ]; do aoqi@0: ldone="1" aoqi@0: set - $LINE aoqi@0: if [ $# -eq 2 -a "$1" == "A" ]; then aoqi@0: AFILE=$2 aoqi@0: if read LINE2; then aoqi@0: set - $LINE2 aoqi@0: if [ $# -eq 1 ]; then aoqi@0: echo $AFILE $1 >>$FLIST aoqi@0: elif [ $# -eq 2 ]; then aoqi@0: echo $AFILE >>$FLIST aoqi@0: LINE=$LINE2 aoqi@0: ldone="" aoqi@0: fi aoqi@0: else aoqi@0: echo $AFILE >>$FLIST aoqi@0: fi aoqi@0: fi aoqi@0: done aoqi@0: done < $FLIST.temp aoqi@0: hg status $STATUS_REV -rn | $FILTER > $FLIST.temp aoqi@0: while read RFILE; do aoqi@0: grep "$RFILE" $FLIST >/dev/null aoqi@0: if [ $? -eq 1 ]; then aoqi@0: echo $RFILE >>$FLIST aoqi@0: fi aoqi@0: done < $FLIST.temp aoqi@0: rm -f $FLIST.temp aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: function env_from_flist aoqi@0: { aoqi@0: [[ -r $FLIST ]] || return aoqi@0: aoqi@0: # aoqi@0: # Use "eval" to set env variables that are listed in the file aoqi@0: # list. Then copy those into our local versions of those aoqi@0: # variables if they have not been set already. aoqi@0: # aoqi@0: eval `sed -e "s/#.*$//" $FLIST | grep = ` aoqi@0: aoqi@0: [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS aoqi@0: aoqi@0: # aoqi@0: # Check to see if CODEMGR_PARENT is set in the flist file. aoqi@0: # aoqi@0: [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \ aoqi@0: codemgr_parent=$CODEMGR_PARENT aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # detect_scm aoqi@0: # aoqi@0: # We dynamically test the SCM type; this allows future extensions to aoqi@0: # new SCM types aoqi@0: # aoqi@0: function detect_scm aoqi@0: { aoqi@0: if hg root >/dev/null ; then aoqi@0: print "mercurial" aoqi@0: else aoqi@0: print "unknown" aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: function look_for_prog aoqi@0: { aoqi@0: typeset path aoqi@0: typeset ppath aoqi@0: typeset progname=$1 aoqi@0: aoqi@0: DEVTOOLS= aoqi@0: OS=`uname` aoqi@0: if [[ "$OS" == "SunOS" ]]; then aoqi@0: DEVTOOLS="/java/devtools/`uname -p`/bin" aoqi@0: elif [[ "$OS" == "Linux" ]]; then aoqi@0: DEVTOOLS="/java/devtools/linux/bin" aoqi@0: fi aoqi@0: aoqi@0: ppath=$PATH aoqi@0: ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin aoqi@0: ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin aoqi@0: ppath=$ppath:/opt/onbld/bin/`uname -p` aoqi@0: ppath=$ppath:/java/devtools/share/bin:$DEVTOOLS aoqi@0: aoqi@0: PATH=$ppath prog=`whence $progname` aoqi@0: if [[ -n $prog ]]; then aoqi@0: print $prog aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # Find the parent for $1 aoqi@0: # aoqi@0: function find_outrev aoqi@0: { aoqi@0: crev=$1 aoqi@0: prev=`hg log -r $crev --template '{parents}\n'` aoqi@0: if [[ -z "$prev" ]] aoqi@0: then aoqi@0: # No specific parent means previous changeset is parent aoqi@0: prev=`expr $crev - 1` aoqi@0: else aoqi@0: # Format is either of the following two: aoqi@0: # 546:7df6fcf1183b aoqi@0: # 548:16f1915bb5cd 547:ffaa4e775815 aoqi@0: prev=`echo $prev | sed -e 's/\([0-9]*\):.*/\1/'` aoqi@0: fi aoqi@0: print $prev aoqi@0: } aoqi@0: aoqi@0: function extract_ssh_infos aoqi@0: { aoqi@0: CMD=$1 aoqi@0: if expr "$CMD" : 'ssh://[^/]*@' >/dev/null; then aoqi@0: ssh_user=`echo $CMD | sed -e 's/ssh:\/\/\(.*\)@.*/\1/'` aoqi@0: ssh_host=`echo $CMD | sed -e 's/ssh:\/\/.*@\([^/]*\)\/.*/\1/'` aoqi@0: ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/.*@[^/]*\/\(.*\)/\1/'` aoqi@0: else aoqi@0: ssh_user= aoqi@0: ssh_host=`echo $CMD | sed -e 's/ssh:\/\/\([^/]*\)\/.*/\1/'` aoqi@0: ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/[^/]*\/\(.*\)/\1/'` aoqi@0: fi aoqi@0: aoqi@0: } aoqi@0: aoqi@0: function build_old_new_mercurial aoqi@0: { aoqi@0: olddir=$1 aoqi@0: newdir=$2 aoqi@0: DIR=$3 aoqi@0: F=$4 aoqi@0: # aoqi@0: # new version of the file. aoqi@0: # aoqi@0: rm -rf $newdir/$DIR/$F aoqi@0: if [ -f $F ]; then aoqi@0: cp $F $newdir/$DIR/$F aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Old version of the file. aoqi@0: # aoqi@0: rm -rf $olddir/$DIR/$F aoqi@0: aoqi@0: if [ -n "$PWS" ]; then aoqi@0: if expr "$PWS" : 'ssh://' >/dev/null aoqi@0: then aoqi@0: extract_ssh_infos $PWS aoqi@0: if [ -n "$ssh_user" ]; then aoqi@0: parent="ssh -l $ssh_user $ssh_host hg -R $ssh_dir --cwd $ssh_dir" aoqi@0: else aoqi@0: parent="ssh $ssh_host hg -R $ssh_dir --cwd $ssh_dir" aoqi@0: fi aoqi@0: else aoqi@0: parent="hg -R $PWS --cwd $PWS" aoqi@0: fi aoqi@0: else aoqi@0: parent="" aoqi@0: fi aoqi@0: aoqi@0: if [ -z "$rename" ]; then aoqi@0: if [ -n "$rflag" ]; then aoqi@0: parentrev=$PARENT_REV aoqi@0: elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then aoqi@0: parentrev=$OUTREV aoqi@0: else aoqi@0: if [[ -n $HG_BRANCH ]]; then aoqi@0: parentrev=$HG_BRANCH aoqi@0: else aoqi@0: parentrev="tip" aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [ -n "$parentrev" ]; then aoqi@0: if [ -z "$parent" ]; then aoqi@0: hg cat --rev $parentrev --output $olddir/$DIR/$F $F 2>/dev/null aoqi@0: else aoqi@0: # when specifying a workspace we have to provide aoqi@0: # the full path aoqi@0: $parent cat --rev $parentrev --output $olddir/$DIR/$F $DIR/$F 2>/dev/null aoqi@0: fi aoqi@0: fi aoqi@0: else aoqi@0: # It's a rename (or a move), or a copy, so let's make sure we move aoqi@0: # to the right directory first, then restore it once done aoqi@0: current_dir=`pwd` aoqi@0: hg_root=`hg root` aoqi@0: cd $CWS aoqi@0: if [ -n "$rflag" ]; then aoqi@0: parentrev=$PARENT_REV aoqi@0: elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then aoqi@0: parentrev=$OUTREV aoqi@0: fi aoqi@0: if [ -z "$parentrev" ]; then aoqi@0: parentrev=`hg log -l1 $PDIR/$PF | $AWK -F: '/changeset/ {print $2}'` aoqi@0: fi aoqi@0: if [ -n "$parentrev" ]; then aoqi@0: mkdir -p $olddir/$PDIR aoqi@0: if [ -z "$parent" ]; then aoqi@0: hg cat -R $hg_root --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null aoqi@0: else aoqi@0: $parent cat --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null aoqi@0: fi aoqi@0: fi aoqi@0: cd $current_dir aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: function build_old_new aoqi@0: { aoqi@0: if [[ $SCM_MODE == "mercurial" ]]; then aoqi@0: build_old_new_mercurial $@ aoqi@0: fi aoqi@0: } aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # Usage message. aoqi@0: # aoqi@0: function usage aoqi@0: { aoqi@0: print "Usage:\twebrev [options] aoqi@0: webrev [options] ( | - ) aoqi@0: aoqi@0: Options: aoqi@0: -v: Print the version of this tool. aoqi@0: -b: Do not ignore changes in the amount of white space. aoqi@0: -c : Include link to CR (aka bugid) in the main page. aoqi@0: -i : Include in the index.html file. aoqi@0: -o : Output webrev to specified directory. aoqi@0: -p : Use specified parent wkspc or basis for comparison aoqi@0: -u : Use that username instead of 'guessing' one. aoqi@0: -m: Forces the use of Mercurial aoqi@0: aoqi@0: Mercurial only options: aoqi@0: -r rev: Compare against a specified revision aoqi@0: -N: Skip 'hg outgoing', use only 'hg status' aoqi@0: -f: Use the forest extension aoqi@0: aoqi@0: Arguments: aoqi@0: : Optional file containing list of files to include in webrev aoqi@0: -: read list of files to include in webrev from standard input aoqi@0: aoqi@0: Environment: aoqi@0: WDIR: Control the output directory. aoqi@0: WEBREV_BUGURL: Control the URL prefix for bugids. aoqi@0: aoqi@0: " aoqi@0: aoqi@0: exit 2 aoqi@0: } aoqi@0: aoqi@0: # aoqi@0: # aoqi@0: # Main program starts here aoqi@0: # aoqi@0: # aoqi@0: LANG="C" aoqi@0: LC_ALL="C" aoqi@0: export LANG LC_ALL aoqi@0: trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15 aoqi@0: aoqi@0: set +o noclobber aoqi@0: aoqi@0: [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff` aoqi@0: [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview` aoqi@0: [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf` aoqi@0: [[ -z $PERL ]] && PERL=`look_for_prog perl` aoqi@0: [[ -z $SCCS ]] && SCCS=`look_for_prog sccs` aoqi@0: [[ -z $AWK ]] && AWK=`look_for_prog nawk` aoqi@0: [[ -z $AWK ]] && AWK=`look_for_prog gawk` aoqi@0: [[ -z $AWK ]] && AWK=`look_for_prog awk` aoqi@0: [[ -z $JAR ]] && JAR=`look_for_prog jar` aoqi@0: [[ -z $ZIP ]] && ZIP=`look_for_prog zip` aoqi@0: [[ -z $GETENT ]] && GETENT=`look_for_prog getent` aoqi@0: [[ -z $WGET ]] && WGET=`look_for_prog wget` aoqi@0: aoqi@0: if uname | grep CYGWIN >/dev/null aoqi@0: then aoqi@0: ISWIN=1 aoqi@0: # Under windows mercurial outputs '\' instead of '/' aoqi@0: FILTER="tr '\\\\' '/'" aoqi@0: else aoqi@0: FILTER="cat" aoqi@0: fi aoqi@0: aoqi@0: if [[ ! -x $PERL ]]; then aoqi@0: print -u2 "Error: No perl interpreter found. Exiting." aoqi@0: exit 1 aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # These aren't fatal, but we want to note them to the user. aoqi@0: # aoqi@0: # [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found." aoqi@0: # [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found." aoqi@0: # [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found." aoqi@0: aoqi@0: # Declare global total counters. aoqi@0: integer TOTL TINS TDEL TMOD TUNC aoqi@0: aoqi@0: flist_mode= aoqi@0: flist_file= aoqi@0: bflag= aoqi@0: iflag= aoqi@0: oflag= aoqi@0: pflag= aoqi@0: uflag= aoqi@0: Oflag= aoqi@0: rflag= aoqi@0: Nflag= aoqi@0: forestflag= aoqi@0: while getopts "c:i:o:p:r:u:mONvfb" opt aoqi@0: do aoqi@0: case $opt in aoqi@0: b) bflag=1;; aoqi@0: aoqi@0: i) iflag=1 aoqi@0: INCLUDE_FILE=$OPTARG;; aoqi@0: aoqi@0: o) oflag=1 aoqi@0: WDIR=$OPTARG;; aoqi@0: aoqi@0: p) pflag=1 aoqi@0: codemgr_parent=$OPTARG;; aoqi@0: aoqi@0: u) uflag=1 aoqi@0: username=$OPTARG;; aoqi@0: aoqi@0: c) if [[ -z $CRID ]]; then aoqi@0: CRID=$OPTARG aoqi@0: else aoqi@0: CRID="$CRID $OPTARG" aoqi@0: fi;; aoqi@0: aoqi@0: m) SCM_MODE="mercurial";; aoqi@0: aoqi@0: O) Oflag=1;; # ignored (bugs are now all visible at bugs.openjdk.java.net) aoqi@0: aoqi@0: N) Nflag=1;; aoqi@0: aoqi@0: f) forestflag=1;; aoqi@0: aoqi@0: r) rflag=1 aoqi@0: PARENT_REV=$OPTARG;; aoqi@0: aoqi@0: v) print "$0 version: $WEBREV_UPDATED";; aoqi@0: aoqi@0: aoqi@0: ?) usage;; aoqi@0: esac aoqi@0: done aoqi@0: aoqi@0: FLIST=/tmp/$$.flist aoqi@0: HG_LIST_FROM_COMMIT= aoqi@0: aoqi@0: if [[ -n $forestflag && -n $rflag ]]; then aoqi@0: print "The -r flag is incompatible with the use of forests" aoqi@0: exit 2 aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # If this manually set as the parent, and it appears to be an earlier webrev, aoqi@0: # then note that fact and set the parent to the raw_files/new subdirectory. aoqi@0: # aoqi@0: if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then aoqi@0: parent_webrev="$codemgr_parent" aoqi@0: codemgr_parent="$codemgr_parent/raw_files/new" aoqi@0: fi aoqi@0: aoqi@0: shift $(($OPTIND - 1)) aoqi@0: aoqi@0: if [[ $1 == "-" ]]; then aoqi@0: cat > $FLIST aoqi@0: flist_mode="stdin" aoqi@0: flist_done=1 aoqi@0: shift aoqi@0: elif [[ -n $1 ]]; then aoqi@0: if [[ ! -r $1 ]]; then aoqi@0: print -u2 "$1: no such file or not readable" aoqi@0: usage aoqi@0: fi aoqi@0: cat $1 > $FLIST aoqi@0: flist_mode="file" aoqi@0: flist_file=$1 aoqi@0: flist_done=1 aoqi@0: shift aoqi@0: else aoqi@0: flist_mode="auto" aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Before we go on to further consider -l and -w, work out which SCM we think aoqi@0: # is in use. aoqi@0: # aoqi@0: if [[ -z $SCM_MODE ]]; then aoqi@0: SCM_MODE=`detect_scm $FLIST` aoqi@0: fi aoqi@0: if [[ $SCM_MODE == "unknown" ]]; then aoqi@0: print -u2 "Unable to determine SCM type currently in use." aoqi@0: print -u2 "For mercurial: webrev runs 'hg root'." aoqi@0: exit 1 aoqi@0: fi aoqi@0: aoqi@0: print -u2 " SCM detected: $SCM_MODE" aoqi@0: aoqi@0: aoqi@0: if [[ $SCM_MODE == "mercurial" ]]; then aoqi@0: # aoqi@0: # determine Workspace and parent workspace paths aoqi@0: # aoqi@0: CWS=`hg root | $FILTER` aoqi@0: if [[ -n $pflag && -z "$PWS" ]]; then aoqi@0: OUTPWS=$codemgr_parent aoqi@0: # Let's try to expand it if it's an alias defined in [paths] aoqi@0: tmp=`hg path $OUTPWS 2>/dev/null | $FILTER` aoqi@0: if [[ -n $tmp ]]; then aoqi@0: OUTPWS="$tmp" aoqi@0: fi aoqi@0: if [[ -n $rflag ]]; then aoqi@0: if expr "$codemgr_parent" : 'ssh://.*' >/dev/null; then aoqi@0: PWS=$codemgr_parent aoqi@0: else aoqi@0: PWS=`hg -R "$codemgr_parent" root 2>/dev/null | $FILTER` aoqi@0: fi aoqi@0: fi aoqi@0: fi aoqi@0: # aoqi@0: # OUTPWS is the parent repository to use when using 'hg outgoing' aoqi@0: # aoqi@0: if [[ -z $Nflag ]]; then aoqi@0: if [[ -n $forestflag ]]; then aoqi@0: # aoqi@0: # for forest we have to rely on properly set default and aoqi@0: # default-push because they can be different from the top one. aoqi@0: # unless of course it was explicitly specified with -p aoqi@0: if [[ -z $pflag ]]; then aoqi@0: OUTPWS= aoqi@0: fi aoqi@0: else aoqi@0: # aoqi@0: # Unfortunately mercurial is bugged and doesn't handle aoqi@0: # aliases correctly in 'hg path default' aoqi@0: # So let's do it ourselves. Sigh... aoqi@0: if [[ -z "$OUTPWS" ]]; then aoqi@0: OUTPWS=`grep default-push $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER` aoqi@0: fi aoqi@0: # Still empty, means no default-push aoqi@0: if [[ -z "$OUTPWS" ]]; then aoqi@0: OUTPWS=`grep 'default =' $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER` aoqi@0: fi aoqi@0: # Let's try to expand it if it's an alias defined in [paths] aoqi@0: tmp=`hg path $OUTPWS 2>/dev/null | $FILTER` aoqi@0: if [[ -n $tmp ]]; then aoqi@0: OUTPWS="$tmp" aoqi@0: fi aoqi@0: fi aoqi@0: fi aoqi@0: # aoqi@0: # OUTPWS may contain username:password, let's make sure we remove the aoqi@0: # sensitive information before we print out anything in the HTML aoqi@0: # aoqi@0: OUTPWS2=$OUTPWS aoqi@0: if [[ -n $OUTPWS ]]; then aoqi@0: if [[ `expr "$OUTPWS" : '.*://[^/]*@.*'` -gt 0 ]]; then aoqi@0: # Remove everything between '://' and '@' aoqi@0: OUTPWS2=`echo $OUTPWS | sed -e 's/\(.*:\/\/\).*@\(.*\)/\1\2/'` aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [[ -z $HG_BRANCH ]]; then aoqi@0: HG_BRANCH=`hg branch` aoqi@0: if [ "$HG_BRANCH" == "default" ]; then aoqi@0: # aoqi@0: # 'default' means no particular branch, so let's cancel that aoqi@0: # aoqi@0: HG_BRANCH= aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [[ -z $forestflag ]]; then aoqi@0: if [[ -z $Nflag ]]; then aoqi@0: # aoqi@0: # If no "-N", always do "hg outgoing" against parent aoqi@0: # repository to determine list of outgoing revisions. aoqi@0: # aoqi@0: ALL_CREV=`hg outgoing -q --template '{rev}\n' $OUTPWS | sort -n` aoqi@0: if [[ -n $ALL_CREV ]]; then aoqi@0: FIRST_CREV=`echo "$ALL_CREV" | head -1` aoqi@0: # aoqi@0: # If no "-r", choose revision to compare against by aoqi@0: # finding the latest revision not in the outgoing list. aoqi@0: # aoqi@0: if [[ -z $rflag ]]; then aoqi@0: OUTREV=`find_outrev "$FIRST_CREV"` aoqi@0: if [[ -n $OUTREV ]]; then aoqi@0: HG_LIST_FROM_COMMIT=1 aoqi@0: fi aoqi@0: fi aoqi@0: fi aoqi@0: elif [[ -n $rflag ]]; then aoqi@0: # aoqi@0: # If skipping "hg outgoing" but still comparing against a aoqi@0: # specific revision (not the tip), set revision for comment aoqi@0: # accumulation. aoqi@0: # aoqi@0: FIRST_CREV=`hg log --rev $PARENT_REV --template '{rev}'` aoqi@0: FIRST_CREV=`expr $FIRST_CREV + 1` aoqi@0: fi aoqi@0: fi aoqi@0: #Let's check if a merge is needed, if so, issue a warning aoqi@0: PREV=`hg parent | grep '^tag:.*tip$'` aoqi@0: if [[ -z $PREV ]]; then aoqi@0: print "WARNING: parent rev is not tip. Maybe an update or merge is needed" aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [[ $flist_mode == "stdin" ]]; then aoqi@0: print -u2 " File list from: standard input" aoqi@0: elif [[ $flist_mode == "file" ]]; then aoqi@0: print -u2 " File list from: $flist_file" aoqi@0: fi aoqi@0: aoqi@0: if [[ $# -gt 0 ]]; then aoqi@0: print -u2 "WARNING: unused arguments: $*" aoqi@0: fi aoqi@0: aoqi@0: if [[ $SCM_MODE == "mercurial" ]]; then aoqi@0: if [[ -z $flist_done ]]; then aoqi@0: flist_from_mercurial $PWS aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # If the user didn't specify a -i option, check to see if there is a aoqi@0: # webrev-info file in the workspace directory. aoqi@0: # aoqi@0: if [[ -z $iflag && -r "$CWS/webrev-info" ]]; then aoqi@0: iflag=1 aoqi@0: INCLUDE_FILE="$CWS/webrev-info" aoqi@0: fi aoqi@0: aoqi@0: if [[ -n $iflag ]]; then aoqi@0: if [[ ! -r $INCLUDE_FILE ]]; then aoqi@0: print -u2 "include file '$INCLUDE_FILE' does not exist or is" \ aoqi@0: "not readable." aoqi@0: exit 1 aoqi@0: else aoqi@0: # aoqi@0: # $INCLUDE_FILE may be a relative path, and the script alters aoqi@0: # PWD, so we just stash a copy in /tmp. aoqi@0: # aoqi@0: cp $INCLUDE_FILE /tmp/$$.include aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Output directory. aoqi@0: # aoqi@0: if [[ -z $WDIR ]]; then aoqi@0: WDIR=$CWS/webrev aoqi@0: else aoqi@0: # If the output directory doesn't end with '/webrev' or '/webrev/' aoqi@0: # then add '/webrev'. This is for backward compatibility aoqi@0: if ! expr $WDIR : '.*/webrev/\?$' >/dev/null aoqi@0: then aoqi@0: WDIR=$WDIR/webrev aoqi@0: fi aoqi@0: fi aoqi@0: # WDIR=${WDIR:-$CWS/webrev} aoqi@0: aoqi@0: # aoqi@0: # Name of the webrev, derived from the workspace name; in the aoqi@0: # future this could potentially be an option. aoqi@0: # aoqi@0: # Let's keep what's after the last '/' aoqi@0: WNAME=${CWS##*/} aoqi@0: aoqi@0: # aoqi@0: # If WDIR doesn't start with '/' or 'x:' prepend the current dir aoqi@0: # aoqi@0: if [ ${WDIR%%/*} ]; then aoqi@0: if [[ -n $ISWIN ]]; then aoqi@0: if [ ${WDIR%%[A-Za-z]:*} ]; then aoqi@0: WDIR=$PWD/$WDIR aoqi@0: fi aoqi@0: else aoqi@0: WDIR=$PWD/$WDIR aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [[ ! -d $WDIR ]]; then aoqi@0: mkdir -p $WDIR aoqi@0: [[ $? != 0 ]] && exit 1 aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Summarize what we're going to do. aoqi@0: # aoqi@0: print " Workspace: $CWS" aoqi@0: if [[ -n $parent_webrev ]]; then aoqi@0: print "Compare against: webrev at $parent_webrev" aoqi@0: elif [[ -n $OUTPWS2 ]]; then aoqi@0: print "Compare against: $OUTPWS2" aoqi@0: fi aoqi@0: if [[ -n $HG_BRANCH ]]; then aoqi@0: print " Branch: $HG_BRANCH" aoqi@0: fi aoqi@0: if [[ -n $rflag ]]; then aoqi@0: print "Compare against version: $PARENT_REV" aoqi@0: fi aoqi@0: [[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE" aoqi@0: print " Output to: $WDIR" aoqi@0: aoqi@0: # aoqi@0: # Save the file list in the webrev dir aoqi@0: # aoqi@0: [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list aoqi@0: aoqi@0: # aoqi@0: # Bug IDs will be replaced by a URL. Order of precedence aoqi@0: # is: default location, $WEBREV_BUGURL aoqi@0: # aoqi@0: BUGURL='https://bugs.openjdk.java.net/browse/' aoqi@0: [[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL" aoqi@0: IDPREFIX='JDK-' aoqi@0: aoqi@0: aoqi@0: rm -f $WDIR/$WNAME.patch aoqi@0: rm -f $WDIR/$WNAME.changeset aoqi@0: rm -f $WDIR/$WNAME.ps aoqi@0: rm -f $WDIR/$WNAME.pdf aoqi@0: aoqi@0: touch $WDIR/$WNAME.patch aoqi@0: aoqi@0: print " Output Files:" aoqi@0: aoqi@0: # aoqi@0: # Clean up the file list: Remove comments, blank lines and env variables. aoqi@0: # aoqi@0: sed -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean aoqi@0: FLIST=/tmp/$$.flist.clean aoqi@0: aoqi@0: # aoqi@0: # Clean up residual raw files aoqi@0: # aoqi@0: if [ -d $WDIR/raw_files ]; then aoqi@0: rm -rf $WDIR/raw_files 2>/dev/null aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Should we ignore changes in white spaces when generating diffs? aoqi@0: # aoqi@0: if [[ -n $bflag ]]; then aoqi@0: DIFFOPTS="-t" aoqi@0: else aoqi@0: DIFFOPTS="-bt" aoqi@0: fi aoqi@0: # aoqi@0: # First pass through the files: generate the per-file webrev HTML-files. aoqi@0: # aoqi@0: while read LINE aoqi@0: do aoqi@0: set - $LINE aoqi@0: P=$1 aoqi@0: aoqi@0: if [[ $1 == "Revision:" ]]; then aoqi@0: OUTREV=$2 aoqi@0: continue aoqi@0: fi aoqi@0: # aoqi@0: # Normally, each line in the file list is just a pathname of a aoqi@0: # file that has been modified or created in the child. A file aoqi@0: # that is renamed in the child workspace has two names on the aoqi@0: # line: new name followed by the old name. aoqi@0: # aoqi@0: oldname="" aoqi@0: oldpath="" aoqi@0: rename= aoqi@0: if [[ $# -eq 2 ]]; then aoqi@0: PP=$2 # old filename aoqi@0: oldname=" (was $PP)" aoqi@0: oldpath="$PP" aoqi@0: rename=1 aoqi@0: PDIR=${PP%/*} aoqi@0: if [[ $PDIR == $PP ]]; then aoqi@0: PDIR="." # File at root of workspace aoqi@0: fi aoqi@0: aoqi@0: PF=${PP##*/} aoqi@0: aoqi@0: DIR=${P%/*} aoqi@0: if [[ $DIR == $P ]]; then aoqi@0: DIR="." # File at root of workspace aoqi@0: fi aoqi@0: aoqi@0: F=${P##*/} aoqi@0: else aoqi@0: DIR=${P%/*} aoqi@0: if [[ "$DIR" == "$P" ]]; then aoqi@0: DIR="." # File at root of workspace aoqi@0: fi aoqi@0: aoqi@0: F=${P##*/} aoqi@0: aoqi@0: PP=$P aoqi@0: PDIR=$DIR aoqi@0: PF=$F aoqi@0: fi aoqi@0: aoqi@0: # Make the webrev directory if necessary as it may have been aoqi@0: # removed because it was empty aoqi@0: if [ ! -d $CWS/$DIR ]; then aoqi@0: mkdir -p $CWS/$DIR aoqi@0: fi aoqi@0: aoqi@0: COMM=`getcomments html $P $PP` aoqi@0: aoqi@0: print "\t$P$oldname\n\t\t\c" aoqi@0: aoqi@0: # Make the webrev mirror directory if necessary aoqi@0: mkdir -p $WDIR/$DIR aoqi@0: aoqi@0: # cd to the directory so the names are short aoqi@0: cd $CWS/$DIR aoqi@0: aoqi@0: # aoqi@0: # We stash old and new files into parallel directories in /tmp aoqi@0: # and do our diffs there. This makes it possible to generate aoqi@0: # clean looking diffs which don't have absolute paths present. aoqi@0: # aoqi@0: olddir=$WDIR/raw_files/old aoqi@0: newdir=$WDIR/raw_files/new aoqi@0: mkdir -p $olddir aoqi@0: mkdir -p $newdir aoqi@0: mkdir -p $olddir/$PDIR aoqi@0: mkdir -p $newdir/$DIR aoqi@0: aoqi@0: build_old_new $olddir $newdir $DIR $F aoqi@0: aoqi@0: if [[ ! -f $F && ! -f $olddir/$DIR/$F ]]; then aoqi@0: print "*** Error: file not in parent or child" aoqi@0: continue aoqi@0: fi aoqi@0: aoqi@0: cd $WDIR/raw_files aoqi@0: ofile=old/$PDIR/$PF aoqi@0: nfile=new/$DIR/$F aoqi@0: aoqi@0: mv_but_nodiff= aoqi@0: cmp $ofile $nfile > /dev/null 2>&1 aoqi@0: if [[ $? == 0 && $rename == 1 ]]; then aoqi@0: mv_but_nodiff=1 aoqi@0: fi aoqi@0: aoqi@0: # aoqi@0: # Cleaning up aoqi@0: # aoqi@0: rm -f $WDIR/$DIR/$F.cdiff.html aoqi@0: rm -f $WDIR/$DIR/$F.udiff.html aoqi@0: rm -f $WDIR/$DIR/$F.wdiff.html aoqi@0: rm -f $WDIR/$DIR/$F.sdiff.html aoqi@0: rm -f $WDIR/$DIR/$F-.html aoqi@0: rm -f $WDIR/$DIR/$F.html aoqi@0: aoqi@0: its_a_jar= aoqi@0: if expr $F : '.*\.jar' \| $F : '.*\.zip' >/dev/null; then aoqi@0: its_a_jar=1 aoqi@0: # It's a JAR or ZIP file, let's do it differently aoqi@0: if [[ -z $JAR ]]; then aoqi@0: print "No access to jar, so can't produce diffs for jar or zip files" aoqi@0: else aoqi@0: if [ -f $ofile ]; then aoqi@0: $JAR -tvf $ofile >"$ofile".lst aoqi@0: fi aoqi@0: if [ -f $nfile ]; then aoqi@0: $JAR -tvf $nfile >"$nfile".lst aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then aoqi@0: aoqi@0: ${CDIFFCMD:-diff -bt -C 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.cdiff aoqi@0: diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \ aoqi@0: > $WDIR/$DIR/$F.cdiff.html aoqi@0: print " cdiffs\c" aoqi@0: aoqi@0: ${UDIFFCMD:-diff -bt -U 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.udiff aoqi@0: diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \ aoqi@0: > $WDIR/$DIR/$F.udiff.html aoqi@0: aoqi@0: print " udiffs\c" aoqi@0: aoqi@0: if [[ -x $WDIFF ]]; then aoqi@0: $WDIFF -c "$COMM" \ aoqi@0: -t "$WNAME Wdiff $DIR/$F" $ofile.lst $nfile.lst > \ aoqi@0: $WDIR/$DIR/$F.wdiff.html 2>/dev/null aoqi@0: if [[ $? -eq 0 ]]; then aoqi@0: print " wdiffs\c" aoqi@0: else aoqi@0: print " wdiffs[fail]\c" aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: sdiff_to_html $ofile $nfile $F $DIR "$COMM" \ aoqi@0: > $WDIR/$DIR/$F.sdiff.html aoqi@0: print " sdiffs\c" aoqi@0: aoqi@0: print " frames\c" aoqi@0: aoqi@0: rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff aoqi@0: aoqi@0: difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count aoqi@0: aoqi@0: elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then aoqi@0: # renamed file: may also have differences aoqi@0: difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count aoqi@0: elif [[ -f $nfile ]]; then aoqi@0: # new file: count added lines aoqi@0: difflines /dev/null $nfile.lst > $WDIR/$DIR/$F.count aoqi@0: elif [[ -f $ofile ]]; then aoqi@0: # old file: count deleted lines aoqi@0: difflines $ofile.lst /dev/null > $WDIR/$DIR/$F.count aoqi@0: fi aoqi@0: fi aoqi@0: else aoqi@0: aoqi@0: # aoqi@0: # If we have old and new versions of the file then run the aoqi@0: # appropriate diffs. This is complicated by a couple of factors: aoqi@0: # aoqi@0: # - renames must be handled specially: we emit a 'remove' aoqi@0: # diff and an 'add' diff aoqi@0: # - new files and deleted files must be handled specially aoqi@0: # - Solaris patch(1m) can't cope with file creation aoqi@0: # (and hence renames) as of this writing. aoqi@0: # - To make matters worse, gnu patch doesn't interpret the aoqi@0: # output of Solaris diff properly when it comes to aoqi@0: # adds and deletes. We need to do some "cleansing" aoqi@0: # transformations: aoqi@0: # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@ aoqi@0: # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@ aoqi@0: # aoqi@0: cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'" aoqi@0: cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'" aoqi@0: aoqi@0: if [[ ! "$HG_LIST_FROM_COMMIT" -eq 1 || ! $flist_mode == "auto" ]]; aoqi@0: then aoqi@0: # Only need to generate a patch file here if there are no commits in outgoing aoqi@0: # or if we've specified a file list aoqi@0: rm -f $WDIR/$DIR/$F.patch aoqi@0: if [[ -z $rename ]]; then aoqi@0: if [ ! -f $ofile ]; then aoqi@0: diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ aoqi@0: > $WDIR/$DIR/$F.patch aoqi@0: elif [ ! -f $nfile ]; then aoqi@0: diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ aoqi@0: > $WDIR/$DIR/$F.patch aoqi@0: else aoqi@0: diff -u $ofile $nfile > $WDIR/$DIR/$F.patch aoqi@0: fi aoqi@0: else aoqi@0: diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ aoqi@0: > $WDIR/$DIR/$F.patch aoqi@0: aoqi@0: diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ aoqi@0: >> $WDIR/$DIR/$F.patch aoqi@0: aoqi@0: fi aoqi@0: aoqi@0: aoqi@0: # aoqi@0: # Tack the patch we just made onto the accumulated patch for the aoqi@0: # whole wad. aoqi@0: # aoqi@0: cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch aoqi@0: fi aoqi@0: aoqi@0: print " patch\c" aoqi@0: aoqi@0: if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then aoqi@0: aoqi@0: ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff aoqi@0: diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \ aoqi@0: > $WDIR/$DIR/$F.cdiff.html aoqi@0: print " cdiffs\c" aoqi@0: aoqi@0: ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff aoqi@0: diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \ aoqi@0: > $WDIR/$DIR/$F.udiff.html aoqi@0: aoqi@0: print " udiffs\c" aoqi@0: aoqi@0: if [[ -x $WDIFF ]]; then aoqi@0: $WDIFF -c "$COMM" \ aoqi@0: -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \ aoqi@0: $WDIR/$DIR/$F.wdiff.html 2>/dev/null aoqi@0: if [[ $? -eq 0 ]]; then aoqi@0: print " wdiffs\c" aoqi@0: else aoqi@0: print " wdiffs[fail]\c" aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: sdiff_to_html $ofile $nfile $F $DIR "$COMM" \ aoqi@0: > $WDIR/$DIR/$F.sdiff.html aoqi@0: print " sdiffs\c" aoqi@0: aoqi@0: print " frames\c" aoqi@0: aoqi@0: rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff aoqi@0: aoqi@0: difflines $ofile $nfile > $WDIR/$DIR/$F.count aoqi@0: aoqi@0: elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then aoqi@0: # renamed file: may also have differences aoqi@0: difflines $ofile $nfile > $WDIR/$DIR/$F.count aoqi@0: elif [[ -f $nfile ]]; then aoqi@0: # new file: count added lines aoqi@0: difflines /dev/null $nfile > $WDIR/$DIR/$F.count aoqi@0: elif [[ -f $ofile ]]; then aoqi@0: # old file: count deleted lines aoqi@0: difflines $ofile /dev/null > $WDIR/$DIR/$F.count aoqi@0: fi aoqi@0: fi aoqi@0: # aoqi@0: # Now we generate the postscript for this file. We generate diffs aoqi@0: # only in the event that there is delta, or the file is new (it seems aoqi@0: # tree-killing to print out the contents of deleted files). aoqi@0: # aoqi@0: if [[ -f $nfile ]]; then aoqi@0: ocr=$ofile aoqi@0: [[ ! -f $ofile ]] && ocr=/dev/null aoqi@0: aoqi@0: if [[ -z $mv_but_nodiff ]]; then aoqi@0: textcomm=`getcomments text $P $PP` aoqi@0: if [[ -x $CODEREVIEW ]]; then aoqi@0: $CODEREVIEW -y "$textcomm" \ aoqi@0: -e $ocr $nfile \ aoqi@0: > /tmp/$$.psfile 2>/dev/null && aoqi@0: cat /tmp/$$.psfile >> $WDIR/$WNAME.ps aoqi@0: if [[ $? -eq 0 ]]; then aoqi@0: print " ps\c" aoqi@0: else aoqi@0: print " ps[fail]\c" aoqi@0: fi aoqi@0: fi aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $ofile && -z $mv_but_nodiff ]]; then aoqi@0: if [[ -n $its_a_jar ]]; then aoqi@0: source_to_html Old $P < $ofile.lst > $WDIR/$DIR/$F-.html aoqi@0: else aoqi@0: source_to_html Old $P < $ofile > $WDIR/$DIR/$F-.html aoqi@0: fi aoqi@0: print " old\c" aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $nfile ]]; then aoqi@0: if [[ -n $its_a_jar ]]; then aoqi@0: source_to_html New $P < $nfile.lst > $WDIR/$DIR/$F.html aoqi@0: else aoqi@0: source_to_html New $P < $nfile > $WDIR/$DIR/$F.html aoqi@0: fi aoqi@0: print " new\c" aoqi@0: fi aoqi@0: aoqi@0: print aoqi@0: done < $FLIST aoqi@0: aoqi@0: # Create the new style mercurial patch here using hg export -r [all-revs] -g -o $CHANGESETPATH aoqi@0: if [[ $SCM_MODE == "mercurial" ]]; then aoqi@0: if [[ "$HG_LIST_FROM_COMMIT" -eq 1 && $flist_mode == "auto" ]]; then aoqi@0: EXPORTCHANGESET="$WNAME.changeset" aoqi@0: CHANGESETPATH=${WDIR}/${EXPORTCHANGESET} aoqi@0: rm -f $CHANGESETPATH aoqi@0: touch $CHANGESETPATH aoqi@0: if [[ -n $ALL_CREV ]]; then aoqi@0: rev_opt= aoqi@0: for rev in $ALL_CREV; do aoqi@0: rev_opt="$rev_opt --rev $rev" aoqi@0: done aoqi@0: elif [[ -n $FIRST_CREV ]]; then aoqi@0: rev_opt="--rev $FIRST_CREV" aoqi@0: fi aoqi@0: aoqi@0: if [[ -n $rev_opt ]]; then aoqi@0: (cd $CWS;hg export -g $rev_opt -o $CHANGESETPATH) aoqi@0: echo "Created changeset: $CHANGESETPATH" 1>&2 aoqi@0: # Use it in place of the jdk.patch created above aoqi@0: rm -f $WDIR/$WNAME.patch aoqi@0: fi aoqi@0: set +x aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: frame_nav_js > $WDIR/ancnav.js aoqi@0: frame_navigation > $WDIR/ancnav.html aoqi@0: aoqi@0: if [[ -f $WDIR/$WNAME.ps && -x $CODEREVIEW && -x $PS2PDF ]]; then aoqi@0: print " Generating PDF: \c" aoqi@0: fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf aoqi@0: print "Done." aoqi@0: fi aoqi@0: aoqi@0: # Now build the index.html file that contains aoqi@0: # links to the source files and their diffs. aoqi@0: aoqi@0: cd $CWS aoqi@0: aoqi@0: # Save total changed lines for Code Inspection. aoqi@0: print "$TOTL" > $WDIR/TotalChangedLines aoqi@0: aoqi@0: print " index.html: \c" aoqi@0: INDEXFILE=$WDIR/index.html aoqi@0: exec 3<&1 # duplicate stdout to FD3. aoqi@0: exec 1<&- # Close stdout. aoqi@0: exec > $INDEXFILE # Open stdout to index file. aoqi@0: aoqi@0: print "$HTML" aoqi@0: print "" aoqi@0: print "$STDHEAD" aoqi@0: print "$WNAME" aoqi@0: print "" aoqi@0: print "" aoqi@0: print "
" aoqi@0: print "

Code Review for $WNAME

" aoqi@0: aoqi@0: print "" aoqi@0: aoqi@0: if [[ -z $uflag ]]; then aoqi@0: if [[ $SCM_MODE == "mercurial" ]]; then aoqi@0: # aoqi@0: # Let's try to extract the user name from the .hgrc file aoqi@0: # aoqi@0: username=`grep '^username' $HOME/.hgrc | sed 's/^username[ ]*=[ ]*\(.*\)/\1/'` aoqi@0: fi aoqi@0: aoqi@0: if [[ -z $username ]]; then aoqi@0: # aoqi@0: # Figure out the username and gcos name. To maintain compatibility aoqi@0: # with passwd(4), we must support '&' substitutions. aoqi@0: # aoqi@0: username=`id | cut -d '(' -f 2 | cut -d ')' -f 1` aoqi@0: if [[ -x $GETENT ]]; then aoqi@0: realname=`$GETENT passwd $username | cut -d':' -f 5 | cut -d ',' -f 1` aoqi@0: fi aoqi@0: userupper=`print "$username" | sed 's/\<./\u&/g'` aoqi@0: realname=`print $realname | sed s/\&/$userupper/` aoqi@0: fi aoqi@0: fi aoqi@0: aoqi@0: date="on `date`" aoqi@0: aoqi@0: if [[ -n "$username" && -n "$realname" ]]; then aoqi@0: print "" aoqi@0: print "" aoqi@0: elif [[ -n "$username" ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: aoqi@0: print "" aoqi@0: if [[ -n $parent_webrev ]]; then aoqi@0: print "" aoqi@0: if [[ -n $rflag ]]; then aoqi@0: print "" aoqi@0: elif [[ -n $OUTREV ]]; then aoqi@0: if [[ -z $forestflag ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: fi aoqi@0: if [[ -n $HG_BRANCH ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: aoqi@0: print "" aoqi@0: aoqi@0: if [[ -f $WDIR/$WNAME.patch ]]; then aoqi@0: print "" aoqi@0: elif [[ -f $CHANGESETPATH ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $WDIR/$WNAME.pdf ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: aoqi@0: if [[ -n "$iflag" ]]; then aoqi@0: print "" aoqi@0: fi aoqi@0: # Add links to referenced CRs, if any aoqi@0: # URL has a like: aoqi@0: # <title>[#JDK-8024688] b106-lambda: j.u.Map.merge doesn't work as specified if contains key:null pair - Java Bug System aoqi@0: # we format this to: aoqi@0: # JDK-8024688: b106-lambda: j.u.Map.merge doesn't work as specified if contains key:null pair aoqi@0: if [[ -n $CRID ]]; then aoqi@0: for id in $CRID aoqi@0: do aoqi@0: #add "JDK-" to raw bug id for openjdk.java.net links. aoqi@0: id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'` aoqi@0: aoqi@0: print "
Prepared by:$realname ($username) $date
Prepared by:$username $date
Workspace:$CWS
Compare against:" aoqi@0: print "webrev at $parent_webrev" aoqi@0: else aoqi@0: if [[ -n $OUTPWS2 ]]; then aoqi@0: print "
Compare against:" aoqi@0: print "$OUTPWS2" aoqi@0: fi aoqi@0: fi aoqi@0: print "
Compare against version:$PARENT_REV
Compare against version:$OUTREV
Branch:$HG_BRANCH
Summary of changes:" aoqi@0: printCI $TOTL $TINS $TDEL $TMOD $TUNC aoqi@0: print "
Patch of changes:" aoqi@0: print "$WNAME.patch
Changeset:" aoqi@0: print "$EXPORTCHANGESET
Printable review:" aoqi@0: print "$WNAME.pdf
Author comments:
" aoqi@0: cat /tmp/$$.include aoqi@0: print "
Bug id:" aoqi@0: url="${BUGURL}${id}" aoqi@0: aoqi@0: if [[ -n $WGET ]]; then aoqi@0: msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '' | sed 's/<title>\[#\(.*\)\] \(.*\) - Java Bug System<\/title>/\1 : \2/' | html_dequote | html_quote` aoqi@0: fi aoqi@0: if [[ -z $msg ]]; then aoqi@0: msg="${id}" aoqi@0: fi aoqi@0: aoqi@0: print "<a href=\"$url\">$msg</a>" aoqi@0: aoqi@0: print "</td></tr>" aoqi@0: done aoqi@0: fi aoqi@0: print "<tr><th>Legend:</th><td>" aoqi@0: print "<b>Modified file</b><br><font color=red><b>Deleted file</b></font><br><font color=green><b>New file</b></font></td></tr>" aoqi@0: print "</table>" aoqi@0: print "</div>" aoqi@0: aoqi@0: # aoqi@0: # Second pass through the files: generate the rest of the index file aoqi@0: # aoqi@0: while read LINE aoqi@0: do aoqi@0: set - $LINE aoqi@0: if [[ $1 == "Revision:" ]]; then aoqi@0: FIRST_CREV=`expr $3 + 1` aoqi@0: continue aoqi@0: fi aoqi@0: P=$1 aoqi@0: aoqi@0: if [[ $# == 2 ]]; then aoqi@0: PP=$2 aoqi@0: oldname=" <i>(was $PP)</i>" aoqi@0: aoqi@0: else aoqi@0: PP=$P aoqi@0: oldname="" aoqi@0: fi aoqi@0: aoqi@0: DIR=${P%/*} aoqi@0: if [[ $DIR == $P ]]; then aoqi@0: DIR="." # File at root of workspace aoqi@0: fi aoqi@0: aoqi@0: # Avoid processing the same file twice. aoqi@0: # It's possible for renamed files to aoqi@0: # appear twice in the file list aoqi@0: aoqi@0: F=$WDIR/$P aoqi@0: aoqi@0: print "<p><code>" aoqi@0: aoqi@0: # If there's a diffs file, make diffs links aoqi@0: aoqi@0: NODIFFS= aoqi@0: if [[ -f $F.cdiff.html ]]; then aoqi@0: print "<a href=\"$P.cdiff.html\">Cdiffs</a>" aoqi@0: print "<a href=\"$P.udiff.html\">Udiffs</a>" aoqi@0: aoqi@0: if [[ -f $F.wdiff.html && -x $WDIFF ]]; then aoqi@0: print "<a href=\"$P.wdiff.html\">Wdiffs</a>" aoqi@0: fi aoqi@0: aoqi@0: print "<a href=\"$P.sdiff.html\">Sdiffs</a>" aoqi@0: aoqi@0: print "<a href=\"$P.frames.html\">Frames</a>" aoqi@0: else aoqi@0: NODIFFS=1 aoqi@0: print " ------ ------ ------" aoqi@0: aoqi@0: if [[ -x $WDIFF ]]; then aoqi@0: print " ------" aoqi@0: fi aoqi@0: aoqi@0: print " ------" aoqi@0: fi aoqi@0: aoqi@0: # If there's an old file, make the link aoqi@0: aoqi@0: NOOLD= aoqi@0: if [[ -f $F-.html ]]; then aoqi@0: print "<a href=\"$P-.html\">Old</a>" aoqi@0: else aoqi@0: NOOLD=1 aoqi@0: print " ---" aoqi@0: fi aoqi@0: aoqi@0: # If there's an new file, make the link aoqi@0: aoqi@0: NONEW= aoqi@0: if [[ -f $F.html ]]; then aoqi@0: print "<a href=\"$P.html\">New</a>" aoqi@0: else aoqi@0: NONEW=1 aoqi@0: print " ---" aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $F.patch ]]; then aoqi@0: print "<a href=\"$P.patch\">Patch</a>" aoqi@0: else aoqi@0: print " -----" aoqi@0: fi aoqi@0: aoqi@0: if [[ -f $WDIR/raw_files/new/$P ]]; then aoqi@0: print "<a href=\"raw_files/new/$P\">Raw</a>" aoqi@0: else aoqi@0: print " ---" aoqi@0: fi aoqi@0: print "</code>" aoqi@0: if [[ -n $NODIFFS && -z $oldname ]]; then aoqi@0: if [[ -n $NOOLD ]]; then aoqi@0: print "<font color=green><b>$P</b></font>" aoqi@0: elif [[ -n $NONEW ]]; then aoqi@0: print "<font color=red><b>$P</b></font>" aoqi@0: fi aoqi@0: else aoqi@0: print "<b>$P</b> $oldname" aoqi@0: fi aoqi@0: aoqi@0: print "</p><blockquote>\c" aoqi@0: # Insert delta comments if any aoqi@0: comments=`getcomments html $P $PP` aoqi@0: if [ -n "$comments" ]; then aoqi@0: print "<pre>$comments</pre>" aoqi@0: fi aoqi@0: aoqi@0: # Add additional comments comment aoqi@0: aoqi@0: print "<!-- Add comments to explain changes in $P here -->" aoqi@0: aoqi@0: # Add count of changes. aoqi@0: aoqi@0: if [[ -f $F.count ]]; then aoqi@0: cat $F.count aoqi@0: rm $F.count aoqi@0: fi aoqi@0: print "</blockquote>" aoqi@0: done < $FLIST aoqi@0: aoqi@0: print aoqi@0: print aoqi@0: print "<hr />" aoqi@0: print "<p style=\"font-size: small\">" aoqi@0: print "This code review page was prepared using <b>$0</b>" aoqi@0: print "(vers $WEBREV_UPDATED)." aoqi@0: print "</body>" aoqi@0: print "</html>" aoqi@0: aoqi@0: if [[ -n $ZIP ]]; then aoqi@0: # Let's generate a zip file for convenience aoqi@0: cd $WDIR/.. aoqi@0: if [ -f webrev.zip ]; then aoqi@0: rm webrev.zip aoqi@0: fi aoqi@0: $ZIP -r webrev webrev >/dev/null 2>&1 aoqi@0: fi aoqi@0: aoqi@0: exec 1<&- # Close FD 1. aoqi@0: exec 1<&3 # dup FD 3 to restore stdout. aoqi@0: exec 3<&- # close FD 3. aoqi@0: aoqi@0: print "Done." aoqi@0: print "Output to: $WDIR"