1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/make/scripts/webrev.ksh Wed Apr 27 01:39:08 2016 +0800 1.3 @@ -0,0 +1,2783 @@ 1.4 +#!/bin/ksh -p 1.5 +# 1.6 +# CDDL HEADER START 1.7 +# 1.8 +# The contents of this file are subject to the terms of the 1.9 +# Common Development and Distribution License (the "License"). 1.10 +# You may not use this file except in compliance with the License. 1.11 +# 1.12 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 1.13 +# or http://www.opensolaris.org/os/licensing. 1.14 +# See the License for the specific language governing permissions 1.15 +# and limitations under the License. 1.16 +# 1.17 +# When distributing Covered Code, include this CDDL HEADER in each 1.18 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1.19 +# If applicable, add the following below this CDDL HEADER, with the 1.20 +# fields enclosed by brackets "[]" replaced with your own identifying 1.21 +# information: Portions Copyright [yyyy] [name of copyright owner] 1.22 +# 1.23 +# CDDL HEADER END 1.24 +# 1.25 +# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 1.26 +# Use is subject to license terms. 1.27 +# 1.28 +# This script takes a file list and a workspace and builds a set of html files 1.29 +# suitable for doing a code review of source changes via a web page. 1.30 +# Documentation is available via 'webrev -h'. 1.31 +# 1.32 + 1.33 +WEBREV_UPDATED=25.1-hg+openjdk.java.net 1.34 + 1.35 +HTML='<?xml version="1.0"?> 1.36 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 1.37 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 1.38 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' 1.39 + 1.40 +FRAMEHTML='<?xml version="1.0"?> 1.41 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 1.42 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> 1.43 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' 1.44 + 1.45 +STDHEAD='<meta charset="utf-8"> 1.46 +<meta http-equiv="cache-control" content="no-cache" /> 1.47 +<meta http-equiv="Pragma" content="no-cache" /> 1.48 +<meta http-equiv="Expires" content="-1" /> 1.49 +<!-- 1.50 + Note to customizers: the body of the webrev is IDed as SUNWwebrev 1.51 + to allow easy overriding by users of webrev via the userContent.css 1.52 + mechanism available in some browsers. 1.53 + 1.54 + For example, to have all "removed" information be red instead of 1.55 + brown, set a rule in your userContent.css file like: 1.56 + 1.57 + body#SUNWwebrev span.removed { color: red ! important; } 1.58 +--> 1.59 +<style type="text/css" media="screen"> 1.60 +body { 1.61 + background-color: #eeeeee; 1.62 +} 1.63 +hr { 1.64 + border: none 0; 1.65 + border-top: 1px solid #aaa; 1.66 + height: 1px; 1.67 +} 1.68 +div.summary { 1.69 + font-size: .8em; 1.70 + border-bottom: 1px solid #aaa; 1.71 + padding-left: 1em; 1.72 + padding-right: 1em; 1.73 +} 1.74 +div.summary h2 { 1.75 + margin-bottom: 0.3em; 1.76 +} 1.77 +div.summary table th { 1.78 + text-align: right; 1.79 + vertical-align: top; 1.80 + white-space: nowrap; 1.81 +} 1.82 +span.lineschanged { 1.83 + font-size: 0.7em; 1.84 +} 1.85 +span.oldmarker { 1.86 + color: red; 1.87 + font-size: large; 1.88 + font-weight: bold; 1.89 +} 1.90 +span.newmarker { 1.91 + color: green; 1.92 + font-size: large; 1.93 + font-weight: bold; 1.94 +} 1.95 +span.removed { 1.96 + color: brown; 1.97 +} 1.98 +span.changed { 1.99 + color: blue; 1.100 +} 1.101 +span.new { 1.102 + color: blue; 1.103 + font-weight: bold; 1.104 +} 1.105 +a.print { font-size: x-small; } 1.106 + 1.107 +</style> 1.108 + 1.109 +<style type="text/css" media="print"> 1.110 +pre { font-size: 0.8em; font-family: courier, monospace; } 1.111 +span.removed { color: #444; font-style: italic } 1.112 +span.changed { font-weight: bold; } 1.113 +span.new { font-weight: bold; } 1.114 +span.newmarker { font-size: 1.2em; font-weight: bold; } 1.115 +span.oldmarker { font-size: 1.2em; font-weight: bold; } 1.116 +a.print {display: none} 1.117 +hr { border: none 0; border-top: 1px solid #aaa; height: 1px; } 1.118 +</style> 1.119 +' 1.120 + 1.121 +# 1.122 +# UDiffs need a slightly different CSS rule for 'new' items (we don't 1.123 +# want them to be bolded as we do in cdiffs or sdiffs). 1.124 +# 1.125 +UDIFFCSS=' 1.126 +<style type="text/css" media="screen"> 1.127 +span.new { 1.128 + color: blue; 1.129 + font-weight: normal; 1.130 +} 1.131 +</style> 1.132 +' 1.133 + 1.134 +# 1.135 +# input_cmd | html_quote | output_cmd 1.136 +# or 1.137 +# html_quote filename | output_cmd 1.138 +# 1.139 +# Make a piece of source code safe for display in an HTML <pre> block. 1.140 +# 1.141 +html_quote() 1.142 +{ 1.143 + sed -e "s/&/\&/g" -e "s/&#\([x]*[0-9A-Fa-f]\{2,5\}\);/\&#\1;/g" -e "s/</\</g" -e "s/>/\>/g" "$@" | expand 1.144 +} 1.145 + 1.146 +# 1.147 +# input_cmd | html_quote | output_cmd 1.148 +# or 1.149 +# html_dequote filename | output_cmd 1.150 +# 1.151 +# Replace HTML entities with literals 1.152 +# 1.153 +html_dequote() 1.154 +{ 1.155 + sed -e "s/"/\"/g" -e "s/'/\'/g" -e "s/&/\&/g" -e "s/</<'/g" -e "s/>/>/g" "$@" | expand 1.156 +} 1.157 + 1.158 +# 1.159 +# input_cmd | bug2url | output_cmd 1.160 +# 1.161 +# Scan for bugids and insert <a> links to the relevent bug database. 1.162 +# 1.163 +bug2url() 1.164 +{ 1.165 + sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL$IDPREFIX'&\">&</a>|g' 1.166 +} 1.167 + 1.168 +# 1.169 +# strip_unchanged <infile> | output_cmd 1.170 +# 1.171 +# Removes chunks of sdiff documents that have not changed. This makes it 1.172 +# easier for a code reviewer to find the bits that have changed. 1.173 +# 1.174 +# Deleted lines of text are replaced by a horizontal rule. Some 1.175 +# identical lines are retained before and after the changed lines to 1.176 +# provide some context. The number of these lines is controlled by the 1.177 +# variable C in the $AWK script below. 1.178 +# 1.179 +# The script detects changed lines as any line that has a "<span class=" 1.180 +# string embedded (unchanged lines have no particular class and are not 1.181 +# part of a <span>). Blank lines (without a sequence number) are also 1.182 +# detected since they flag lines that have been inserted or deleted. 1.183 +# 1.184 +strip_unchanged() 1.185 +{ 1.186 + $AWK ' 1.187 + BEGIN { C = c = 20 } 1.188 + NF == 0 || /span class=/ { 1.189 + if (c > C) { 1.190 + c -= C 1.191 + inx = 0 1.192 + if (c > C) { 1.193 + print "\n</pre><hr></hr><pre>" 1.194 + inx = c % C 1.195 + c = C 1.196 + } 1.197 + 1.198 + for (i = 0; i < c; i++) 1.199 + print ln[(inx + i) % C] 1.200 + } 1.201 + c = 0; 1.202 + print 1.203 + next 1.204 + } 1.205 + { if (c >= C) { 1.206 + ln[c % C] = $0 1.207 + c++; 1.208 + next; 1.209 + } 1.210 + c++; 1.211 + print 1.212 + } 1.213 + END { if (c > (C * 2)) print "\n</pre><hr></hr>" } 1.214 + 1.215 + ' $1 1.216 +} 1.217 + 1.218 +# 1.219 +# sdiff_to_html 1.220 +# 1.221 +# This function takes two files as arguments, obtains their diff, and 1.222 +# processes the diff output to present the files as an HTML document with 1.223 +# the files displayed side-by-side, differences shown in color. It also 1.224 +# takes a delta comment, rendered as an HTML snippet, as the third 1.225 +# argument. The function takes two files as arguments, then the name of 1.226 +# file, the path, and the comment. The HTML will be delivered on stdout, 1.227 +# e.g. 1.228 +# 1.229 +# $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \ 1.230 +# new/usr/src/tools/scripts/webrev.sh \ 1.231 +# webrev.sh usr/src/tools/scripts \ 1.232 +# '<a href="https://bugs.openjdk.java.net/browse/JDK-1234567"> 1.233 +# JDK-1234567</a> my bugid' > <file>.html 1.234 +# 1.235 +# framed_sdiff() is then called which creates $2.frames.html 1.236 +# in the webrev tree. 1.237 +# 1.238 +# FYI: This function is rather unusual in its use of awk. The initial 1.239 +# diff run produces conventional diff output showing changed lines mixed 1.240 +# with editing codes. The changed lines are ignored - we're interested in 1.241 +# the editing codes, e.g. 1.242 +# 1.243 +# 8c8 1.244 +# 57a61 1.245 +# 63c66,76 1.246 +# 68,93d80 1.247 +# 106d90 1.248 +# 108,110d91 1.249 +# 1.250 +# These editing codes are parsed by the awk script and used to generate 1.251 +# another awk script that generates HTML, e.g the above lines would turn 1.252 +# into something like this: 1.253 +# 1.254 +# BEGIN { printf "<pre>\n" } 1.255 +# function sp(n) {for (i=0;i<n;i++)printf "\n"} 1.256 +# function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0} 1.257 +# NR==8 {wl("#7A7ADD");next} 1.258 +# NR==54 {wl("#7A7ADD");sp(3);next} 1.259 +# NR==56 {wl("#7A7ADD");next} 1.260 +# NR==57 {wl("black");printf "\n"; next} 1.261 +# : : 1.262 +# 1.263 +# This script is then run on the original source file to generate the 1.264 +# HTML that corresponds to the source file. 1.265 +# 1.266 +# The two HTML files are then combined into a single piece of HTML that 1.267 +# uses an HTML table construct to present the files side by side. You'll 1.268 +# notice that the changes are color-coded: 1.269 +# 1.270 +# black - unchanged lines 1.271 +# blue - changed lines 1.272 +# bold blue - new lines 1.273 +# brown - deleted lines 1.274 +# 1.275 +# Blank lines are inserted in each file to keep unchanged lines in sync 1.276 +# (side-by-side). This format is familiar to users of sdiff(1) or 1.277 +# Teamware's filemerge tool. 1.278 +# 1.279 +sdiff_to_html() 1.280 +{ 1.281 + diff -b $1 $2 > /tmp/$$.diffs 1.282 + 1.283 + TNAME=$3 1.284 + TPATH=$4 1.285 + COMMENT=$5 1.286 + 1.287 + # 1.288 + # Now we have the diffs, generate the HTML for the old file. 1.289 + # 1.290 + $AWK ' 1.291 + BEGIN { 1.292 + printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n" 1.293 + printf "function removed() " 1.294 + printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 1.295 + printf "function changed() " 1.296 + printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 1.297 + printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n" 1.298 +} 1.299 + /^</ {next} 1.300 + /^>/ {next} 1.301 + /^---/ {next} 1.302 + 1.303 + { 1.304 + split($1, a, /[cad]/) ; 1.305 + if (index($1, "a")) { 1.306 + if (a[1] == 0) { 1.307 + n = split(a[2], r, /,/); 1.308 + if (n == 1) 1.309 + printf "BEGIN\t\t{sp(1)}\n" 1.310 + else 1.311 + printf "BEGIN\t\t{sp(%d)}\n",\ 1.312 + (r[2] - r[1]) + 1 1.313 + next 1.314 + } 1.315 + 1.316 + printf "NR==%s\t\t{", a[1] 1.317 + n = split(a[2], r, /,/); 1.318 + s = r[1]; 1.319 + if (n == 1) 1.320 + printf "bl();printf \"\\n\"; next}\n" 1.321 + else { 1.322 + n = r[2] - r[1] 1.323 + printf "bl();sp(%d);next}\n",\ 1.324 + (r[2] - r[1]) + 1 1.325 + } 1.326 + next 1.327 + } 1.328 + if (index($1, "d")) { 1.329 + n = split(a[1], r, /,/); 1.330 + n1 = r[1] 1.331 + n2 = r[2] 1.332 + if (n == 1) 1.333 + printf "NR==%s\t\t{removed(); next}\n" , n1 1.334 + else 1.335 + printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2 1.336 + next 1.337 + } 1.338 + if (index($1, "c")) { 1.339 + n = split(a[1], r, /,/); 1.340 + n1 = r[1] 1.341 + n2 = r[2] 1.342 + final = n2 1.343 + d1 = 0 1.344 + if (n == 1) 1.345 + printf "NR==%s\t\t{changed();" , n1 1.346 + else { 1.347 + d1 = n2 - n1 1.348 + printf "NR==%s,NR==%s\t{changed();" , n1, n2 1.349 + } 1.350 + m = split(a[2], r, /,/); 1.351 + n1 = r[1] 1.352 + n2 = r[2] 1.353 + if (m > 1) { 1.354 + d2 = n2 - n1 1.355 + if (d2 > d1) { 1.356 + if (n > 1) printf "if (NR==%d)", final 1.357 + printf "sp(%d);", d2 - d1 1.358 + } 1.359 + } 1.360 + printf "next}\n" ; 1.361 + 1.362 + next 1.363 + } 1.364 + } 1.365 + 1.366 + END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" } 1.367 + ' /tmp/$$.diffs > /tmp/$$.file1 1.368 + 1.369 + # 1.370 + # Now generate the HTML for the new file 1.371 + # 1.372 + $AWK ' 1.373 + BEGIN { 1.374 + printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n" 1.375 + printf "function new() " 1.376 + printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n" 1.377 + printf "function changed() " 1.378 + printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 1.379 + printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n" 1.380 + } 1.381 + 1.382 + /^</ {next} 1.383 + /^>/ {next} 1.384 + /^---/ {next} 1.385 + 1.386 + { 1.387 + split($1, a, /[cad]/) ; 1.388 + if (index($1, "d")) { 1.389 + if (a[2] == 0) { 1.390 + n = split(a[1], r, /,/); 1.391 + if (n == 1) 1.392 + printf "BEGIN\t\t{sp(1)}\n" 1.393 + else 1.394 + printf "BEGIN\t\t{sp(%d)}\n",\ 1.395 + (r[2] - r[1]) + 1 1.396 + next 1.397 + } 1.398 + 1.399 + printf "NR==%s\t\t{", a[2] 1.400 + n = split(a[1], r, /,/); 1.401 + s = r[1]; 1.402 + if (n == 1) 1.403 + printf "bl();printf \"\\n\"; next}\n" 1.404 + else { 1.405 + n = r[2] - r[1] 1.406 + printf "bl();sp(%d);next}\n",\ 1.407 + (r[2] - r[1]) + 1 1.408 + } 1.409 + next 1.410 + } 1.411 + if (index($1, "a")) { 1.412 + n = split(a[2], r, /,/); 1.413 + n1 = r[1] 1.414 + n2 = r[2] 1.415 + if (n == 1) 1.416 + printf "NR==%s\t\t{new() ; next}\n" , n1 1.417 + else 1.418 + printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2 1.419 + next 1.420 + } 1.421 + if (index($1, "c")) { 1.422 + n = split(a[2], r, /,/); 1.423 + n1 = r[1] 1.424 + n2 = r[2] 1.425 + final = n2 1.426 + d2 = 0; 1.427 + if (n == 1) { 1.428 + final = n1 1.429 + printf "NR==%s\t\t{changed();" , n1 1.430 + } else { 1.431 + d2 = n2 - n1 1.432 + printf "NR==%s,NR==%s\t{changed();" , n1, n2 1.433 + } 1.434 + m = split(a[1], r, /,/); 1.435 + n1 = r[1] 1.436 + n2 = r[2] 1.437 + if (m > 1) { 1.438 + d1 = n2 - n1 1.439 + if (d1 > d2) { 1.440 + if (n > 1) printf "if (NR==%d)", final 1.441 + printf "sp(%d);", d1 - d2 1.442 + } 1.443 + } 1.444 + printf "next}\n" ; 1.445 + next 1.446 + } 1.447 + } 1.448 + END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" } 1.449 + ' /tmp/$$.diffs > /tmp/$$.file2 1.450 + 1.451 + # 1.452 + # Post-process the HTML files by running them back through $AWK 1.453 + # 1.454 + html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html 1.455 + 1.456 + html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html 1.457 + 1.458 + # 1.459 + # Now combine into a valid HTML file and side-by-side into a table 1.460 + # 1.461 + print "$HTML<head>$STDHEAD" 1.462 + print "<title>$WNAME Sdiff $TPATH </title>" 1.463 + print "</head><body id=\"SUNWwebrev\">" 1.464 + print "<h2>$TPATH/$TNAME</h2>" 1.465 + print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>" 1.466 + print "<pre>$COMMENT</pre>\n" 1.467 + print "<table><tr valign=\"top\">" 1.468 + print "<td><pre>" 1.469 + 1.470 + strip_unchanged /tmp/$$.file1.html 1.471 + 1.472 + print "</pre></td><td><pre>" 1.473 + 1.474 + strip_unchanged /tmp/$$.file2.html 1.475 + 1.476 + print "</pre></td>" 1.477 + print "</tr></table>" 1.478 + print "</body></html>" 1.479 + 1.480 + framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \ 1.481 + "$COMMENT" 1.482 +} 1.483 + 1.484 + 1.485 +# 1.486 +# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment> 1.487 +# 1.488 +# Expects lefthand and righthand side html files created by sdiff_to_html. 1.489 +# We use insert_anchors() to augment those with HTML navigation anchors, 1.490 +# and then emit the main frame. Content is placed into: 1.491 +# 1.492 +# $WDIR/DIR/$TNAME.lhs.html 1.493 +# $WDIR/DIR/$TNAME.rhs.html 1.494 +# $WDIR/DIR/$TNAME.frames.html 1.495 +# 1.496 +# NOTE: We rely on standard usage of $WDIR and $DIR. 1.497 +# 1.498 +function framed_sdiff 1.499 +{ 1.500 + typeset TNAME=$1 1.501 + typeset TPATH=$2 1.502 + typeset lhsfile=$3 1.503 + typeset rhsfile=$4 1.504 + typeset comments=$5 1.505 + typeset RTOP 1.506 + 1.507 + # Enable html files to access WDIR via a relative path. 1.508 + RTOP=$(relative_dir $TPATH $WDIR) 1.509 + 1.510 + # Make the rhs/lhs files and output the frameset file. 1.511 + print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html 1.512 + 1.513 + cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF 1.514 + <script type="text/javascript" src="$RTOP/ancnav.js"></script> 1.515 + </head> 1.516 + <body id="SUNWwebrev" onkeypress="keypress(event);"> 1.517 + <a name="0"></a> 1.518 + <pre>$comments</pre><hr></hr> 1.519 + EOF 1.520 + 1.521 + cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html 1.522 + 1.523 + insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html 1.524 + insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html 1.525 + 1.526 + close='</body></html>' 1.527 + 1.528 + print $close >> $WDIR/$DIR/$TNAME.lhs.html 1.529 + print $close >> $WDIR/$DIR/$TNAME.rhs.html 1.530 + 1.531 + print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html 1.532 + print "<title>$WNAME Framed-Sdiff " \ 1.533 + "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html 1.534 + cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF 1.535 + <frameset rows="*,60"> 1.536 + <frameset cols="50%,50%"> 1.537 + <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs" /> 1.538 + <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs" /> 1.539 + </frameset> 1.540 + <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0" 1.541 + marginheight="0" name="nav" /> 1.542 + <noframes> 1.543 + <body id="SUNWwebrev"> 1.544 + Alas 'frames' webrev requires that your browser supports frames 1.545 + and has the feature enabled. 1.546 + </body> 1.547 + </noframes> 1.548 + </frameset> 1.549 + </html> 1.550 + EOF 1.551 +} 1.552 + 1.553 + 1.554 +# 1.555 +# fix_postscript 1.556 +# 1.557 +# Merge codereview output files to a single conforming postscript file, by: 1.558 +# - removing all extraneous headers/trailers 1.559 +# - making the page numbers right 1.560 +# - removing pages devoid of contents which confuse some 1.561 +# postscript readers. 1.562 +# 1.563 +# From Casper. 1.564 +# 1.565 +function fix_postscript 1.566 +{ 1.567 + infile=$1 1.568 + 1.569 + cat > /tmp/$$.crmerge.pl << \EOF 1.570 + 1.571 + print scalar(<>); # %!PS-Adobe--- 1.572 + print "%%Orientation: Landscape\n"; 1.573 + 1.574 + $pno = 0; 1.575 + $doprint = 1; 1.576 + 1.577 + $page = ""; 1.578 + 1.579 + while (<>) { 1.580 + next if (/^%%Pages:\s*\d+/); 1.581 + 1.582 + if (/^%%Page:/) { 1.583 + if ($pno == 0 || $page =~ /\)S/) { 1.584 + # Header or single page containing text 1.585 + print "%%Page: ? $pno\n" if ($pno > 0); 1.586 + print $page; 1.587 + $pno++; 1.588 + } else { 1.589 + # Empty page, skip it. 1.590 + } 1.591 + $page = ""; 1.592 + $doprint = 1; 1.593 + next; 1.594 + } 1.595 + 1.596 + # Skip from %%Trailer of one document to Endprolog 1.597 + # %%Page of the next 1.598 + $doprint = 0 if (/^%%Trailer/); 1.599 + $page .= $_ if ($doprint); 1.600 + } 1.601 + 1.602 + if ($page =~ /\)S/) { 1.603 + print "%%Page: ? $pno\n"; 1.604 + print $page; 1.605 + } else { 1.606 + $pno--; 1.607 + } 1.608 + print "%%Trailer\n%%Pages: $pno\n"; 1.609 +EOF 1.610 + 1.611 + $PERL /tmp/$$.crmerge.pl < $infile 1.612 +} 1.613 + 1.614 + 1.615 +# 1.616 +# input_cmd | insert_anchors | output_cmd 1.617 +# 1.618 +# Flag blocks of difference with sequentially numbered invisible 1.619 +# anchors. These are used to drive the frames version of the 1.620 +# sdiffs output. 1.621 +# 1.622 +# NOTE: Anchor zero flags the top of the file irrespective of changes, 1.623 +# an additional anchor is also appended to flag the bottom. 1.624 +# 1.625 +# The script detects changed lines as any line that has a "<span 1.626 +# class=" string embedded (unchanged lines have no class set and are 1.627 +# not part of a <span>. Blank lines (without a sequence number) 1.628 +# are also detected since they flag lines that have been inserted or 1.629 +# deleted. 1.630 +# 1.631 +function insert_anchors 1.632 +{ 1.633 + $AWK ' 1.634 + function ia() { 1.635 + # This should be able to be a singleton <a /> but that 1.636 + # seems to trigger a bug in firefox a:hover rule processing 1.637 + printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++; 1.638 + } 1.639 + 1.640 + BEGIN { 1.641 + anc=1; 1.642 + inblock=1; 1.643 + printf "<pre>\n"; 1.644 + } 1.645 + NF == 0 || /^<span class=/ { 1.646 + if (inblock == 0) { 1.647 + ia(); 1.648 + inblock=1; 1.649 + } 1.650 + print; 1.651 + next; 1.652 + } 1.653 + { 1.654 + inblock=0; 1.655 + print; 1.656 + } 1.657 + END { 1.658 + ia(); 1.659 + 1.660 + printf "<b style=\"font-size: large; color: red\">"; 1.661 + printf "--- EOF ---</b>" 1.662 + for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n"; 1.663 + printf "</pre>" 1.664 + printf "<form name=\"eof\">"; 1.665 + printf "<input name=\"value\" value=\"%d\" type=\"hidden\" />", 1.666 + anc - 1; 1.667 + printf "</form>"; 1.668 + } 1.669 + ' $1 1.670 +} 1.671 + 1.672 + 1.673 +# 1.674 +# relative_dir 1.675 +# 1.676 +# Print a relative return path from $1 to $2. For example if 1.677 +# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview, 1.678 +# this function would print "../../../../". 1.679 +# 1.680 +# In the event that $1 is not in $2 a warning is printed to stderr, 1.681 +# and $2 is returned-- the result of this is that the resulting webrev 1.682 +# is not relocatable. 1.683 +# 1.684 +function relative_dir 1.685 +{ 1.686 + d1=$1 1.687 + d2=$2 1.688 + if [[ "$d1" == "." ]]; then 1.689 + print "." 1.690 + else 1.691 + typeset cur="${d1##$d2?(/)}" 1.692 + typeset ret="" 1.693 + if [[ $d2 == $cur ]]; then # Should never happen. 1.694 + # Should never happen. 1.695 + print -u2 "\nWARNING: relative_dir: \"$1\" not relative " 1.696 + print -u2 "to \"$2\". Check input paths. Framed webrev " 1.697 + print -u2 "will not be relocatable!" 1.698 + print $2 1.699 + return 1.700 + fi 1.701 + 1.702 + while [[ -n ${cur} ]]; 1.703 + do 1.704 + cur=${cur%%*(/)*([!/])} 1.705 + if [[ -z $ret ]]; then 1.706 + ret=".." 1.707 + else 1.708 + ret="../$ret" 1.709 + fi 1.710 + done 1.711 + print $ret 1.712 + fi 1.713 +} 1.714 + 1.715 + 1.716 +# 1.717 +# frame_nav_js 1.718 +# 1.719 +# Emit javascript for frame navigation 1.720 +# 1.721 +function frame_nav_js 1.722 +{ 1.723 +cat << \EOF 1.724 +var myInt; 1.725 +var scrolling=0; 1.726 +var sfactor = 3; 1.727 +var scount=10; 1.728 + 1.729 +function scrollByPix() { 1.730 + if (scount<=0) { 1.731 + sfactor*=1.2; 1.732 + scount=10; 1.733 + } 1.734 + parent.lhs.scrollBy(0,sfactor); 1.735 + parent.rhs.scrollBy(0,sfactor); 1.736 + scount--; 1.737 +} 1.738 + 1.739 +function scrollToAnc(num) { 1.740 + 1.741 + // Update the value of the anchor in the form which we use as 1.742 + // storage for this value. setAncValue() will take care of 1.743 + // correcting for overflow and underflow of the value and return 1.744 + // us the new value. 1.745 + num = setAncValue(num); 1.746 + 1.747 + // Set location and scroll back a little to expose previous 1.748 + // lines. 1.749 + // 1.750 + // Note that this could be improved: it is possible although 1.751 + // complex to compute the x and y position of an anchor, and to 1.752 + // scroll to that location directly. 1.753 + // 1.754 + parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num); 1.755 + parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num); 1.756 + 1.757 + parent.lhs.scrollBy(0,-30); 1.758 + parent.rhs.scrollBy(0,-30); 1.759 +} 1.760 + 1.761 +function getAncValue() 1.762 +{ 1.763 + return (parseInt(parent.nav.document.diff.real.value)); 1.764 +} 1.765 + 1.766 +function setAncValue(val) 1.767 +{ 1.768 + if (val <= 0) { 1.769 + val = 0; 1.770 + parent.nav.document.diff.real.value = val; 1.771 + parent.nav.document.diff.display.value = "BOF"; 1.772 + return (val); 1.773 + } 1.774 + 1.775 + // 1.776 + // The way we compute the max anchor value is to stash it 1.777 + // inline in the left and right hand side pages-- it's the same 1.778 + // on each side, so we pluck from the left. 1.779 + // 1.780 + maxval = parent.lhs.document.eof.value.value; 1.781 + if (val < maxval) { 1.782 + parent.nav.document.diff.real.value = val; 1.783 + parent.nav.document.diff.display.value = val.toString(); 1.784 + return (val); 1.785 + } 1.786 + 1.787 + // this must be: val >= maxval 1.788 + val = maxval; 1.789 + parent.nav.document.diff.real.value = val; 1.790 + parent.nav.document.diff.display.value = "EOF"; 1.791 + return (val); 1.792 +} 1.793 + 1.794 +function stopScroll() { 1.795 + if (scrolling==1) { 1.796 + clearInterval(myInt); 1.797 + scrolling=0; 1.798 + } 1.799 +} 1.800 + 1.801 +function startScroll() { 1.802 + stopScroll(); 1.803 + scrolling=1; 1.804 + myInt=setInterval("scrollByPix()",10); 1.805 +} 1.806 + 1.807 +function handlePress(b) { 1.808 + 1.809 + switch (b) { 1.810 + case 1 : 1.811 + scrollToAnc(-1); 1.812 + break; 1.813 + case 2 : 1.814 + scrollToAnc(getAncValue() - 1); 1.815 + break; 1.816 + case 3 : 1.817 + sfactor=-3; 1.818 + startScroll(); 1.819 + break; 1.820 + case 4 : 1.821 + sfactor=3; 1.822 + startScroll(); 1.823 + break; 1.824 + case 5 : 1.825 + scrollToAnc(getAncValue() + 1); 1.826 + break; 1.827 + case 6 : 1.828 + scrollToAnc(999999); 1.829 + break; 1.830 + } 1.831 +} 1.832 + 1.833 +function handleRelease(b) { 1.834 + stopScroll(); 1.835 +} 1.836 + 1.837 +function keypress(ev) { 1.838 + var keynum; 1.839 + var keychar; 1.840 + 1.841 + if (window.event) { // IE 1.842 + keynum = ev.keyCode; 1.843 + } else if (ev.which) { // non-IE 1.844 + keynum = ev.which; 1.845 + } 1.846 + 1.847 + keychar = String.fromCharCode(keynum); 1.848 + 1.849 + if (keychar == "k") { 1.850 + handlePress(2); 1.851 + return (0); 1.852 + } else if (keychar == "j" || keychar == " ") { 1.853 + handlePress(5); 1.854 + return (0); 1.855 + } 1.856 + return (1); 1.857 +} 1.858 + 1.859 +function ValidateDiffNum(){ 1.860 + val = parent.nav.document.diff.display.value; 1.861 + if (val == "EOF") { 1.862 + scrollToAnc(999999); 1.863 + return; 1.864 + } 1.865 + 1.866 + if (val == "BOF") { 1.867 + scrollToAnc(0); 1.868 + return; 1.869 + } 1.870 + 1.871 + i=parseInt(val); 1.872 + if (isNaN(i)) { 1.873 + parent.nav.document.diff.display.value = getAncValue(); 1.874 + } else { 1.875 + scrollToAnc(i); 1.876 + } 1.877 + return false; 1.878 +} 1.879 + 1.880 +EOF 1.881 +} 1.882 + 1.883 +# 1.884 +# frame_navigation 1.885 +# 1.886 +# Output anchor navigation file for framed sdiffs. 1.887 +# 1.888 +function frame_navigation 1.889 +{ 1.890 + print "$HTML<head>$STDHEAD" 1.891 + 1.892 + cat << \EOF 1.893 +<title>Anchor Navigation</title> 1.894 +<meta http-equiv="Content-Script-Type" content="text/javascript" /> 1.895 +<meta http-equiv="Content-Type" content="text/html" /> 1.896 + 1.897 +<style type="text/css"> 1.898 + div.button td { padding-left: 5px; padding-right: 5px; 1.899 + background-color: #eee; text-align: center; 1.900 + border: 1px #444 outset; cursor: pointer; } 1.901 + div.button a { font-weight: bold; color: black } 1.902 + div.button td:hover { background: #ffcc99; } 1.903 +</style> 1.904 +EOF 1.905 + 1.906 + print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>" 1.907 + 1.908 + cat << \EOF 1.909 +</head> 1.910 +<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();" 1.911 + onkeypress="keypress(event);"> 1.912 + <noscript lang="javascript"> 1.913 + <center> 1.914 + <p><big>Framed Navigation controls require Javascript</big><br /> 1.915 + Either this browser is incompatable or javascript is not enabled</p> 1.916 + </center> 1.917 + </noscript> 1.918 + <table width="100%" border="0" align="center"> 1.919 + <tr> 1.920 + <td valign="middle" width="25%">Diff navigation: 1.921 + Use 'j' and 'k' for next and previous diffs; or use buttons 1.922 + at right</td> 1.923 + <td align="center" valign="top" width="50%"> 1.924 + <div class="button"> 1.925 + <table border="0" align="center"> 1.926 + <tr> 1.927 + <td> 1.928 + <a onMouseDown="handlePress(1);return true;" 1.929 + onMouseUp="handleRelease(1);return true;" 1.930 + onMouseOut="handleRelease(1);return true;" 1.931 + onClick="return false;" 1.932 + title="Go to Beginning Of file">BOF</a></td> 1.933 + <td> 1.934 + <a onMouseDown="handlePress(3);return true;" 1.935 + onMouseUp="handleRelease(3);return true;" 1.936 + onMouseOut="handleRelease(3);return true;" 1.937 + title="Scroll Up: Press and Hold to accelerate" 1.938 + onClick="return false;">Scroll Up</a></td> 1.939 + <td> 1.940 + <a onMouseDown="handlePress(2);return true;" 1.941 + onMouseUp="handleRelease(2);return true;" 1.942 + onMouseOut="handleRelease(2);return true;" 1.943 + title="Go to previous Diff" 1.944 + onClick="return false;">Prev Diff</a> 1.945 + </td></tr> 1.946 + 1.947 + <tr> 1.948 + <td> 1.949 + <a onMouseDown="handlePress(6);return true;" 1.950 + onMouseUp="handleRelease(6);return true;" 1.951 + onMouseOut="handleRelease(6);return true;" 1.952 + onClick="return false;" 1.953 + title="Go to End Of File">EOF</a></td> 1.954 + <td> 1.955 + <a onMouseDown="handlePress(4);return true;" 1.956 + onMouseUp="handleRelease(4);return true;" 1.957 + onMouseOut="handleRelease(4);return true;" 1.958 + title="Scroll Down: Press and Hold to accelerate" 1.959 + onClick="return false;">Scroll Down</a></td> 1.960 + <td> 1.961 + <a onMouseDown="handlePress(5);return true;" 1.962 + onMouseUp="handleRelease(5);return true;" 1.963 + onMouseOut="handleRelease(5);return true;" 1.964 + title="Go to next Diff" 1.965 + onClick="return false;">Next Diff</a></td> 1.966 + </tr> 1.967 + </table> 1.968 + </div> 1.969 + </td> 1.970 + <th valign="middle" width="25%"> 1.971 + <form action="" name="diff" onsubmit="return ValidateDiffNum();"> 1.972 + <input name="display" value="BOF" size="8" type="text" /> 1.973 + <input name="real" value="0" size="8" type="hidden" /> 1.974 + </form> 1.975 + </th> 1.976 + </tr> 1.977 + </table> 1.978 + </body> 1.979 +</html> 1.980 +EOF 1.981 +} 1.982 + 1.983 + 1.984 + 1.985 +# 1.986 +# diff_to_html <filename> <filepath> { U | C } <comment> 1.987 +# 1.988 +# Processes the output of diff to produce an HTML file representing either 1.989 +# context or unified diffs. 1.990 +# 1.991 +diff_to_html() 1.992 +{ 1.993 + TNAME=$1 1.994 + TPATH=$2 1.995 + DIFFTYPE=$3 1.996 + COMMENT=$4 1.997 + 1.998 + print "$HTML<head>$STDHEAD" 1.999 + print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>" 1.1000 + 1.1001 + if [[ $DIFFTYPE == "U" ]]; then 1.1002 + print "$UDIFFCSS" 1.1003 + fi 1.1004 + 1.1005 + cat <<-EOF 1.1006 + </head> 1.1007 + <body id="SUNWwebrev"> 1.1008 + <h2>$TPATH</h2> 1.1009 + <a class="print" href="javascript:print()">Print this page</a> 1.1010 + <pre>$COMMENT</pre> 1.1011 + <pre> 1.1012 +EOF 1.1013 + 1.1014 + html_quote | $AWK ' 1.1015 + /^--- new/ { next } 1.1016 + /^\+\+\+ new/ { next } 1.1017 + /^--- old/ { next } 1.1018 + /^\*\*\* old/ { next } 1.1019 + /^\*\*\*\*/ { next } 1.1020 + /^-------/ { printf "<center><h1>%s</h1></center>\n", $0; next } 1.1021 + /^\@\@.*\@\@$/ { printf "</pre><hr /><pre>\n"; 1.1022 + printf "<span class=\"newmarker\">%s</span>\n", $0; 1.1023 + next} 1.1024 + 1.1025 + /^\*\*\*/ { printf "<hr /><span class=\"oldmarker\">%s</span>\n", $0; 1.1026 + next} 1.1027 + /^---/ { printf "<span class=\"newmarker\">%s</span>\n", $0; 1.1028 + next} 1.1029 + /^\+/ {printf "<span class=\"new\">%s</span>\n", $0; next} 1.1030 + /^!/ {printf "<span class=\"changed\">%s</span>\n", $0; next} 1.1031 + /^-/ {printf "<span class=\"removed\">%s</span>\n", $0; next} 1.1032 + {printf "%s\n", $0; next} 1.1033 + ' 1.1034 + 1.1035 + print "</pre></body></html>\n" 1.1036 +} 1.1037 + 1.1038 + 1.1039 +# 1.1040 +# source_to_html { new | old } <filename> 1.1041 +# 1.1042 +# Process a plain vanilla source file to transform it into an HTML file. 1.1043 +# 1.1044 +source_to_html() 1.1045 +{ 1.1046 + WHICH=$1 1.1047 + TNAME=$2 1.1048 + 1.1049 + print "$HTML<head>$STDHEAD" 1.1050 + print "<title>$WHICH $TNAME</title>" 1.1051 + print "<body id=\"SUNWwebrev\">" 1.1052 + print "<pre>" 1.1053 + html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }' 1.1054 + print "</pre></body></html>" 1.1055 +} 1.1056 + 1.1057 +comments_from_mercurial() 1.1058 +{ 1.1059 + fmt=$1 1.1060 + pfile=$PWS/$2 1.1061 + cfile=$CWS/$3 1.1062 + 1.1063 + logdir=`dirname $cfile` 1.1064 + logf=`basename $cfile` 1.1065 + if [ -d $logdir ]; then 1.1066 + ( cd $logdir; 1.1067 + active=`hg status $logf 2>/dev/null` 1.1068 + # If the output from 'hg status' is not empty, it means the file 1.1069 + # hasn't been committed, so don't fetch comments. 1.1070 + if [[ -z $active ]] ; then 1.1071 + if [[ -n $ALL_CREV ]]; then 1.1072 + rev_opt= 1.1073 + for rev in $ALL_CREV; do 1.1074 + rev_opt="$rev_opt --rev $rev" 1.1075 + done 1.1076 + comm=`hg log $rev_opt --follow --template 'rev {rev} : {desc}\n' $logf` 1.1077 + elif [[ -n $FIRST_CREV ]]; then 1.1078 + comm=`hg log --rev $FIRST_CREV:tip --follow --template 'rev {rev} : {desc}\n' $logf` 1.1079 + else 1.1080 + comm=`hg log -l1 --follow --template 'rev {rev} : {desc}\n' $logf` 1.1081 + fi 1.1082 + else 1.1083 + comm="" 1.1084 + fi 1.1085 + if [[ $fmt == "text" ]]; then 1.1086 + print "$comm" 1.1087 + return 1.1088 + fi 1.1089 + 1.1090 + print "$comm" | html_quote | bug2url 1.1091 + ) 1.1092 + fi 1.1093 +} 1.1094 + 1.1095 + 1.1096 +# 1.1097 +# getcomments {text|html} filepath parentpath 1.1098 +# 1.1099 +# Fetch the comments depending on what SCM mode we're in. 1.1100 +# 1.1101 +getcomments() 1.1102 +{ 1.1103 + typeset fmt=$1 1.1104 + typeset p=$2 1.1105 + typeset pp=$3 1.1106 + 1.1107 + comments_from_mercurial $fmt $pp $p 1.1108 +} 1.1109 + 1.1110 +# 1.1111 +# printCI <total-changed> <inserted> <deleted> <modified> <unchanged> 1.1112 +# 1.1113 +# Print out Code Inspection figures similar to sccs-prt(1) format. 1.1114 +# 1.1115 +function printCI 1.1116 +{ 1.1117 + integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5 1.1118 + typeset str 1.1119 + if (( tot == 1 )); then 1.1120 + str="line" 1.1121 + else 1.1122 + str="lines" 1.1123 + fi 1.1124 + printf '%d %s changed: %d ins; %d del; %d mod; %d unchg' \ 1.1125 + $tot $str $ins $del $mod $unc 1.1126 +} 1.1127 + 1.1128 + 1.1129 +# 1.1130 +# difflines <oldfile> <newfile> 1.1131 +# 1.1132 +# Calculate and emit number of added, removed, modified and unchanged lines, 1.1133 +# and total lines changed, the sum of added + removed + modified. 1.1134 +# 1.1135 +function difflines 1.1136 +{ 1.1137 + integer tot mod del ins unc err 1.1138 + typeset filename 1.1139 + 1.1140 + eval $( diff -e $1 $2 | $AWK ' 1.1141 + # Change range of lines: N,Nc 1.1142 + /^[0-9]*,[0-9]*c$/ { 1.1143 + n=split(substr($1,1,length($1)-1), counts, ","); 1.1144 + if (n != 2) { 1.1145 + error=2 1.1146 + exit; 1.1147 + } 1.1148 + # 1.1149 + # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines. 1.1150 + # following would be 5 - 3 = 2! Hence +1 for correction. 1.1151 + # 1.1152 + r=(counts[2]-counts[1])+1; 1.1153 + 1.1154 + # 1.1155 + # Now count replacement lines: each represents a change instead 1.1156 + # of a delete, so increment c and decrement r. 1.1157 + # 1.1158 + while (getline != /^\.$/) { 1.1159 + c++; 1.1160 + r--; 1.1161 + } 1.1162 + # 1.1163 + # If there were more replacement lines than original lines, 1.1164 + # then r will be negative; in this case there are no deletions, 1.1165 + # but there are r changes that should be counted as adds, and 1.1166 + # since r is negative, subtract it from a and add it to c. 1.1167 + # 1.1168 + if (r < 0) { 1.1169 + a-=r; 1.1170 + c+=r; 1.1171 + } 1.1172 + 1.1173 + # 1.1174 + # If there were more original lines than replacement lines, then 1.1175 + # r will be positive; in this case, increment d by that much. 1.1176 + # 1.1177 + if (r > 0) { 1.1178 + d+=r; 1.1179 + } 1.1180 + next; 1.1181 + } 1.1182 + 1.1183 + # Change lines: Nc 1.1184 + /^[0-9].*c$/ { 1.1185 + # The first line is a replacement; any more are additions. 1.1186 + if (getline != /^\.$/) { 1.1187 + c++; 1.1188 + while (getline != /^\.$/) a++; 1.1189 + } 1.1190 + next; 1.1191 + } 1.1192 + 1.1193 + # Add lines: both Na and N,Na 1.1194 + /^[0-9].*a$/ { 1.1195 + while (getline != /^\.$/) a++; 1.1196 + next; 1.1197 + } 1.1198 + 1.1199 + # Delete range of lines: N,Nd 1.1200 + /^[0-9]*,[0-9]*d$/ { 1.1201 + n=split(substr($1,1,length($1)-1), counts, ","); 1.1202 + if (n != 2) { 1.1203 + error=2 1.1204 + exit; 1.1205 + } 1.1206 + # 1.1207 + # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines. 1.1208 + # following would be 5 - 3 = 2! Hence +1 for correction. 1.1209 + # 1.1210 + r=(counts[2]-counts[1])+1; 1.1211 + d+=r; 1.1212 + next; 1.1213 + } 1.1214 + 1.1215 + # Delete line: Nd. For example 10d says line 10 is deleted. 1.1216 + /^[0-9]*d$/ {d++; next} 1.1217 + 1.1218 + # Should not get here! 1.1219 + { 1.1220 + error=1; 1.1221 + exit; 1.1222 + } 1.1223 + 1.1224 + # Finish off - print results 1.1225 + END { 1.1226 + printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n", 1.1227 + (c+d+a), c, d, a, error); 1.1228 + }' ) 1.1229 + 1.1230 + # End of $AWK, Check to see if any trouble occurred. 1.1231 + if (( $? > 0 || err > 0 )); then 1.1232 + print "Unexpected Error occurred reading" \ 1.1233 + "\`diff -e $1 $2\`: \$?=$?, err=" $err 1.1234 + return 1.1235 + fi 1.1236 + 1.1237 + # Accumulate totals 1.1238 + (( TOTL += tot )) 1.1239 + (( TMOD += mod )) 1.1240 + (( TDEL += del )) 1.1241 + (( TINS += ins )) 1.1242 + # Calculate unchanged lines 1.1243 + unc=`wc -l < $1` 1.1244 + if (( unc > 0 )); then 1.1245 + (( unc -= del + mod )) 1.1246 + (( TUNC += unc )) 1.1247 + fi 1.1248 + # print summary 1.1249 + print "<span class=\"lineschanged\">\c" 1.1250 + printCI $tot $ins $del $mod $unc 1.1251 + print "</span>" 1.1252 +} 1.1253 + 1.1254 +function outgoing_from_mercurial_forest 1.1255 +{ 1.1256 + hg foutgoing --template 'rev: {rev}\n' $OUTPWS | $FILTER | $AWK ' 1.1257 + BEGIN {ntree=0} 1.1258 + /^comparing/ {next} 1.1259 + /^no changes/ {next} 1.1260 + /^searching/ {next} 1.1261 + /^\[.*\]$/ {tree=substr($1,2,length($1)-2); 1.1262 + trees[ntree++] = tree; 1.1263 + revs[tree]=-1; 1.1264 + next} 1.1265 + /^rev:/ {rev=$2+0; 1.1266 + if (revs[tree] == -1 || rev < revs[tree]) 1.1267 + { revs[tree] = rev; }; 1.1268 + next;} 1.1269 + END {for (tree in trees) 1.1270 + { rev=revs[trees[tree]]; 1.1271 + if (rev > 0) 1.1272 + {printf("%s %d\n",trees[tree],rev-1)} 1.1273 + }}' | while read LINE 1.1274 + do 1.1275 + set - $LINE 1.1276 + TREE=$1 1.1277 + REV=$2 1.1278 + A=`hg -R $CWS/$TREE log --rev $REV --template '{node}'` 1.1279 + FSTAT_OPT="--rev $A" 1.1280 + print "Revision: $A $REV" >> $FLIST 1.1281 + treestatus $TREE 1.1282 + done 1.1283 +} 1.1284 + 1.1285 +function flist_from_mercurial_forest 1.1286 +{ 1.1287 + rm -f $FLIST 1.1288 + if [ -z "$Nflag" ]; then 1.1289 + print " File list from hg foutgoing $PWS ..." 1.1290 + outgoing_from_mercurial_forest 1.1291 + HG_LIST_FROM_COMMIT=1 1.1292 + fi 1.1293 + if [ ! -f $FLIST ]; then 1.1294 + # hg commit hasn't been run see what is lying around 1.1295 + print "\n No outgoing, perhaps you haven't commited." 1.1296 + print " File list from hg fstatus -mard ...\c" 1.1297 + FSTAT_OPT= 1.1298 + fstatus 1.1299 + HG_LIST_FROM_COMMIT= 1.1300 + fi 1.1301 + print " Done." 1.1302 +} 1.1303 + 1.1304 +# 1.1305 +# Used when dealing with the result of 'hg foutgoing' 1.1306 +# When now go down the tree and generate the change list 1.1307 +# 1.1308 +function treestatus 1.1309 +{ 1.1310 + TREE=$1 1.1311 + HGCMD="hg -R $CWS/$TREE status $FSTAT_OPT" 1.1312 + 1.1313 + $HGCMD -mdn 2>/dev/null | $FILTER | while read F 1.1314 + do 1.1315 + echo $TREE/$F 1.1316 + done >> $FLIST 1.1317 + 1.1318 + # Then all the added files 1.1319 + # But some of these could have been "moved" or renamed ones or copied ones 1.1320 + # so let's make sure we get the proper info 1.1321 + # hg status -aC will produce something like: 1.1322 + # A subdir/File3 1.1323 + # A subdir/File4 1.1324 + # File4 1.1325 + # A subdir/File5 1.1326 + # The first and last are simple addition while the middle one 1.1327 + # is a move/rename or a copy. We can't distinguish from a rename vs a copy 1.1328 + # without also getting the status of removed files. The middle case above 1.1329 + # is a rename if File4 is also shown a being removed. If File4 is not a 1.1330 + # removed file, then the middle case is a copy from File4 to subdir/File4 1.1331 + # FIXME - we're not distinguishing copy from rename 1.1332 + $HGCMD -aC | $FILTER | while read LINE; do 1.1333 + ldone="" 1.1334 + while [ -z "$ldone" ]; do 1.1335 + ldone="1" 1.1336 + set - $LINE 1.1337 + if [ $# -eq 2 -a "$1" == "A" ]; then 1.1338 + AFILE=$2 1.1339 + if read LINE2; then 1.1340 + set - $LINE2 1.1341 + if [ $# -eq 1 ]; then 1.1342 + echo $TREE/$AFILE $TREE/$1 >>$FLIST 1.1343 + elif [ $# -eq 2 ]; then 1.1344 + echo $TREE/$AFILE >>$FLIST 1.1345 + LINE=$LINE2 1.1346 + ldone="" 1.1347 + fi 1.1348 + else 1.1349 + echo $TREE/$AFILE >>$FLIST 1.1350 + fi 1.1351 + fi 1.1352 + done 1.1353 + done 1.1354 + $HGCMD -rn | $FILTER | while read RFILE; do 1.1355 + grep "$TREE/$RFILE" $FLIST >/dev/null 1.1356 + if [ $? -eq 1 ]; then 1.1357 + echo $TREE/$RFILE >>$FLIST 1.1358 + fi 1.1359 + done 1.1360 +} 1.1361 + 1.1362 +function fstatus 1.1363 +{ 1.1364 + # 1.1365 + # forest extension is still being changed. For instance the output 1.1366 + # of fstatus used to no prepend the tree path to filenames, but 1.1367 + # this has changed recently. AWK code below does try to handle both 1.1368 + # cases 1.1369 + # 1.1370 + hg fstatus -mdn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' 1.1371 + /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} 1.1372 + $1 != "" {n=index($1,tree); 1.1373 + if (n == 0) 1.1374 + { printf("%s/%s\n",tree,$1)} 1.1375 + else 1.1376 + { printf("%s\n",$1)}}' >> $FLIST 1.1377 + 1.1378 + # 1.1379 + # There is a bug in the output of fstatus -aC on recent versions: it 1.1380 + # inserts a space between the name of the tree and the filename of the 1.1381 + # old file. e.g.: 1.1382 + # 1.1383 + # $ hg fstatus -aC 1.1384 + # [.] 1.1385 + # 1.1386 + # [MyWS] 1.1387 + # A MyWS/subdir/File2 1.1388 + # MyWS/ File2 1.1389 + # 1.1390 + # [MyWS2] 1.1391 + # 1.1392 + 1.1393 + hg fstatus -aC $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' 1.1394 + /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} 1.1395 + /^A .*/ {n=index($2,tree); 1.1396 + if (n == 0) 1.1397 + { printf("A %s/%s\n",tree,$2)} 1.1398 + else 1.1399 + { printf("A %s\n",$2)}; 1.1400 + next} 1.1401 + /^ / {n=index($1,tree); 1.1402 + if (n == 0) 1.1403 + { printf("%s/%s\n",tree,$1)} 1.1404 + else 1.1405 + { if (NF == 2) 1.1406 + printf("%s/%s\n",tree,$2) 1.1407 + else 1.1408 + printf("%s\n",$1) 1.1409 + }; 1.1410 + next} 1.1411 + ' | while read LINE; do 1.1412 + ldone="" 1.1413 + while [ -z "$ldone" ]; do 1.1414 + ldone="1" 1.1415 + set - $LINE 1.1416 + if [ $# -eq 2 -a "$1" == "A" ]; then 1.1417 + AFILE=$2 1.1418 + if read LINE2; then 1.1419 + set - $LINE2 1.1420 + if [ $# -eq 1 ]; then 1.1421 + echo $AFILE $1 >>$FLIST 1.1422 + elif [ $# -eq 2 ]; then 1.1423 + echo $AFILE >>$FLIST 1.1424 + LINE=$LINE2 1.1425 + ldone="" 1.1426 + fi 1.1427 + else 1.1428 + echo $AFILE >>$FLIST 1.1429 + fi 1.1430 + fi 1.1431 + done 1.1432 + done 1.1433 + hg fstatus -rn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK ' 1.1434 + /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next} 1.1435 + $1 != "" {n=index($1,tree); 1.1436 + if (n == 0) 1.1437 + { printf("%s/%s\n",tree,$1)} 1.1438 + else 1.1439 + { printf("%s\n",$1)}}' | while read RFILE; do 1.1440 + grep "$RFILE" $FLIST >/dev/null 1.1441 + if [ $? -eq 1 ]; then 1.1442 + echo $RFILE >>$FLIST 1.1443 + fi 1.1444 + done 1.1445 +} 1.1446 + 1.1447 +# 1.1448 +# flist_from_mercurial $PWS 1.1449 +# 1.1450 +# Only local file based repositories are supported at present 1.1451 +# since even though we can determine the list from the parent finding 1.1452 +# the changes is harder. 1.1453 +# 1.1454 +# We first look for any outgoing files, this is for when the user has 1.1455 +# run hg commit. If we don't find any then we look with hg status. 1.1456 +# 1.1457 +# We need at least one of default-push or default paths set in .hg/hgrc 1.1458 +# If neither are set we don't know who to compare with. 1.1459 + 1.1460 +function flist_from_mercurial 1.1461 +{ 1.1462 +# if [ "${PWS##ssh://}" != "$PWS" -o \ 1.1463 +# "${PWS##http://}" != "$PWS" -o \ 1.1464 +# "${PWS##https://}" != "$PWS" ]; then 1.1465 +# print "Remote Mercurial repositories not currently supported." 1.1466 +# print "Set default and/or default-push to a local repository" 1.1467 +# exit 1.1468 +# fi 1.1469 + if [[ -n $forestflag ]]; then 1.1470 + HG_LIST_FROM_COMMIT= 1.1471 + flist_from_mercurial_forest 1.1472 + else 1.1473 + STATUS_REV= 1.1474 + if [[ -n $rflag ]]; then 1.1475 + STATUS_REV="--rev $PARENT_REV" 1.1476 + elif [[ -n $OUTREV ]]; then 1.1477 + STATUS_REV="--rev $OUTREV" 1.1478 + else 1.1479 + # hg commit hasn't been run see what is lying around 1.1480 + print "\n No outgoing, perhaps you haven't commited." 1.1481 + fi 1.1482 + # First let's list all the modified or deleted files 1.1483 + 1.1484 + hg status $STATUS_REV -mdn | $FILTER > $FLIST 1.1485 + 1.1486 + # Then all the added files 1.1487 + # But some of these could have been "moved" or renamed ones 1.1488 + # so let's make sure we get the proper info 1.1489 + # hg status -aC will produce something like: 1.1490 + # A subdir/File3 1.1491 + # A subdir/File4 1.1492 + # File4 1.1493 + # A subdir/File5 1.1494 + # The first and last are simple addition while the middle one 1.1495 + # is a move/rename or a copy. We can't distinguish from a rename vs a copy 1.1496 + # without also getting the status of removed files. The middle case above 1.1497 + # is a rename if File4 is also shown a being removed. If File4 is not a 1.1498 + # removed file, then the middle case is a copy from File4 to subdir/File4 1.1499 + # FIXME - we're not distinguishing copy from rename 1.1500 + 1.1501 + hg status $STATUS_REV -aC | $FILTER >$FLIST.temp 1.1502 + while read LINE; do 1.1503 + ldone="" 1.1504 + while [ -z "$ldone" ]; do 1.1505 + ldone="1" 1.1506 + set - $LINE 1.1507 + if [ $# -eq 2 -a "$1" == "A" ]; then 1.1508 + AFILE=$2 1.1509 + if read LINE2; then 1.1510 + set - $LINE2 1.1511 + if [ $# -eq 1 ]; then 1.1512 + echo $AFILE $1 >>$FLIST 1.1513 + elif [ $# -eq 2 ]; then 1.1514 + echo $AFILE >>$FLIST 1.1515 + LINE=$LINE2 1.1516 + ldone="" 1.1517 + fi 1.1518 + else 1.1519 + echo $AFILE >>$FLIST 1.1520 + fi 1.1521 + fi 1.1522 + done 1.1523 + done < $FLIST.temp 1.1524 + hg status $STATUS_REV -rn | $FILTER > $FLIST.temp 1.1525 + while read RFILE; do 1.1526 + grep "$RFILE" $FLIST >/dev/null 1.1527 + if [ $? -eq 1 ]; then 1.1528 + echo $RFILE >>$FLIST 1.1529 + fi 1.1530 + done < $FLIST.temp 1.1531 + rm -f $FLIST.temp 1.1532 + fi 1.1533 +} 1.1534 + 1.1535 +function env_from_flist 1.1536 +{ 1.1537 + [[ -r $FLIST ]] || return 1.1538 + 1.1539 + # 1.1540 + # Use "eval" to set env variables that are listed in the file 1.1541 + # list. Then copy those into our local versions of those 1.1542 + # variables if they have not been set already. 1.1543 + # 1.1544 + eval `sed -e "s/#.*$//" $FLIST | grep = ` 1.1545 + 1.1546 + [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS 1.1547 + 1.1548 + # 1.1549 + # Check to see if CODEMGR_PARENT is set in the flist file. 1.1550 + # 1.1551 + [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \ 1.1552 + codemgr_parent=$CODEMGR_PARENT 1.1553 +} 1.1554 + 1.1555 +# 1.1556 +# detect_scm 1.1557 +# 1.1558 +# We dynamically test the SCM type; this allows future extensions to 1.1559 +# new SCM types 1.1560 +# 1.1561 +function detect_scm 1.1562 +{ 1.1563 + if hg root >/dev/null ; then 1.1564 + print "mercurial" 1.1565 + else 1.1566 + print "unknown" 1.1567 + fi 1.1568 +} 1.1569 + 1.1570 +function look_for_prog 1.1571 +{ 1.1572 + typeset path 1.1573 + typeset ppath 1.1574 + typeset progname=$1 1.1575 + 1.1576 + DEVTOOLS= 1.1577 + OS=`uname` 1.1578 + if [[ "$OS" == "SunOS" ]]; then 1.1579 + DEVTOOLS="/java/devtools/`uname -p`/bin" 1.1580 + elif [[ "$OS" == "Linux" ]]; then 1.1581 + DEVTOOLS="/java/devtools/linux/bin" 1.1582 + fi 1.1583 + 1.1584 + ppath=$PATH 1.1585 + ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin 1.1586 + ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin 1.1587 + ppath=$ppath:/opt/onbld/bin/`uname -p` 1.1588 + ppath=$ppath:/java/devtools/share/bin:$DEVTOOLS 1.1589 + 1.1590 + PATH=$ppath prog=`whence $progname` 1.1591 + if [[ -n $prog ]]; then 1.1592 + print $prog 1.1593 + fi 1.1594 +} 1.1595 + 1.1596 +# 1.1597 +# Find the parent for $1 1.1598 +# 1.1599 +function find_outrev 1.1600 +{ 1.1601 + crev=$1 1.1602 + prev=`hg log -r $crev --template '{parents}\n'` 1.1603 + if [[ -z "$prev" ]] 1.1604 + then 1.1605 + # No specific parent means previous changeset is parent 1.1606 + prev=`expr $crev - 1` 1.1607 + else 1.1608 + # Format is either of the following two: 1.1609 + # 546:7df6fcf1183b 1.1610 + # 548:16f1915bb5cd 547:ffaa4e775815 1.1611 + prev=`echo $prev | sed -e 's/\([0-9]*\):.*/\1/'` 1.1612 + fi 1.1613 + print $prev 1.1614 +} 1.1615 + 1.1616 +function extract_ssh_infos 1.1617 +{ 1.1618 + CMD=$1 1.1619 + if expr "$CMD" : 'ssh://[^/]*@' >/dev/null; then 1.1620 + ssh_user=`echo $CMD | sed -e 's/ssh:\/\/\(.*\)@.*/\1/'` 1.1621 + ssh_host=`echo $CMD | sed -e 's/ssh:\/\/.*@\([^/]*\)\/.*/\1/'` 1.1622 + ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/.*@[^/]*\/\(.*\)/\1/'` 1.1623 + else 1.1624 + ssh_user= 1.1625 + ssh_host=`echo $CMD | sed -e 's/ssh:\/\/\([^/]*\)\/.*/\1/'` 1.1626 + ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/[^/]*\/\(.*\)/\1/'` 1.1627 + fi 1.1628 + 1.1629 +} 1.1630 + 1.1631 +function build_old_new_mercurial 1.1632 +{ 1.1633 + olddir=$1 1.1634 + newdir=$2 1.1635 + DIR=$3 1.1636 + F=$4 1.1637 + # 1.1638 + # new version of the file. 1.1639 + # 1.1640 + rm -rf $newdir/$DIR/$F 1.1641 + if [ -f $F ]; then 1.1642 + cp $F $newdir/$DIR/$F 1.1643 + fi 1.1644 + 1.1645 + # 1.1646 + # Old version of the file. 1.1647 + # 1.1648 + rm -rf $olddir/$DIR/$F 1.1649 + 1.1650 + if [ -n "$PWS" ]; then 1.1651 + if expr "$PWS" : 'ssh://' >/dev/null 1.1652 + then 1.1653 + extract_ssh_infos $PWS 1.1654 + if [ -n "$ssh_user" ]; then 1.1655 + parent="ssh -l $ssh_user $ssh_host hg -R $ssh_dir --cwd $ssh_dir" 1.1656 + else 1.1657 + parent="ssh $ssh_host hg -R $ssh_dir --cwd $ssh_dir" 1.1658 + fi 1.1659 + else 1.1660 + parent="hg -R $PWS --cwd $PWS" 1.1661 + fi 1.1662 + else 1.1663 + parent="" 1.1664 + fi 1.1665 + 1.1666 + if [ -z "$rename" ]; then 1.1667 + if [ -n "$rflag" ]; then 1.1668 + parentrev=$PARENT_REV 1.1669 + elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then 1.1670 + parentrev=$OUTREV 1.1671 + else 1.1672 + if [[ -n $HG_BRANCH ]]; then 1.1673 + parentrev=$HG_BRANCH 1.1674 + else 1.1675 + parentrev="tip" 1.1676 + fi 1.1677 + fi 1.1678 + 1.1679 + if [ -n "$parentrev" ]; then 1.1680 + if [ -z "$parent" ]; then 1.1681 + hg cat --rev $parentrev --output $olddir/$DIR/$F $F 2>/dev/null 1.1682 + else 1.1683 + # when specifying a workspace we have to provide 1.1684 + # the full path 1.1685 + $parent cat --rev $parentrev --output $olddir/$DIR/$F $DIR/$F 2>/dev/null 1.1686 + fi 1.1687 + fi 1.1688 + else 1.1689 + # It's a rename (or a move), or a copy, so let's make sure we move 1.1690 + # to the right directory first, then restore it once done 1.1691 + current_dir=`pwd` 1.1692 + hg_root=`hg root` 1.1693 + cd $CWS 1.1694 + if [ -n "$rflag" ]; then 1.1695 + parentrev=$PARENT_REV 1.1696 + elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then 1.1697 + parentrev=$OUTREV 1.1698 + fi 1.1699 + if [ -z "$parentrev" ]; then 1.1700 + parentrev=`hg log -l1 $PDIR/$PF | $AWK -F: '/changeset/ {print $2}'` 1.1701 + fi 1.1702 + if [ -n "$parentrev" ]; then 1.1703 + mkdir -p $olddir/$PDIR 1.1704 + if [ -z "$parent" ]; then 1.1705 + hg cat -R $hg_root --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null 1.1706 + else 1.1707 + $parent cat --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null 1.1708 + fi 1.1709 + fi 1.1710 + cd $current_dir 1.1711 + fi 1.1712 +} 1.1713 + 1.1714 +function build_old_new 1.1715 +{ 1.1716 + if [[ $SCM_MODE == "mercurial" ]]; then 1.1717 + build_old_new_mercurial $@ 1.1718 + fi 1.1719 +} 1.1720 + 1.1721 + 1.1722 +# 1.1723 +# Usage message. 1.1724 +# 1.1725 +function usage 1.1726 +{ 1.1727 + print "Usage:\twebrev [options] 1.1728 + webrev [options] ( <file> | - ) 1.1729 + 1.1730 +Options: 1.1731 + -v: Print the version of this tool. 1.1732 + -b: Do not ignore changes in the amount of white space. 1.1733 + -c <CR#>: Include link to CR (aka bugid) in the main page. 1.1734 + -i <filename>: Include <filename> in the index.html file. 1.1735 + -o <outdir>: Output webrev to specified directory. 1.1736 + -p <compare-against>: Use specified parent wkspc or basis for comparison 1.1737 + -u <username>: Use that username instead of 'guessing' one. 1.1738 + -m: Forces the use of Mercurial 1.1739 + 1.1740 +Mercurial only options: 1.1741 + -r rev: Compare against a specified revision 1.1742 + -N: Skip 'hg outgoing', use only 'hg status' 1.1743 + -f: Use the forest extension 1.1744 + 1.1745 +Arguments: 1.1746 + <file>: Optional file containing list of files to include in webrev 1.1747 + -: read list of files to include in webrev from standard input 1.1748 + 1.1749 +Environment: 1.1750 + WDIR: Control the output directory. 1.1751 + WEBREV_BUGURL: Control the URL prefix for bugids. 1.1752 + 1.1753 +" 1.1754 + 1.1755 + exit 2 1.1756 +} 1.1757 + 1.1758 +# 1.1759 +# 1.1760 +# Main program starts here 1.1761 +# 1.1762 +# 1.1763 +LANG="C" 1.1764 +LC_ALL="C" 1.1765 +export LANG LC_ALL 1.1766 +trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15 1.1767 + 1.1768 +set +o noclobber 1.1769 + 1.1770 +[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff` 1.1771 +[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview` 1.1772 +[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf` 1.1773 +[[ -z $PERL ]] && PERL=`look_for_prog perl` 1.1774 +[[ -z $SCCS ]] && SCCS=`look_for_prog sccs` 1.1775 +[[ -z $AWK ]] && AWK=`look_for_prog nawk` 1.1776 +[[ -z $AWK ]] && AWK=`look_for_prog gawk` 1.1777 +[[ -z $AWK ]] && AWK=`look_for_prog awk` 1.1778 +[[ -z $JAR ]] && JAR=`look_for_prog jar` 1.1779 +[[ -z $ZIP ]] && ZIP=`look_for_prog zip` 1.1780 +[[ -z $GETENT ]] && GETENT=`look_for_prog getent` 1.1781 +[[ -z $WGET ]] && WGET=`look_for_prog wget` 1.1782 + 1.1783 +if uname | grep CYGWIN >/dev/null 1.1784 +then 1.1785 + ISWIN=1 1.1786 + # Under windows mercurial outputs '\' instead of '/' 1.1787 + FILTER="tr '\\\\' '/'" 1.1788 +else 1.1789 + FILTER="cat" 1.1790 +fi 1.1791 + 1.1792 +if [[ ! -x $PERL ]]; then 1.1793 + print -u2 "Error: No perl interpreter found. Exiting." 1.1794 + exit 1 1.1795 +fi 1.1796 + 1.1797 +# 1.1798 +# These aren't fatal, but we want to note them to the user. 1.1799 +# 1.1800 +# [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found." 1.1801 +# [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found." 1.1802 +# [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found." 1.1803 + 1.1804 +# Declare global total counters. 1.1805 +integer TOTL TINS TDEL TMOD TUNC 1.1806 + 1.1807 +flist_mode= 1.1808 +flist_file= 1.1809 +bflag= 1.1810 +iflag= 1.1811 +oflag= 1.1812 +pflag= 1.1813 +uflag= 1.1814 +Oflag= 1.1815 +rflag= 1.1816 +Nflag= 1.1817 +forestflag= 1.1818 +while getopts "c:i:o:p:r:u:mONvfb" opt 1.1819 +do 1.1820 + case $opt in 1.1821 + b) bflag=1;; 1.1822 + 1.1823 + i) iflag=1 1.1824 + INCLUDE_FILE=$OPTARG;; 1.1825 + 1.1826 + o) oflag=1 1.1827 + WDIR=$OPTARG;; 1.1828 + 1.1829 + p) pflag=1 1.1830 + codemgr_parent=$OPTARG;; 1.1831 + 1.1832 + u) uflag=1 1.1833 + username=$OPTARG;; 1.1834 + 1.1835 + c) if [[ -z $CRID ]]; then 1.1836 + CRID=$OPTARG 1.1837 + else 1.1838 + CRID="$CRID $OPTARG" 1.1839 + fi;; 1.1840 + 1.1841 + m) SCM_MODE="mercurial";; 1.1842 + 1.1843 + O) Oflag=1;; # ignored (bugs are now all visible at bugs.openjdk.java.net) 1.1844 + 1.1845 + N) Nflag=1;; 1.1846 + 1.1847 + f) forestflag=1;; 1.1848 + 1.1849 + r) rflag=1 1.1850 + PARENT_REV=$OPTARG;; 1.1851 + 1.1852 + v) print "$0 version: $WEBREV_UPDATED";; 1.1853 + 1.1854 + 1.1855 + ?) usage;; 1.1856 + esac 1.1857 +done 1.1858 + 1.1859 +FLIST=/tmp/$$.flist 1.1860 +HG_LIST_FROM_COMMIT= 1.1861 + 1.1862 +if [[ -n $forestflag && -n $rflag ]]; then 1.1863 + print "The -r <rev> flag is incompatible with the use of forests" 1.1864 + exit 2 1.1865 +fi 1.1866 + 1.1867 +# 1.1868 +# If this manually set as the parent, and it appears to be an earlier webrev, 1.1869 +# then note that fact and set the parent to the raw_files/new subdirectory. 1.1870 +# 1.1871 +if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then 1.1872 + parent_webrev="$codemgr_parent" 1.1873 + codemgr_parent="$codemgr_parent/raw_files/new" 1.1874 +fi 1.1875 + 1.1876 +shift $(($OPTIND - 1)) 1.1877 + 1.1878 +if [[ $1 == "-" ]]; then 1.1879 + cat > $FLIST 1.1880 + flist_mode="stdin" 1.1881 + flist_done=1 1.1882 + shift 1.1883 +elif [[ -n $1 ]]; then 1.1884 + if [[ ! -r $1 ]]; then 1.1885 + print -u2 "$1: no such file or not readable" 1.1886 + usage 1.1887 + fi 1.1888 + cat $1 > $FLIST 1.1889 + flist_mode="file" 1.1890 + flist_file=$1 1.1891 + flist_done=1 1.1892 + shift 1.1893 +else 1.1894 + flist_mode="auto" 1.1895 +fi 1.1896 + 1.1897 +# 1.1898 +# Before we go on to further consider -l and -w, work out which SCM we think 1.1899 +# is in use. 1.1900 +# 1.1901 +if [[ -z $SCM_MODE ]]; then 1.1902 + SCM_MODE=`detect_scm $FLIST` 1.1903 +fi 1.1904 +if [[ $SCM_MODE == "unknown" ]]; then 1.1905 + print -u2 "Unable to determine SCM type currently in use." 1.1906 + print -u2 "For mercurial: webrev runs 'hg root'." 1.1907 + exit 1 1.1908 +fi 1.1909 + 1.1910 +print -u2 " SCM detected: $SCM_MODE" 1.1911 + 1.1912 + 1.1913 +if [[ $SCM_MODE == "mercurial" ]]; then 1.1914 + # 1.1915 + # determine Workspace and parent workspace paths 1.1916 + # 1.1917 + CWS=`hg root | $FILTER` 1.1918 + if [[ -n $pflag && -z "$PWS" ]]; then 1.1919 + OUTPWS=$codemgr_parent 1.1920 + # Let's try to expand it if it's an alias defined in [paths] 1.1921 + tmp=`hg path $OUTPWS 2>/dev/null | $FILTER` 1.1922 + if [[ -n $tmp ]]; then 1.1923 + OUTPWS="$tmp" 1.1924 + fi 1.1925 + if [[ -n $rflag ]]; then 1.1926 + if expr "$codemgr_parent" : 'ssh://.*' >/dev/null; then 1.1927 + PWS=$codemgr_parent 1.1928 + else 1.1929 + PWS=`hg -R "$codemgr_parent" root 2>/dev/null | $FILTER` 1.1930 + fi 1.1931 + fi 1.1932 + fi 1.1933 + # 1.1934 + # OUTPWS is the parent repository to use when using 'hg outgoing' 1.1935 + # 1.1936 + if [[ -z $Nflag ]]; then 1.1937 + if [[ -n $forestflag ]]; then 1.1938 + # 1.1939 + # for forest we have to rely on properly set default and 1.1940 + # default-push because they can be different from the top one. 1.1941 + # unless of course it was explicitly specified with -p 1.1942 + if [[ -z $pflag ]]; then 1.1943 + OUTPWS= 1.1944 + fi 1.1945 + else 1.1946 + # 1.1947 + # Unfortunately mercurial is bugged and doesn't handle 1.1948 + # aliases correctly in 'hg path default' 1.1949 + # So let's do it ourselves. Sigh... 1.1950 + if [[ -z "$OUTPWS" ]]; then 1.1951 + OUTPWS=`grep default-push $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER` 1.1952 + fi 1.1953 + # Still empty, means no default-push 1.1954 + if [[ -z "$OUTPWS" ]]; then 1.1955 + OUTPWS=`grep 'default =' $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER` 1.1956 + fi 1.1957 + # Let's try to expand it if it's an alias defined in [paths] 1.1958 + tmp=`hg path $OUTPWS 2>/dev/null | $FILTER` 1.1959 + if [[ -n $tmp ]]; then 1.1960 + OUTPWS="$tmp" 1.1961 + fi 1.1962 + fi 1.1963 + fi 1.1964 + # 1.1965 + # OUTPWS may contain username:password, let's make sure we remove the 1.1966 + # sensitive information before we print out anything in the HTML 1.1967 + # 1.1968 + OUTPWS2=$OUTPWS 1.1969 + if [[ -n $OUTPWS ]]; then 1.1970 + if [[ `expr "$OUTPWS" : '.*://[^/]*@.*'` -gt 0 ]]; then 1.1971 + # Remove everything between '://' and '@' 1.1972 + OUTPWS2=`echo $OUTPWS | sed -e 's/\(.*:\/\/\).*@\(.*\)/\1\2/'` 1.1973 + fi 1.1974 + fi 1.1975 + 1.1976 + if [[ -z $HG_BRANCH ]]; then 1.1977 + HG_BRANCH=`hg branch` 1.1978 + if [ "$HG_BRANCH" == "default" ]; then 1.1979 + # 1.1980 + # 'default' means no particular branch, so let's cancel that 1.1981 + # 1.1982 + HG_BRANCH= 1.1983 + fi 1.1984 + fi 1.1985 + 1.1986 + if [[ -z $forestflag ]]; then 1.1987 + if [[ -z $Nflag ]]; then 1.1988 + # 1.1989 + # If no "-N", always do "hg outgoing" against parent 1.1990 + # repository to determine list of outgoing revisions. 1.1991 + # 1.1992 + ALL_CREV=`hg outgoing -q --template '{rev}\n' $OUTPWS | sort -n` 1.1993 + if [[ -n $ALL_CREV ]]; then 1.1994 + FIRST_CREV=`echo "$ALL_CREV" | head -1` 1.1995 + # 1.1996 + # If no "-r", choose revision to compare against by 1.1997 + # finding the latest revision not in the outgoing list. 1.1998 + # 1.1999 + if [[ -z $rflag ]]; then 1.2000 + OUTREV=`find_outrev "$FIRST_CREV"` 1.2001 + if [[ -n $OUTREV ]]; then 1.2002 + HG_LIST_FROM_COMMIT=1 1.2003 + fi 1.2004 + fi 1.2005 + fi 1.2006 + elif [[ -n $rflag ]]; then 1.2007 + # 1.2008 + # If skipping "hg outgoing" but still comparing against a 1.2009 + # specific revision (not the tip), set revision for comment 1.2010 + # accumulation. 1.2011 + # 1.2012 + FIRST_CREV=`hg log --rev $PARENT_REV --template '{rev}'` 1.2013 + FIRST_CREV=`expr $FIRST_CREV + 1` 1.2014 + fi 1.2015 + fi 1.2016 + #Let's check if a merge is needed, if so, issue a warning 1.2017 + PREV=`hg parent | grep '^tag:.*tip$'` 1.2018 + if [[ -z $PREV ]]; then 1.2019 + print "WARNING: parent rev is not tip. Maybe an update or merge is needed" 1.2020 + fi 1.2021 +fi 1.2022 + 1.2023 +if [[ $flist_mode == "stdin" ]]; then 1.2024 + print -u2 " File list from: standard input" 1.2025 +elif [[ $flist_mode == "file" ]]; then 1.2026 + print -u2 " File list from: $flist_file" 1.2027 +fi 1.2028 + 1.2029 +if [[ $# -gt 0 ]]; then 1.2030 + print -u2 "WARNING: unused arguments: $*" 1.2031 +fi 1.2032 + 1.2033 +if [[ $SCM_MODE == "mercurial" ]]; then 1.2034 + if [[ -z $flist_done ]]; then 1.2035 + flist_from_mercurial $PWS 1.2036 + fi 1.2037 +fi 1.2038 + 1.2039 +# 1.2040 +# If the user didn't specify a -i option, check to see if there is a 1.2041 +# webrev-info file in the workspace directory. 1.2042 +# 1.2043 +if [[ -z $iflag && -r "$CWS/webrev-info" ]]; then 1.2044 + iflag=1 1.2045 + INCLUDE_FILE="$CWS/webrev-info" 1.2046 +fi 1.2047 + 1.2048 +if [[ -n $iflag ]]; then 1.2049 + if [[ ! -r $INCLUDE_FILE ]]; then 1.2050 + print -u2 "include file '$INCLUDE_FILE' does not exist or is" \ 1.2051 + "not readable." 1.2052 + exit 1 1.2053 + else 1.2054 + # 1.2055 + # $INCLUDE_FILE may be a relative path, and the script alters 1.2056 + # PWD, so we just stash a copy in /tmp. 1.2057 + # 1.2058 + cp $INCLUDE_FILE /tmp/$$.include 1.2059 + fi 1.2060 +fi 1.2061 + 1.2062 +# 1.2063 +# Output directory. 1.2064 +# 1.2065 +if [[ -z $WDIR ]]; then 1.2066 + WDIR=$CWS/webrev 1.2067 +else 1.2068 + # If the output directory doesn't end with '/webrev' or '/webrev/' 1.2069 + # then add '/webrev'. This is for backward compatibility 1.2070 + if ! expr $WDIR : '.*/webrev/\?$' >/dev/null 1.2071 + then 1.2072 + WDIR=$WDIR/webrev 1.2073 + fi 1.2074 +fi 1.2075 +# WDIR=${WDIR:-$CWS/webrev} 1.2076 + 1.2077 +# 1.2078 +# Name of the webrev, derived from the workspace name; in the 1.2079 +# future this could potentially be an option. 1.2080 +# 1.2081 +# Let's keep what's after the last '/' 1.2082 +WNAME=${CWS##*/} 1.2083 + 1.2084 +# 1.2085 +# If WDIR doesn't start with '/' or 'x:' prepend the current dir 1.2086 +# 1.2087 +if [ ${WDIR%%/*} ]; then 1.2088 + if [[ -n $ISWIN ]]; then 1.2089 + if [ ${WDIR%%[A-Za-z]:*} ]; then 1.2090 + WDIR=$PWD/$WDIR 1.2091 + fi 1.2092 + else 1.2093 + WDIR=$PWD/$WDIR 1.2094 + fi 1.2095 +fi 1.2096 + 1.2097 +if [[ ! -d $WDIR ]]; then 1.2098 + mkdir -p $WDIR 1.2099 + [[ $? != 0 ]] && exit 1 1.2100 +fi 1.2101 + 1.2102 +# 1.2103 +# Summarize what we're going to do. 1.2104 +# 1.2105 +print " Workspace: $CWS" 1.2106 +if [[ -n $parent_webrev ]]; then 1.2107 + print "Compare against: webrev at $parent_webrev" 1.2108 +elif [[ -n $OUTPWS2 ]]; then 1.2109 + print "Compare against: $OUTPWS2" 1.2110 +fi 1.2111 +if [[ -n $HG_BRANCH ]]; then 1.2112 + print " Branch: $HG_BRANCH" 1.2113 +fi 1.2114 +if [[ -n $rflag ]]; then 1.2115 + print "Compare against version: $PARENT_REV" 1.2116 +fi 1.2117 +[[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE" 1.2118 +print " Output to: $WDIR" 1.2119 + 1.2120 +# 1.2121 +# Save the file list in the webrev dir 1.2122 +# 1.2123 +[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list 1.2124 + 1.2125 +# 1.2126 +# Bug IDs will be replaced by a URL. Order of precedence 1.2127 +# is: default location, $WEBREV_BUGURL 1.2128 +# 1.2129 +BUGURL='https://bugs.openjdk.java.net/browse/' 1.2130 +[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL" 1.2131 +IDPREFIX='JDK-' 1.2132 + 1.2133 + 1.2134 +rm -f $WDIR/$WNAME.patch 1.2135 +rm -f $WDIR/$WNAME.changeset 1.2136 +rm -f $WDIR/$WNAME.ps 1.2137 +rm -f $WDIR/$WNAME.pdf 1.2138 + 1.2139 +touch $WDIR/$WNAME.patch 1.2140 + 1.2141 +print " Output Files:" 1.2142 + 1.2143 +# 1.2144 +# Clean up the file list: Remove comments, blank lines and env variables. 1.2145 +# 1.2146 +sed -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean 1.2147 +FLIST=/tmp/$$.flist.clean 1.2148 + 1.2149 +# 1.2150 +# Clean up residual raw files 1.2151 +# 1.2152 +if [ -d $WDIR/raw_files ]; then 1.2153 + rm -rf $WDIR/raw_files 2>/dev/null 1.2154 +fi 1.2155 + 1.2156 +# 1.2157 +# Should we ignore changes in white spaces when generating diffs? 1.2158 +# 1.2159 +if [[ -n $bflag ]]; then 1.2160 + DIFFOPTS="-t" 1.2161 +else 1.2162 + DIFFOPTS="-bt" 1.2163 +fi 1.2164 +# 1.2165 +# First pass through the files: generate the per-file webrev HTML-files. 1.2166 +# 1.2167 +while read LINE 1.2168 +do 1.2169 + set - $LINE 1.2170 + P=$1 1.2171 + 1.2172 + if [[ $1 == "Revision:" ]]; then 1.2173 + OUTREV=$2 1.2174 + continue 1.2175 + fi 1.2176 + # 1.2177 + # Normally, each line in the file list is just a pathname of a 1.2178 + # file that has been modified or created in the child. A file 1.2179 + # that is renamed in the child workspace has two names on the 1.2180 + # line: new name followed by the old name. 1.2181 + # 1.2182 + oldname="" 1.2183 + oldpath="" 1.2184 + rename= 1.2185 + if [[ $# -eq 2 ]]; then 1.2186 + PP=$2 # old filename 1.2187 + oldname=" (was $PP)" 1.2188 + oldpath="$PP" 1.2189 + rename=1 1.2190 + PDIR=${PP%/*} 1.2191 + if [[ $PDIR == $PP ]]; then 1.2192 + PDIR="." # File at root of workspace 1.2193 + fi 1.2194 + 1.2195 + PF=${PP##*/} 1.2196 + 1.2197 + DIR=${P%/*} 1.2198 + if [[ $DIR == $P ]]; then 1.2199 + DIR="." # File at root of workspace 1.2200 + fi 1.2201 + 1.2202 + F=${P##*/} 1.2203 + else 1.2204 + DIR=${P%/*} 1.2205 + if [[ "$DIR" == "$P" ]]; then 1.2206 + DIR="." # File at root of workspace 1.2207 + fi 1.2208 + 1.2209 + F=${P##*/} 1.2210 + 1.2211 + PP=$P 1.2212 + PDIR=$DIR 1.2213 + PF=$F 1.2214 + fi 1.2215 + 1.2216 + # Make the webrev directory if necessary as it may have been 1.2217 + # removed because it was empty 1.2218 + if [ ! -d $CWS/$DIR ]; then 1.2219 + mkdir -p $CWS/$DIR 1.2220 + fi 1.2221 + 1.2222 + COMM=`getcomments html $P $PP` 1.2223 + 1.2224 + print "\t$P$oldname\n\t\t\c" 1.2225 + 1.2226 + # Make the webrev mirror directory if necessary 1.2227 + mkdir -p $WDIR/$DIR 1.2228 + 1.2229 + # cd to the directory so the names are short 1.2230 + cd $CWS/$DIR 1.2231 + 1.2232 + # 1.2233 + # We stash old and new files into parallel directories in /tmp 1.2234 + # and do our diffs there. This makes it possible to generate 1.2235 + # clean looking diffs which don't have absolute paths present. 1.2236 + # 1.2237 + olddir=$WDIR/raw_files/old 1.2238 + newdir=$WDIR/raw_files/new 1.2239 + mkdir -p $olddir 1.2240 + mkdir -p $newdir 1.2241 + mkdir -p $olddir/$PDIR 1.2242 + mkdir -p $newdir/$DIR 1.2243 + 1.2244 + build_old_new $olddir $newdir $DIR $F 1.2245 + 1.2246 + if [[ ! -f $F && ! -f $olddir/$DIR/$F ]]; then 1.2247 + print "*** Error: file not in parent or child" 1.2248 + continue 1.2249 + fi 1.2250 + 1.2251 + cd $WDIR/raw_files 1.2252 + ofile=old/$PDIR/$PF 1.2253 + nfile=new/$DIR/$F 1.2254 + 1.2255 + mv_but_nodiff= 1.2256 + cmp $ofile $nfile > /dev/null 2>&1 1.2257 + if [[ $? == 0 && $rename == 1 ]]; then 1.2258 + mv_but_nodiff=1 1.2259 + fi 1.2260 + 1.2261 + # 1.2262 + # Cleaning up 1.2263 + # 1.2264 + rm -f $WDIR/$DIR/$F.cdiff.html 1.2265 + rm -f $WDIR/$DIR/$F.udiff.html 1.2266 + rm -f $WDIR/$DIR/$F.wdiff.html 1.2267 + rm -f $WDIR/$DIR/$F.sdiff.html 1.2268 + rm -f $WDIR/$DIR/$F-.html 1.2269 + rm -f $WDIR/$DIR/$F.html 1.2270 + 1.2271 + its_a_jar= 1.2272 + if expr $F : '.*\.jar' \| $F : '.*\.zip' >/dev/null; then 1.2273 + its_a_jar=1 1.2274 + # It's a JAR or ZIP file, let's do it differently 1.2275 + if [[ -z $JAR ]]; then 1.2276 + print "No access to jar, so can't produce diffs for jar or zip files" 1.2277 + else 1.2278 + if [ -f $ofile ]; then 1.2279 + $JAR -tvf $ofile >"$ofile".lst 1.2280 + fi 1.2281 + if [ -f $nfile ]; then 1.2282 + $JAR -tvf $nfile >"$nfile".lst 1.2283 + fi 1.2284 + 1.2285 + if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then 1.2286 + 1.2287 + ${CDIFFCMD:-diff -bt -C 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.cdiff 1.2288 + diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \ 1.2289 + > $WDIR/$DIR/$F.cdiff.html 1.2290 + print " cdiffs\c" 1.2291 + 1.2292 + ${UDIFFCMD:-diff -bt -U 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.udiff 1.2293 + diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \ 1.2294 + > $WDIR/$DIR/$F.udiff.html 1.2295 + 1.2296 + print " udiffs\c" 1.2297 + 1.2298 + if [[ -x $WDIFF ]]; then 1.2299 + $WDIFF -c "$COMM" \ 1.2300 + -t "$WNAME Wdiff $DIR/$F" $ofile.lst $nfile.lst > \ 1.2301 + $WDIR/$DIR/$F.wdiff.html 2>/dev/null 1.2302 + if [[ $? -eq 0 ]]; then 1.2303 + print " wdiffs\c" 1.2304 + else 1.2305 + print " wdiffs[fail]\c" 1.2306 + fi 1.2307 + fi 1.2308 + 1.2309 + sdiff_to_html $ofile $nfile $F $DIR "$COMM" \ 1.2310 + > $WDIR/$DIR/$F.sdiff.html 1.2311 + print " sdiffs\c" 1.2312 + 1.2313 + print " frames\c" 1.2314 + 1.2315 + rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff 1.2316 + 1.2317 + difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count 1.2318 + 1.2319 + elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then 1.2320 + # renamed file: may also have differences 1.2321 + difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count 1.2322 + elif [[ -f $nfile ]]; then 1.2323 + # new file: count added lines 1.2324 + difflines /dev/null $nfile.lst > $WDIR/$DIR/$F.count 1.2325 + elif [[ -f $ofile ]]; then 1.2326 + # old file: count deleted lines 1.2327 + difflines $ofile.lst /dev/null > $WDIR/$DIR/$F.count 1.2328 + fi 1.2329 + fi 1.2330 + else 1.2331 + 1.2332 + # 1.2333 + # If we have old and new versions of the file then run the 1.2334 + # appropriate diffs. This is complicated by a couple of factors: 1.2335 + # 1.2336 + # - renames must be handled specially: we emit a 'remove' 1.2337 + # diff and an 'add' diff 1.2338 + # - new files and deleted files must be handled specially 1.2339 + # - Solaris patch(1m) can't cope with file creation 1.2340 + # (and hence renames) as of this writing. 1.2341 + # - To make matters worse, gnu patch doesn't interpret the 1.2342 + # output of Solaris diff properly when it comes to 1.2343 + # adds and deletes. We need to do some "cleansing" 1.2344 + # transformations: 1.2345 + # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@ 1.2346 + # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@ 1.2347 + # 1.2348 + cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'" 1.2349 + cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'" 1.2350 + 1.2351 + if [[ ! "$HG_LIST_FROM_COMMIT" -eq 1 || ! $flist_mode == "auto" ]]; 1.2352 + then 1.2353 + # Only need to generate a patch file here if there are no commits in outgoing 1.2354 + # or if we've specified a file list 1.2355 + rm -f $WDIR/$DIR/$F.patch 1.2356 + if [[ -z $rename ]]; then 1.2357 + if [ ! -f $ofile ]; then 1.2358 + diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ 1.2359 + > $WDIR/$DIR/$F.patch 1.2360 + elif [ ! -f $nfile ]; then 1.2361 + diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ 1.2362 + > $WDIR/$DIR/$F.patch 1.2363 + else 1.2364 + diff -u $ofile $nfile > $WDIR/$DIR/$F.patch 1.2365 + fi 1.2366 + else 1.2367 + diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ 1.2368 + > $WDIR/$DIR/$F.patch 1.2369 + 1.2370 + diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ 1.2371 + >> $WDIR/$DIR/$F.patch 1.2372 + 1.2373 + fi 1.2374 + 1.2375 + 1.2376 + # 1.2377 + # Tack the patch we just made onto the accumulated patch for the 1.2378 + # whole wad. 1.2379 + # 1.2380 + cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch 1.2381 + fi 1.2382 + 1.2383 + print " patch\c" 1.2384 + 1.2385 + if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then 1.2386 + 1.2387 + ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff 1.2388 + diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \ 1.2389 + > $WDIR/$DIR/$F.cdiff.html 1.2390 + print " cdiffs\c" 1.2391 + 1.2392 + ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff 1.2393 + diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \ 1.2394 + > $WDIR/$DIR/$F.udiff.html 1.2395 + 1.2396 + print " udiffs\c" 1.2397 + 1.2398 + if [[ -x $WDIFF ]]; then 1.2399 + $WDIFF -c "$COMM" \ 1.2400 + -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \ 1.2401 + $WDIR/$DIR/$F.wdiff.html 2>/dev/null 1.2402 + if [[ $? -eq 0 ]]; then 1.2403 + print " wdiffs\c" 1.2404 + else 1.2405 + print " wdiffs[fail]\c" 1.2406 + fi 1.2407 + fi 1.2408 + 1.2409 + sdiff_to_html $ofile $nfile $F $DIR "$COMM" \ 1.2410 + > $WDIR/$DIR/$F.sdiff.html 1.2411 + print " sdiffs\c" 1.2412 + 1.2413 + print " frames\c" 1.2414 + 1.2415 + rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff 1.2416 + 1.2417 + difflines $ofile $nfile > $WDIR/$DIR/$F.count 1.2418 + 1.2419 + elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then 1.2420 + # renamed file: may also have differences 1.2421 + difflines $ofile $nfile > $WDIR/$DIR/$F.count 1.2422 + elif [[ -f $nfile ]]; then 1.2423 + # new file: count added lines 1.2424 + difflines /dev/null $nfile > $WDIR/$DIR/$F.count 1.2425 + elif [[ -f $ofile ]]; then 1.2426 + # old file: count deleted lines 1.2427 + difflines $ofile /dev/null > $WDIR/$DIR/$F.count 1.2428 + fi 1.2429 + fi 1.2430 + # 1.2431 + # Now we generate the postscript for this file. We generate diffs 1.2432 + # only in the event that there is delta, or the file is new (it seems 1.2433 + # tree-killing to print out the contents of deleted files). 1.2434 + # 1.2435 + if [[ -f $nfile ]]; then 1.2436 + ocr=$ofile 1.2437 + [[ ! -f $ofile ]] && ocr=/dev/null 1.2438 + 1.2439 + if [[ -z $mv_but_nodiff ]]; then 1.2440 + textcomm=`getcomments text $P $PP` 1.2441 + if [[ -x $CODEREVIEW ]]; then 1.2442 + $CODEREVIEW -y "$textcomm" \ 1.2443 + -e $ocr $nfile \ 1.2444 + > /tmp/$$.psfile 2>/dev/null && 1.2445 + cat /tmp/$$.psfile >> $WDIR/$WNAME.ps 1.2446 + if [[ $? -eq 0 ]]; then 1.2447 + print " ps\c" 1.2448 + else 1.2449 + print " ps[fail]\c" 1.2450 + fi 1.2451 + fi 1.2452 + fi 1.2453 + fi 1.2454 + 1.2455 + if [[ -f $ofile && -z $mv_but_nodiff ]]; then 1.2456 + if [[ -n $its_a_jar ]]; then 1.2457 + source_to_html Old $P < $ofile.lst > $WDIR/$DIR/$F-.html 1.2458 + else 1.2459 + source_to_html Old $P < $ofile > $WDIR/$DIR/$F-.html 1.2460 + fi 1.2461 + print " old\c" 1.2462 + fi 1.2463 + 1.2464 + if [[ -f $nfile ]]; then 1.2465 + if [[ -n $its_a_jar ]]; then 1.2466 + source_to_html New $P < $nfile.lst > $WDIR/$DIR/$F.html 1.2467 + else 1.2468 + source_to_html New $P < $nfile > $WDIR/$DIR/$F.html 1.2469 + fi 1.2470 + print " new\c" 1.2471 + fi 1.2472 + 1.2473 + print 1.2474 +done < $FLIST 1.2475 + 1.2476 +# Create the new style mercurial patch here using hg export -r [all-revs] -g -o $CHANGESETPATH 1.2477 +if [[ $SCM_MODE == "mercurial" ]]; then 1.2478 + if [[ "$HG_LIST_FROM_COMMIT" -eq 1 && $flist_mode == "auto" ]]; then 1.2479 + EXPORTCHANGESET="$WNAME.changeset" 1.2480 + CHANGESETPATH=${WDIR}/${EXPORTCHANGESET} 1.2481 + rm -f $CHANGESETPATH 1.2482 + touch $CHANGESETPATH 1.2483 + if [[ -n $ALL_CREV ]]; then 1.2484 + rev_opt= 1.2485 + for rev in $ALL_CREV; do 1.2486 + rev_opt="$rev_opt --rev $rev" 1.2487 + done 1.2488 + elif [[ -n $FIRST_CREV ]]; then 1.2489 + rev_opt="--rev $FIRST_CREV" 1.2490 + fi 1.2491 + 1.2492 + if [[ -n $rev_opt ]]; then 1.2493 + (cd $CWS;hg export -g $rev_opt -o $CHANGESETPATH) 1.2494 + echo "Created changeset: $CHANGESETPATH" 1>&2 1.2495 + # Use it in place of the jdk.patch created above 1.2496 + rm -f $WDIR/$WNAME.patch 1.2497 + fi 1.2498 + set +x 1.2499 + fi 1.2500 +fi 1.2501 + 1.2502 +frame_nav_js > $WDIR/ancnav.js 1.2503 +frame_navigation > $WDIR/ancnav.html 1.2504 + 1.2505 +if [[ -f $WDIR/$WNAME.ps && -x $CODEREVIEW && -x $PS2PDF ]]; then 1.2506 + print " Generating PDF: \c" 1.2507 + fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf 1.2508 + print "Done." 1.2509 +fi 1.2510 + 1.2511 +# Now build the index.html file that contains 1.2512 +# links to the source files and their diffs. 1.2513 + 1.2514 +cd $CWS 1.2515 + 1.2516 +# Save total changed lines for Code Inspection. 1.2517 +print "$TOTL" > $WDIR/TotalChangedLines 1.2518 + 1.2519 +print " index.html: \c" 1.2520 +INDEXFILE=$WDIR/index.html 1.2521 +exec 3<&1 # duplicate stdout to FD3. 1.2522 +exec 1<&- # Close stdout. 1.2523 +exec > $INDEXFILE # Open stdout to index file. 1.2524 + 1.2525 +print "$HTML<head>" 1.2526 +print "<meta name=\"scm\" content=\"$SCM_MODE\" />" 1.2527 +print "$STDHEAD" 1.2528 +print "<title>$WNAME</title>" 1.2529 +print "</head>" 1.2530 +print "<body id=\"SUNWwebrev\">" 1.2531 +print "<div class=\"summary\">" 1.2532 +print "<h2>Code Review for $WNAME</h2>" 1.2533 + 1.2534 +print "<table>" 1.2535 + 1.2536 +if [[ -z $uflag ]]; then 1.2537 + if [[ $SCM_MODE == "mercurial" ]]; then 1.2538 + # 1.2539 + # Let's try to extract the user name from the .hgrc file 1.2540 + # 1.2541 + username=`grep '^username' $HOME/.hgrc | sed 's/^username[ ]*=[ ]*\(.*\)/\1/'` 1.2542 + fi 1.2543 + 1.2544 + if [[ -z $username ]]; then 1.2545 + # 1.2546 + # Figure out the username and gcos name. To maintain compatibility 1.2547 + # with passwd(4), we must support '&' substitutions. 1.2548 + # 1.2549 + username=`id | cut -d '(' -f 2 | cut -d ')' -f 1` 1.2550 + if [[ -x $GETENT ]]; then 1.2551 + realname=`$GETENT passwd $username | cut -d':' -f 5 | cut -d ',' -f 1` 1.2552 + fi 1.2553 + userupper=`print "$username" | sed 's/\<./\u&/g'` 1.2554 + realname=`print $realname | sed s/\&/$userupper/` 1.2555 + fi 1.2556 +fi 1.2557 + 1.2558 +date="on `date`" 1.2559 + 1.2560 +if [[ -n "$username" && -n "$realname" ]]; then 1.2561 + print "<tr><th>Prepared by:</th>" 1.2562 + print "<td>$realname ($username) $date</td></tr>" 1.2563 +elif [[ -n "$username" ]]; then 1.2564 + print "<tr><th>Prepared by:</th><td>$username $date</td></tr>" 1.2565 +fi 1.2566 + 1.2567 +print "<tr><th>Workspace:</th><td>$CWS</td></tr>" 1.2568 +if [[ -n $parent_webrev ]]; then 1.2569 + print "<tr><th>Compare against:</th><td>" 1.2570 + print "webrev at $parent_webrev" 1.2571 +else 1.2572 + if [[ -n $OUTPWS2 ]]; then 1.2573 + print "<tr><th>Compare against:</th><td>" 1.2574 + print "$OUTPWS2" 1.2575 + fi 1.2576 +fi 1.2577 +print "</td></tr>" 1.2578 +if [[ -n $rflag ]]; then 1.2579 + print "<tr><th>Compare against version:</th><td>$PARENT_REV</td></tr>" 1.2580 +elif [[ -n $OUTREV ]]; then 1.2581 + if [[ -z $forestflag ]]; then 1.2582 + print "<tr><th>Compare against version:</th><td>$OUTREV</td></tr>" 1.2583 + fi 1.2584 +fi 1.2585 +if [[ -n $HG_BRANCH ]]; then 1.2586 + print "<tr><th>Branch:</th><td>$HG_BRANCH</td></tr>" 1.2587 +fi 1.2588 + 1.2589 +print "<tr><th>Summary of changes:</th><td>" 1.2590 +printCI $TOTL $TINS $TDEL $TMOD $TUNC 1.2591 +print "</td></tr>" 1.2592 + 1.2593 +if [[ -f $WDIR/$WNAME.patch ]]; then 1.2594 + print "<tr><th>Patch of changes:</th><td>" 1.2595 + print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>" 1.2596 +elif [[ -f $CHANGESETPATH ]]; then 1.2597 + print "<tr><th>Changeset:</th><td>" 1.2598 + print "<a href=\"$EXPORTCHANGESET\">$EXPORTCHANGESET</a></td></tr>" 1.2599 +fi 1.2600 + 1.2601 +if [[ -f $WDIR/$WNAME.pdf ]]; then 1.2602 + print "<tr><th>Printable review:</th><td>" 1.2603 + print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>" 1.2604 +fi 1.2605 + 1.2606 +if [[ -n "$iflag" ]]; then 1.2607 + print "<tr><th>Author comments:</th><td><div>" 1.2608 + cat /tmp/$$.include 1.2609 + print "</div></td></tr>" 1.2610 +fi 1.2611 +# Add links to referenced CRs, if any 1.2612 +# URL has a <title> like: 1.2613 +# <title>[#JDK-8024688] b106-lambda: j.u.Map.merge doesn't work as specified if contains key:null pair - Java Bug System</title> 1.2614 +# we format this to: 1.2615 +# JDK-8024688: b106-lambda: j.u.Map.merge doesn't work as specified if contains key:null pair 1.2616 +if [[ -n $CRID ]]; then 1.2617 + for id in $CRID 1.2618 + do 1.2619 + #add "JDK-" to raw bug id for openjdk.java.net links. 1.2620 + id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'` 1.2621 + 1.2622 + print "<tr><th>Bug id:</th><td>" 1.2623 + url="${BUGURL}${id}" 1.2624 + 1.2625 + if [[ -n $WGET ]]; then 1.2626 + msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '<title>' | sed 's/<title>\[#\(.*\)\] \(.*\) - Java Bug System<\/title>/\1 : \2/' | html_dequote | html_quote` 1.2627 + fi 1.2628 + if [[ -z $msg ]]; then 1.2629 + msg="${id}" 1.2630 + fi 1.2631 + 1.2632 + print "<a href=\"$url\">$msg</a>" 1.2633 + 1.2634 + print "</td></tr>" 1.2635 + done 1.2636 +fi 1.2637 +print "<tr><th>Legend:</th><td>" 1.2638 +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>" 1.2639 +print "</table>" 1.2640 +print "</div>" 1.2641 + 1.2642 +# 1.2643 +# Second pass through the files: generate the rest of the index file 1.2644 +# 1.2645 +while read LINE 1.2646 +do 1.2647 + set - $LINE 1.2648 + if [[ $1 == "Revision:" ]]; then 1.2649 + FIRST_CREV=`expr $3 + 1` 1.2650 + continue 1.2651 + fi 1.2652 + P=$1 1.2653 + 1.2654 + if [[ $# == 2 ]]; then 1.2655 + PP=$2 1.2656 + oldname=" <i>(was $PP)</i>" 1.2657 + 1.2658 + else 1.2659 + PP=$P 1.2660 + oldname="" 1.2661 + fi 1.2662 + 1.2663 + DIR=${P%/*} 1.2664 + if [[ $DIR == $P ]]; then 1.2665 + DIR="." # File at root of workspace 1.2666 + fi 1.2667 + 1.2668 + # Avoid processing the same file twice. 1.2669 + # It's possible for renamed files to 1.2670 + # appear twice in the file list 1.2671 + 1.2672 + F=$WDIR/$P 1.2673 + 1.2674 + print "<p><code>" 1.2675 + 1.2676 + # If there's a diffs file, make diffs links 1.2677 + 1.2678 + NODIFFS= 1.2679 + if [[ -f $F.cdiff.html ]]; then 1.2680 + print "<a href=\"$P.cdiff.html\">Cdiffs</a>" 1.2681 + print "<a href=\"$P.udiff.html\">Udiffs</a>" 1.2682 + 1.2683 + if [[ -f $F.wdiff.html && -x $WDIFF ]]; then 1.2684 + print "<a href=\"$P.wdiff.html\">Wdiffs</a>" 1.2685 + fi 1.2686 + 1.2687 + print "<a href=\"$P.sdiff.html\">Sdiffs</a>" 1.2688 + 1.2689 + print "<a href=\"$P.frames.html\">Frames</a>" 1.2690 + else 1.2691 + NODIFFS=1 1.2692 + print " ------ ------ ------" 1.2693 + 1.2694 + if [[ -x $WDIFF ]]; then 1.2695 + print " ------" 1.2696 + fi 1.2697 + 1.2698 + print " ------" 1.2699 + fi 1.2700 + 1.2701 + # If there's an old file, make the link 1.2702 + 1.2703 + NOOLD= 1.2704 + if [[ -f $F-.html ]]; then 1.2705 + print "<a href=\"$P-.html\">Old</a>" 1.2706 + else 1.2707 + NOOLD=1 1.2708 + print " ---" 1.2709 + fi 1.2710 + 1.2711 + # If there's an new file, make the link 1.2712 + 1.2713 + NONEW= 1.2714 + if [[ -f $F.html ]]; then 1.2715 + print "<a href=\"$P.html\">New</a>" 1.2716 + else 1.2717 + NONEW=1 1.2718 + print " ---" 1.2719 + fi 1.2720 + 1.2721 + if [[ -f $F.patch ]]; then 1.2722 + print "<a href=\"$P.patch\">Patch</a>" 1.2723 + else 1.2724 + print " -----" 1.2725 + fi 1.2726 + 1.2727 + if [[ -f $WDIR/raw_files/new/$P ]]; then 1.2728 + print "<a href=\"raw_files/new/$P\">Raw</a>" 1.2729 + else 1.2730 + print " ---" 1.2731 + fi 1.2732 + print "</code>" 1.2733 + if [[ -n $NODIFFS && -z $oldname ]]; then 1.2734 + if [[ -n $NOOLD ]]; then 1.2735 + print "<font color=green><b>$P</b></font>" 1.2736 + elif [[ -n $NONEW ]]; then 1.2737 + print "<font color=red><b>$P</b></font>" 1.2738 + fi 1.2739 + else 1.2740 + print "<b>$P</b> $oldname" 1.2741 + fi 1.2742 + 1.2743 + print "</p><blockquote>\c" 1.2744 + # Insert delta comments if any 1.2745 + comments=`getcomments html $P $PP` 1.2746 + if [ -n "$comments" ]; then 1.2747 + print "<pre>$comments</pre>" 1.2748 + fi 1.2749 + 1.2750 + # Add additional comments comment 1.2751 + 1.2752 + print "<!-- Add comments to explain changes in $P here -->" 1.2753 + 1.2754 + # Add count of changes. 1.2755 + 1.2756 + if [[ -f $F.count ]]; then 1.2757 + cat $F.count 1.2758 + rm $F.count 1.2759 + fi 1.2760 + print "</blockquote>" 1.2761 +done < $FLIST 1.2762 + 1.2763 +print 1.2764 +print 1.2765 +print "<hr />" 1.2766 +print "<p style=\"font-size: small\">" 1.2767 +print "This code review page was prepared using <b>$0</b>" 1.2768 +print "(vers $WEBREV_UPDATED)." 1.2769 +print "</body>" 1.2770 +print "</html>" 1.2771 + 1.2772 +if [[ -n $ZIP ]]; then 1.2773 + # Let's generate a zip file for convenience 1.2774 + cd $WDIR/.. 1.2775 + if [ -f webrev.zip ]; then 1.2776 + rm webrev.zip 1.2777 + fi 1.2778 + $ZIP -r webrev webrev >/dev/null 2>&1 1.2779 +fi 1.2780 + 1.2781 +exec 1<&- # Close FD 1. 1.2782 +exec 1<&3 # dup FD 3 to restore stdout. 1.2783 +exec 3<&- # close FD 3. 1.2784 + 1.2785 +print "Done." 1.2786 +print "Output to: $WDIR"