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