make/scripts/webrev.ksh

Thu, 31 Aug 2017 15:40:18 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:40:18 +0800
changeset 1133
50aaf272884f
parent 907
c1029b02ca87
parent 0
75a576e87639
permissions
-rw-r--r--

merge

aoqi@0 1 #!/bin/ksh -p
aoqi@0 2 #
aoqi@0 3 # CDDL HEADER START
aoqi@0 4 #
aoqi@0 5 # The contents of this file are subject to the terms of the
aoqi@0 6 # Common Development and Distribution License (the "License").
aoqi@0 7 # You may not use this file except in compliance with the License.
aoqi@0 8 #
aoqi@0 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
aoqi@0 10 # or http://www.opensolaris.org/os/licensing.
aoqi@0 11 # See the License for the specific language governing permissions
aoqi@0 12 # and limitations under the License.
aoqi@0 13 #
aoqi@0 14 # When distributing Covered Code, include this CDDL HEADER in each
aoqi@0 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
aoqi@0 16 # If applicable, add the following below this CDDL HEADER, with the
aoqi@0 17 # fields enclosed by brackets "[]" replaced with your own identifying
aoqi@0 18 # information: Portions Copyright [yyyy] [name of copyright owner]
aoqi@0 19 #
aoqi@0 20 # CDDL HEADER END
aoqi@0 21 #
aoqi@0 22 # Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 23 # Use is subject to license terms.
aoqi@0 24 #
aoqi@0 25 # This script takes a file list and a workspace and builds a set of html files
aoqi@0 26 # suitable for doing a code review of source changes via a web page.
aoqi@0 27 # Documentation is available via 'webrev -h'.
aoqi@0 28 #
aoqi@0 29
aoqi@0 30 WEBREV_UPDATED=25.1-hg+openjdk.java.net
aoqi@0 31
aoqi@0 32 HTML='<?xml version="1.0"?>
aoqi@0 33 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
aoqi@0 34 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
aoqi@0 35 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
aoqi@0 36
aoqi@0 37 FRAMEHTML='<?xml version="1.0"?>
aoqi@0 38 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
aoqi@0 39 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
aoqi@0 40 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
aoqi@0 41
aoqi@0 42 STDHEAD='<meta charset="utf-8">
aoqi@0 43 <meta http-equiv="cache-control" content="no-cache" />
aoqi@0 44 <meta http-equiv="Pragma" content="no-cache" />
aoqi@0 45 <meta http-equiv="Expires" content="-1" />
aoqi@0 46 <!--
aoqi@0 47 Note to customizers: the body of the webrev is IDed as SUNWwebrev
aoqi@0 48 to allow easy overriding by users of webrev via the userContent.css
aoqi@0 49 mechanism available in some browsers.
aoqi@0 50
aoqi@0 51 For example, to have all "removed" information be red instead of
aoqi@0 52 brown, set a rule in your userContent.css file like:
aoqi@0 53
aoqi@0 54 body#SUNWwebrev span.removed { color: red ! important; }
aoqi@0 55 -->
aoqi@0 56 <style type="text/css" media="screen">
aoqi@0 57 body {
aoqi@0 58 background-color: #eeeeee;
aoqi@0 59 }
aoqi@0 60 hr {
aoqi@0 61 border: none 0;
aoqi@0 62 border-top: 1px solid #aaa;
aoqi@0 63 height: 1px;
aoqi@0 64 }
aoqi@0 65 div.summary {
aoqi@0 66 font-size: .8em;
aoqi@0 67 border-bottom: 1px solid #aaa;
aoqi@0 68 padding-left: 1em;
aoqi@0 69 padding-right: 1em;
aoqi@0 70 }
aoqi@0 71 div.summary h2 {
aoqi@0 72 margin-bottom: 0.3em;
aoqi@0 73 }
aoqi@0 74 div.summary table th {
aoqi@0 75 text-align: right;
aoqi@0 76 vertical-align: top;
aoqi@0 77 white-space: nowrap;
aoqi@0 78 }
aoqi@0 79 span.lineschanged {
aoqi@0 80 font-size: 0.7em;
aoqi@0 81 }
aoqi@0 82 span.oldmarker {
aoqi@0 83 color: red;
aoqi@0 84 font-size: large;
aoqi@0 85 font-weight: bold;
aoqi@0 86 }
aoqi@0 87 span.newmarker {
aoqi@0 88 color: green;
aoqi@0 89 font-size: large;
aoqi@0 90 font-weight: bold;
aoqi@0 91 }
aoqi@0 92 span.removed {
aoqi@0 93 color: brown;
aoqi@0 94 }
aoqi@0 95 span.changed {
aoqi@0 96 color: blue;
aoqi@0 97 }
aoqi@0 98 span.new {
aoqi@0 99 color: blue;
aoqi@0 100 font-weight: bold;
aoqi@0 101 }
aoqi@0 102 a.print { font-size: x-small; }
aoqi@0 103
aoqi@0 104 </style>
aoqi@0 105
aoqi@0 106 <style type="text/css" media="print">
aoqi@0 107 pre { font-size: 0.8em; font-family: courier, monospace; }
aoqi@0 108 span.removed { color: #444; font-style: italic }
aoqi@0 109 span.changed { font-weight: bold; }
aoqi@0 110 span.new { font-weight: bold; }
aoqi@0 111 span.newmarker { font-size: 1.2em; font-weight: bold; }
aoqi@0 112 span.oldmarker { font-size: 1.2em; font-weight: bold; }
aoqi@0 113 a.print {display: none}
aoqi@0 114 hr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
aoqi@0 115 </style>
aoqi@0 116 '
aoqi@0 117
aoqi@0 118 #
aoqi@0 119 # UDiffs need a slightly different CSS rule for 'new' items (we don't
aoqi@0 120 # want them to be bolded as we do in cdiffs or sdiffs).
aoqi@0 121 #
aoqi@0 122 UDIFFCSS='
aoqi@0 123 <style type="text/css" media="screen">
aoqi@0 124 span.new {
aoqi@0 125 color: blue;
aoqi@0 126 font-weight: normal;
aoqi@0 127 }
aoqi@0 128 </style>
aoqi@0 129 '
aoqi@0 130
aoqi@0 131 #
aoqi@0 132 # input_cmd | html_quote | output_cmd
aoqi@0 133 # or
aoqi@0 134 # html_quote filename | output_cmd
aoqi@0 135 #
aoqi@0 136 # Make a piece of source code safe for display in an HTML <pre> block.
aoqi@0 137 #
aoqi@0 138 html_quote()
aoqi@0 139 {
aoqi@0 140 sed -e "s/&/\&amp;/g" -e "s/&amp;#\([x]*[0-9A-Fa-f]\{2,5\}\);/\&#\1;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
aoqi@0 141 }
aoqi@0 142
aoqi@0 143 #
aoqi@0 144 # input_cmd | html_quote | output_cmd
aoqi@0 145 # or
aoqi@0 146 # html_dequote filename | output_cmd
aoqi@0 147 #
aoqi@0 148 # Replace HTML entities with literals
aoqi@0 149 #
aoqi@0 150 html_dequote()
aoqi@0 151 {
aoqi@0 152 sed -e "s/&quot;/\"/g" -e "s/&apos;/\'/g" -e "s/&amp;/\&/g" -e "s/&lt;/<'/g" -e "s/&gt;/>/g" "$@" | expand
aoqi@0 153 }
aoqi@0 154
aoqi@0 155 #
aoqi@0 156 # input_cmd | bug2url | output_cmd
aoqi@0 157 #
aoqi@0 158 # Scan for bugids and insert <a> links to the relevent bug database.
aoqi@0 159 #
aoqi@0 160 bug2url()
aoqi@0 161 {
aoqi@0 162 sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL$IDPREFIX'&\">&</a>|g'
aoqi@0 163 }
aoqi@0 164
aoqi@0 165 #
aoqi@0 166 # strip_unchanged <infile> | output_cmd
aoqi@0 167 #
aoqi@0 168 # Removes chunks of sdiff documents that have not changed. This makes it
aoqi@0 169 # easier for a code reviewer to find the bits that have changed.
aoqi@0 170 #
aoqi@0 171 # Deleted lines of text are replaced by a horizontal rule. Some
aoqi@0 172 # identical lines are retained before and after the changed lines to
aoqi@0 173 # provide some context. The number of these lines is controlled by the
aoqi@0 174 # variable C in the $AWK script below.
aoqi@0 175 #
aoqi@0 176 # The script detects changed lines as any line that has a "<span class="
aoqi@0 177 # string embedded (unchanged lines have no particular class and are not
aoqi@0 178 # part of a <span>). Blank lines (without a sequence number) are also
aoqi@0 179 # detected since they flag lines that have been inserted or deleted.
aoqi@0 180 #
aoqi@0 181 strip_unchanged()
aoqi@0 182 {
aoqi@0 183 $AWK '
aoqi@0 184 BEGIN { C = c = 20 }
aoqi@0 185 NF == 0 || /span class=/ {
aoqi@0 186 if (c > C) {
aoqi@0 187 c -= C
aoqi@0 188 inx = 0
aoqi@0 189 if (c > C) {
aoqi@0 190 print "\n</pre><hr></hr><pre>"
aoqi@0 191 inx = c % C
aoqi@0 192 c = C
aoqi@0 193 }
aoqi@0 194
aoqi@0 195 for (i = 0; i < c; i++)
aoqi@0 196 print ln[(inx + i) % C]
aoqi@0 197 }
aoqi@0 198 c = 0;
aoqi@0 199 print
aoqi@0 200 next
aoqi@0 201 }
aoqi@0 202 { if (c >= C) {
aoqi@0 203 ln[c % C] = $0
aoqi@0 204 c++;
aoqi@0 205 next;
aoqi@0 206 }
aoqi@0 207 c++;
aoqi@0 208 print
aoqi@0 209 }
aoqi@0 210 END { if (c > (C * 2)) print "\n</pre><hr></hr>" }
aoqi@0 211
aoqi@0 212 ' $1
aoqi@0 213 }
aoqi@0 214
aoqi@0 215 #
aoqi@0 216 # sdiff_to_html
aoqi@0 217 #
aoqi@0 218 # This function takes two files as arguments, obtains their diff, and
aoqi@0 219 # processes the diff output to present the files as an HTML document with
aoqi@0 220 # the files displayed side-by-side, differences shown in color. It also
aoqi@0 221 # takes a delta comment, rendered as an HTML snippet, as the third
aoqi@0 222 # argument. The function takes two files as arguments, then the name of
aoqi@0 223 # file, the path, and the comment. The HTML will be delivered on stdout,
aoqi@0 224 # e.g.
aoqi@0 225 #
aoqi@0 226 # $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
aoqi@0 227 # new/usr/src/tools/scripts/webrev.sh \
aoqi@0 228 # webrev.sh usr/src/tools/scripts \
aoqi@0 229 # '<a href="https://bugs.openjdk.java.net/browse/JDK-1234567">
aoqi@0 230 # JDK-1234567</a> my bugid' > <file>.html
aoqi@0 231 #
aoqi@0 232 # framed_sdiff() is then called which creates $2.frames.html
aoqi@0 233 # in the webrev tree.
aoqi@0 234 #
aoqi@0 235 # FYI: This function is rather unusual in its use of awk. The initial
aoqi@0 236 # diff run produces conventional diff output showing changed lines mixed
aoqi@0 237 # with editing codes. The changed lines are ignored - we're interested in
aoqi@0 238 # the editing codes, e.g.
aoqi@0 239 #
aoqi@0 240 # 8c8
aoqi@0 241 # 57a61
aoqi@0 242 # 63c66,76
aoqi@0 243 # 68,93d80
aoqi@0 244 # 106d90
aoqi@0 245 # 108,110d91
aoqi@0 246 #
aoqi@0 247 # These editing codes are parsed by the awk script and used to generate
aoqi@0 248 # another awk script that generates HTML, e.g the above lines would turn
aoqi@0 249 # into something like this:
aoqi@0 250 #
aoqi@0 251 # BEGIN { printf "<pre>\n" }
aoqi@0 252 # function sp(n) {for (i=0;i<n;i++)printf "\n"}
aoqi@0 253 # function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
aoqi@0 254 # NR==8 {wl("#7A7ADD");next}
aoqi@0 255 # NR==54 {wl("#7A7ADD");sp(3);next}
aoqi@0 256 # NR==56 {wl("#7A7ADD");next}
aoqi@0 257 # NR==57 {wl("black");printf "\n"; next}
aoqi@0 258 # : :
aoqi@0 259 #
aoqi@0 260 # This script is then run on the original source file to generate the
aoqi@0 261 # HTML that corresponds to the source file.
aoqi@0 262 #
aoqi@0 263 # The two HTML files are then combined into a single piece of HTML that
aoqi@0 264 # uses an HTML table construct to present the files side by side. You'll
aoqi@0 265 # notice that the changes are color-coded:
aoqi@0 266 #
aoqi@0 267 # black - unchanged lines
aoqi@0 268 # blue - changed lines
aoqi@0 269 # bold blue - new lines
aoqi@0 270 # brown - deleted lines
aoqi@0 271 #
aoqi@0 272 # Blank lines are inserted in each file to keep unchanged lines in sync
aoqi@0 273 # (side-by-side). This format is familiar to users of sdiff(1) or
aoqi@0 274 # Teamware's filemerge tool.
aoqi@0 275 #
aoqi@0 276 sdiff_to_html()
aoqi@0 277 {
aoqi@0 278 diff -b $1 $2 > /tmp/$$.diffs
aoqi@0 279
aoqi@0 280 TNAME=$3
aoqi@0 281 TPATH=$4
aoqi@0 282 COMMENT=$5
aoqi@0 283
aoqi@0 284 #
aoqi@0 285 # Now we have the diffs, generate the HTML for the old file.
aoqi@0 286 #
aoqi@0 287 $AWK '
aoqi@0 288 BEGIN {
aoqi@0 289 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
aoqi@0 290 printf "function removed() "
aoqi@0 291 printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
aoqi@0 292 printf "function changed() "
aoqi@0 293 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
aoqi@0 294 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0 295 }
aoqi@0 296 /^</ {next}
aoqi@0 297 /^>/ {next}
aoqi@0 298 /^---/ {next}
aoqi@0 299
aoqi@0 300 {
aoqi@0 301 split($1, a, /[cad]/) ;
aoqi@0 302 if (index($1, "a")) {
aoqi@0 303 if (a[1] == 0) {
aoqi@0 304 n = split(a[2], r, /,/);
aoqi@0 305 if (n == 1)
aoqi@0 306 printf "BEGIN\t\t{sp(1)}\n"
aoqi@0 307 else
aoqi@0 308 printf "BEGIN\t\t{sp(%d)}\n",\
aoqi@0 309 (r[2] - r[1]) + 1
aoqi@0 310 next
aoqi@0 311 }
aoqi@0 312
aoqi@0 313 printf "NR==%s\t\t{", a[1]
aoqi@0 314 n = split(a[2], r, /,/);
aoqi@0 315 s = r[1];
aoqi@0 316 if (n == 1)
aoqi@0 317 printf "bl();printf \"\\n\"; next}\n"
aoqi@0 318 else {
aoqi@0 319 n = r[2] - r[1]
aoqi@0 320 printf "bl();sp(%d);next}\n",\
aoqi@0 321 (r[2] - r[1]) + 1
aoqi@0 322 }
aoqi@0 323 next
aoqi@0 324 }
aoqi@0 325 if (index($1, "d")) {
aoqi@0 326 n = split(a[1], r, /,/);
aoqi@0 327 n1 = r[1]
aoqi@0 328 n2 = r[2]
aoqi@0 329 if (n == 1)
aoqi@0 330 printf "NR==%s\t\t{removed(); next}\n" , n1
aoqi@0 331 else
aoqi@0 332 printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
aoqi@0 333 next
aoqi@0 334 }
aoqi@0 335 if (index($1, "c")) {
aoqi@0 336 n = split(a[1], r, /,/);
aoqi@0 337 n1 = r[1]
aoqi@0 338 n2 = r[2]
aoqi@0 339 final = n2
aoqi@0 340 d1 = 0
aoqi@0 341 if (n == 1)
aoqi@0 342 printf "NR==%s\t\t{changed();" , n1
aoqi@0 343 else {
aoqi@0 344 d1 = n2 - n1
aoqi@0 345 printf "NR==%s,NR==%s\t{changed();" , n1, n2
aoqi@0 346 }
aoqi@0 347 m = split(a[2], r, /,/);
aoqi@0 348 n1 = r[1]
aoqi@0 349 n2 = r[2]
aoqi@0 350 if (m > 1) {
aoqi@0 351 d2 = n2 - n1
aoqi@0 352 if (d2 > d1) {
aoqi@0 353 if (n > 1) printf "if (NR==%d)", final
aoqi@0 354 printf "sp(%d);", d2 - d1
aoqi@0 355 }
aoqi@0 356 }
aoqi@0 357 printf "next}\n" ;
aoqi@0 358
aoqi@0 359 next
aoqi@0 360 }
aoqi@0 361 }
aoqi@0 362
aoqi@0 363 END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
aoqi@0 364 ' /tmp/$$.diffs > /tmp/$$.file1
aoqi@0 365
aoqi@0 366 #
aoqi@0 367 # Now generate the HTML for the new file
aoqi@0 368 #
aoqi@0 369 $AWK '
aoqi@0 370 BEGIN {
aoqi@0 371 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
aoqi@0 372 printf "function new() "
aoqi@0 373 printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
aoqi@0 374 printf "function changed() "
aoqi@0 375 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
aoqi@0 376 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
aoqi@0 377 }
aoqi@0 378
aoqi@0 379 /^</ {next}
aoqi@0 380 /^>/ {next}
aoqi@0 381 /^---/ {next}
aoqi@0 382
aoqi@0 383 {
aoqi@0 384 split($1, a, /[cad]/) ;
aoqi@0 385 if (index($1, "d")) {
aoqi@0 386 if (a[2] == 0) {
aoqi@0 387 n = split(a[1], r, /,/);
aoqi@0 388 if (n == 1)
aoqi@0 389 printf "BEGIN\t\t{sp(1)}\n"
aoqi@0 390 else
aoqi@0 391 printf "BEGIN\t\t{sp(%d)}\n",\
aoqi@0 392 (r[2] - r[1]) + 1
aoqi@0 393 next
aoqi@0 394 }
aoqi@0 395
aoqi@0 396 printf "NR==%s\t\t{", a[2]
aoqi@0 397 n = split(a[1], r, /,/);
aoqi@0 398 s = r[1];
aoqi@0 399 if (n == 1)
aoqi@0 400 printf "bl();printf \"\\n\"; next}\n"
aoqi@0 401 else {
aoqi@0 402 n = r[2] - r[1]
aoqi@0 403 printf "bl();sp(%d);next}\n",\
aoqi@0 404 (r[2] - r[1]) + 1
aoqi@0 405 }
aoqi@0 406 next
aoqi@0 407 }
aoqi@0 408 if (index($1, "a")) {
aoqi@0 409 n = split(a[2], r, /,/);
aoqi@0 410 n1 = r[1]
aoqi@0 411 n2 = r[2]
aoqi@0 412 if (n == 1)
aoqi@0 413 printf "NR==%s\t\t{new() ; next}\n" , n1
aoqi@0 414 else
aoqi@0 415 printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
aoqi@0 416 next
aoqi@0 417 }
aoqi@0 418 if (index($1, "c")) {
aoqi@0 419 n = split(a[2], r, /,/);
aoqi@0 420 n1 = r[1]
aoqi@0 421 n2 = r[2]
aoqi@0 422 final = n2
aoqi@0 423 d2 = 0;
aoqi@0 424 if (n == 1) {
aoqi@0 425 final = n1
aoqi@0 426 printf "NR==%s\t\t{changed();" , n1
aoqi@0 427 } else {
aoqi@0 428 d2 = n2 - n1
aoqi@0 429 printf "NR==%s,NR==%s\t{changed();" , n1, n2
aoqi@0 430 }
aoqi@0 431 m = split(a[1], r, /,/);
aoqi@0 432 n1 = r[1]
aoqi@0 433 n2 = r[2]
aoqi@0 434 if (m > 1) {
aoqi@0 435 d1 = n2 - n1
aoqi@0 436 if (d1 > d2) {
aoqi@0 437 if (n > 1) printf "if (NR==%d)", final
aoqi@0 438 printf "sp(%d);", d1 - d2
aoqi@0 439 }
aoqi@0 440 }
aoqi@0 441 printf "next}\n" ;
aoqi@0 442 next
aoqi@0 443 }
aoqi@0 444 }
aoqi@0 445 END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
aoqi@0 446 ' /tmp/$$.diffs > /tmp/$$.file2
aoqi@0 447
aoqi@0 448 #
aoqi@0 449 # Post-process the HTML files by running them back through $AWK
aoqi@0 450 #
aoqi@0 451 html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
aoqi@0 452
aoqi@0 453 html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
aoqi@0 454
aoqi@0 455 #
aoqi@0 456 # Now combine into a valid HTML file and side-by-side into a table
aoqi@0 457 #
aoqi@0 458 print "$HTML<head>$STDHEAD"
aoqi@0 459 print "<title>$WNAME Sdiff $TPATH </title>"
aoqi@0 460 print "</head><body id=\"SUNWwebrev\">"
aoqi@0 461 print "<h2>$TPATH/$TNAME</h2>"
aoqi@0 462 print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
aoqi@0 463 print "<pre>$COMMENT</pre>\n"
aoqi@0 464 print "<table><tr valign=\"top\">"
aoqi@0 465 print "<td><pre>"
aoqi@0 466
aoqi@0 467 strip_unchanged /tmp/$$.file1.html
aoqi@0 468
aoqi@0 469 print "</pre></td><td><pre>"
aoqi@0 470
aoqi@0 471 strip_unchanged /tmp/$$.file2.html
aoqi@0 472
aoqi@0 473 print "</pre></td>"
aoqi@0 474 print "</tr></table>"
aoqi@0 475 print "</body></html>"
aoqi@0 476
aoqi@0 477 framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
aoqi@0 478 "$COMMENT"
aoqi@0 479 }
aoqi@0 480
aoqi@0 481
aoqi@0 482 #
aoqi@0 483 # framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
aoqi@0 484 #
aoqi@0 485 # Expects lefthand and righthand side html files created by sdiff_to_html.
aoqi@0 486 # We use insert_anchors() to augment those with HTML navigation anchors,
aoqi@0 487 # and then emit the main frame. Content is placed into:
aoqi@0 488 #
aoqi@0 489 # $WDIR/DIR/$TNAME.lhs.html
aoqi@0 490 # $WDIR/DIR/$TNAME.rhs.html
aoqi@0 491 # $WDIR/DIR/$TNAME.frames.html
aoqi@0 492 #
aoqi@0 493 # NOTE: We rely on standard usage of $WDIR and $DIR.
aoqi@0 494 #
aoqi@0 495 function framed_sdiff
aoqi@0 496 {
aoqi@0 497 typeset TNAME=$1
aoqi@0 498 typeset TPATH=$2
aoqi@0 499 typeset lhsfile=$3
aoqi@0 500 typeset rhsfile=$4
aoqi@0 501 typeset comments=$5
aoqi@0 502 typeset RTOP
aoqi@0 503
aoqi@0 504 # Enable html files to access WDIR via a relative path.
aoqi@0 505 RTOP=$(relative_dir $TPATH $WDIR)
aoqi@0 506
aoqi@0 507 # Make the rhs/lhs files and output the frameset file.
aoqi@0 508 print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
aoqi@0 509
aoqi@0 510 cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
aoqi@0 511 <script type="text/javascript" src="$RTOP/ancnav.js"></script>
aoqi@0 512 </head>
aoqi@0 513 <body id="SUNWwebrev" onkeypress="keypress(event);">
aoqi@0 514 <a name="0"></a>
aoqi@0 515 <pre>$comments</pre><hr></hr>
aoqi@0 516 EOF
aoqi@0 517
aoqi@0 518 cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
aoqi@0 519
aoqi@0 520 insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
aoqi@0 521 insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
aoqi@0 522
aoqi@0 523 close='</body></html>'
aoqi@0 524
aoqi@0 525 print $close >> $WDIR/$DIR/$TNAME.lhs.html
aoqi@0 526 print $close >> $WDIR/$DIR/$TNAME.rhs.html
aoqi@0 527
aoqi@0 528 print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
aoqi@0 529 print "<title>$WNAME Framed-Sdiff " \
aoqi@0 530 "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
aoqi@0 531 cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
aoqi@0 532 <frameset rows="*,60">
aoqi@0 533 <frameset cols="50%,50%">
aoqi@0 534 <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs" />
aoqi@0 535 <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs" />
aoqi@0 536 </frameset>
aoqi@0 537 <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
aoqi@0 538 marginheight="0" name="nav" />
aoqi@0 539 <noframes>
aoqi@0 540 <body id="SUNWwebrev">
aoqi@0 541 Alas 'frames' webrev requires that your browser supports frames
aoqi@0 542 and has the feature enabled.
aoqi@0 543 </body>
aoqi@0 544 </noframes>
aoqi@0 545 </frameset>
aoqi@0 546 </html>
aoqi@0 547 EOF
aoqi@0 548 }
aoqi@0 549
aoqi@0 550
aoqi@0 551 #
aoqi@0 552 # fix_postscript
aoqi@0 553 #
aoqi@0 554 # Merge codereview output files to a single conforming postscript file, by:
aoqi@0 555 # - removing all extraneous headers/trailers
aoqi@0 556 # - making the page numbers right
aoqi@0 557 # - removing pages devoid of contents which confuse some
aoqi@0 558 # postscript readers.
aoqi@0 559 #
aoqi@0 560 # From Casper.
aoqi@0 561 #
aoqi@0 562 function fix_postscript
aoqi@0 563 {
aoqi@0 564 infile=$1
aoqi@0 565
aoqi@0 566 cat > /tmp/$$.crmerge.pl << \EOF
aoqi@0 567
aoqi@0 568 print scalar(<>); # %!PS-Adobe---
aoqi@0 569 print "%%Orientation: Landscape\n";
aoqi@0 570
aoqi@0 571 $pno = 0;
aoqi@0 572 $doprint = 1;
aoqi@0 573
aoqi@0 574 $page = "";
aoqi@0 575
aoqi@0 576 while (<>) {
aoqi@0 577 next if (/^%%Pages:\s*\d+/);
aoqi@0 578
aoqi@0 579 if (/^%%Page:/) {
aoqi@0 580 if ($pno == 0 || $page =~ /\)S/) {
aoqi@0 581 # Header or single page containing text
aoqi@0 582 print "%%Page: ? $pno\n" if ($pno > 0);
aoqi@0 583 print $page;
aoqi@0 584 $pno++;
aoqi@0 585 } else {
aoqi@0 586 # Empty page, skip it.
aoqi@0 587 }
aoqi@0 588 $page = "";
aoqi@0 589 $doprint = 1;
aoqi@0 590 next;
aoqi@0 591 }
aoqi@0 592
aoqi@0 593 # Skip from %%Trailer of one document to Endprolog
aoqi@0 594 # %%Page of the next
aoqi@0 595 $doprint = 0 if (/^%%Trailer/);
aoqi@0 596 $page .= $_ if ($doprint);
aoqi@0 597 }
aoqi@0 598
aoqi@0 599 if ($page =~ /\)S/) {
aoqi@0 600 print "%%Page: ? $pno\n";
aoqi@0 601 print $page;
aoqi@0 602 } else {
aoqi@0 603 $pno--;
aoqi@0 604 }
aoqi@0 605 print "%%Trailer\n%%Pages: $pno\n";
aoqi@0 606 EOF
aoqi@0 607
aoqi@0 608 $PERL /tmp/$$.crmerge.pl < $infile
aoqi@0 609 }
aoqi@0 610
aoqi@0 611
aoqi@0 612 #
aoqi@0 613 # input_cmd | insert_anchors | output_cmd
aoqi@0 614 #
aoqi@0 615 # Flag blocks of difference with sequentially numbered invisible
aoqi@0 616 # anchors. These are used to drive the frames version of the
aoqi@0 617 # sdiffs output.
aoqi@0 618 #
aoqi@0 619 # NOTE: Anchor zero flags the top of the file irrespective of changes,
aoqi@0 620 # an additional anchor is also appended to flag the bottom.
aoqi@0 621 #
aoqi@0 622 # The script detects changed lines as any line that has a "<span
aoqi@0 623 # class=" string embedded (unchanged lines have no class set and are
aoqi@0 624 # not part of a <span>. Blank lines (without a sequence number)
aoqi@0 625 # are also detected since they flag lines that have been inserted or
aoqi@0 626 # deleted.
aoqi@0 627 #
aoqi@0 628 function insert_anchors
aoqi@0 629 {
aoqi@0 630 $AWK '
aoqi@0 631 function ia() {
aoqi@0 632 # This should be able to be a singleton <a /> but that
aoqi@0 633 # seems to trigger a bug in firefox a:hover rule processing
aoqi@0 634 printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
aoqi@0 635 }
aoqi@0 636
aoqi@0 637 BEGIN {
aoqi@0 638 anc=1;
aoqi@0 639 inblock=1;
aoqi@0 640 printf "<pre>\n";
aoqi@0 641 }
aoqi@0 642 NF == 0 || /^<span class=/ {
aoqi@0 643 if (inblock == 0) {
aoqi@0 644 ia();
aoqi@0 645 inblock=1;
aoqi@0 646 }
aoqi@0 647 print;
aoqi@0 648 next;
aoqi@0 649 }
aoqi@0 650 {
aoqi@0 651 inblock=0;
aoqi@0 652 print;
aoqi@0 653 }
aoqi@0 654 END {
aoqi@0 655 ia();
aoqi@0 656
aoqi@0 657 printf "<b style=\"font-size: large; color: red\">";
aoqi@0 658 printf "--- EOF ---</b>"
aoqi@0 659 for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
aoqi@0 660 printf "</pre>"
aoqi@0 661 printf "<form name=\"eof\">";
aoqi@0 662 printf "<input name=\"value\" value=\"%d\" type=\"hidden\" />",
aoqi@0 663 anc - 1;
aoqi@0 664 printf "</form>";
aoqi@0 665 }
aoqi@0 666 ' $1
aoqi@0 667 }
aoqi@0 668
aoqi@0 669
aoqi@0 670 #
aoqi@0 671 # relative_dir
aoqi@0 672 #
aoqi@0 673 # Print a relative return path from $1 to $2. For example if
aoqi@0 674 # $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
aoqi@0 675 # this function would print "../../../../".
aoqi@0 676 #
aoqi@0 677 # In the event that $1 is not in $2 a warning is printed to stderr,
aoqi@0 678 # and $2 is returned-- the result of this is that the resulting webrev
aoqi@0 679 # is not relocatable.
aoqi@0 680 #
aoqi@0 681 function relative_dir
aoqi@0 682 {
aoqi@0 683 d1=$1
aoqi@0 684 d2=$2
aoqi@0 685 if [[ "$d1" == "." ]]; then
aoqi@0 686 print "."
aoqi@0 687 else
aoqi@0 688 typeset cur="${d1##$d2?(/)}"
aoqi@0 689 typeset ret=""
aoqi@0 690 if [[ $d2 == $cur ]]; then # Should never happen.
aoqi@0 691 # Should never happen.
aoqi@0 692 print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
aoqi@0 693 print -u2 "to \"$2\". Check input paths. Framed webrev "
aoqi@0 694 print -u2 "will not be relocatable!"
aoqi@0 695 print $2
aoqi@0 696 return
aoqi@0 697 fi
aoqi@0 698
aoqi@0 699 while [[ -n ${cur} ]];
aoqi@0 700 do
aoqi@0 701 cur=${cur%%*(/)*([!/])}
aoqi@0 702 if [[ -z $ret ]]; then
aoqi@0 703 ret=".."
aoqi@0 704 else
aoqi@0 705 ret="../$ret"
aoqi@0 706 fi
aoqi@0 707 done
aoqi@0 708 print $ret
aoqi@0 709 fi
aoqi@0 710 }
aoqi@0 711
aoqi@0 712
aoqi@0 713 #
aoqi@0 714 # frame_nav_js
aoqi@0 715 #
aoqi@0 716 # Emit javascript for frame navigation
aoqi@0 717 #
aoqi@0 718 function frame_nav_js
aoqi@0 719 {
aoqi@0 720 cat << \EOF
aoqi@0 721 var myInt;
aoqi@0 722 var scrolling=0;
aoqi@0 723 var sfactor = 3;
aoqi@0 724 var scount=10;
aoqi@0 725
aoqi@0 726 function scrollByPix() {
aoqi@0 727 if (scount<=0) {
aoqi@0 728 sfactor*=1.2;
aoqi@0 729 scount=10;
aoqi@0 730 }
aoqi@0 731 parent.lhs.scrollBy(0,sfactor);
aoqi@0 732 parent.rhs.scrollBy(0,sfactor);
aoqi@0 733 scount--;
aoqi@0 734 }
aoqi@0 735
aoqi@0 736 function scrollToAnc(num) {
aoqi@0 737
aoqi@0 738 // Update the value of the anchor in the form which we use as
aoqi@0 739 // storage for this value. setAncValue() will take care of
aoqi@0 740 // correcting for overflow and underflow of the value and return
aoqi@0 741 // us the new value.
aoqi@0 742 num = setAncValue(num);
aoqi@0 743
aoqi@0 744 // Set location and scroll back a little to expose previous
aoqi@0 745 // lines.
aoqi@0 746 //
aoqi@0 747 // Note that this could be improved: it is possible although
aoqi@0 748 // complex to compute the x and y position of an anchor, and to
aoqi@0 749 // scroll to that location directly.
aoqi@0 750 //
aoqi@0 751 parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
aoqi@0 752 parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
aoqi@0 753
aoqi@0 754 parent.lhs.scrollBy(0,-30);
aoqi@0 755 parent.rhs.scrollBy(0,-30);
aoqi@0 756 }
aoqi@0 757
aoqi@0 758 function getAncValue()
aoqi@0 759 {
aoqi@0 760 return (parseInt(parent.nav.document.diff.real.value));
aoqi@0 761 }
aoqi@0 762
aoqi@0 763 function setAncValue(val)
aoqi@0 764 {
aoqi@0 765 if (val <= 0) {
aoqi@0 766 val = 0;
aoqi@0 767 parent.nav.document.diff.real.value = val;
aoqi@0 768 parent.nav.document.diff.display.value = "BOF";
aoqi@0 769 return (val);
aoqi@0 770 }
aoqi@0 771
aoqi@0 772 //
aoqi@0 773 // The way we compute the max anchor value is to stash it
aoqi@0 774 // inline in the left and right hand side pages-- it's the same
aoqi@0 775 // on each side, so we pluck from the left.
aoqi@0 776 //
aoqi@0 777 maxval = parent.lhs.document.eof.value.value;
aoqi@0 778 if (val < maxval) {
aoqi@0 779 parent.nav.document.diff.real.value = val;
aoqi@0 780 parent.nav.document.diff.display.value = val.toString();
aoqi@0 781 return (val);
aoqi@0 782 }
aoqi@0 783
aoqi@0 784 // this must be: val >= maxval
aoqi@0 785 val = maxval;
aoqi@0 786 parent.nav.document.diff.real.value = val;
aoqi@0 787 parent.nav.document.diff.display.value = "EOF";
aoqi@0 788 return (val);
aoqi@0 789 }
aoqi@0 790
aoqi@0 791 function stopScroll() {
aoqi@0 792 if (scrolling==1) {
aoqi@0 793 clearInterval(myInt);
aoqi@0 794 scrolling=0;
aoqi@0 795 }
aoqi@0 796 }
aoqi@0 797
aoqi@0 798 function startScroll() {
aoqi@0 799 stopScroll();
aoqi@0 800 scrolling=1;
aoqi@0 801 myInt=setInterval("scrollByPix()",10);
aoqi@0 802 }
aoqi@0 803
aoqi@0 804 function handlePress(b) {
aoqi@0 805
aoqi@0 806 switch (b) {
aoqi@0 807 case 1 :
aoqi@0 808 scrollToAnc(-1);
aoqi@0 809 break;
aoqi@0 810 case 2 :
aoqi@0 811 scrollToAnc(getAncValue() - 1);
aoqi@0 812 break;
aoqi@0 813 case 3 :
aoqi@0 814 sfactor=-3;
aoqi@0 815 startScroll();
aoqi@0 816 break;
aoqi@0 817 case 4 :
aoqi@0 818 sfactor=3;
aoqi@0 819 startScroll();
aoqi@0 820 break;
aoqi@0 821 case 5 :
aoqi@0 822 scrollToAnc(getAncValue() + 1);
aoqi@0 823 break;
aoqi@0 824 case 6 :
aoqi@0 825 scrollToAnc(999999);
aoqi@0 826 break;
aoqi@0 827 }
aoqi@0 828 }
aoqi@0 829
aoqi@0 830 function handleRelease(b) {
aoqi@0 831 stopScroll();
aoqi@0 832 }
aoqi@0 833
aoqi@0 834 function keypress(ev) {
aoqi@0 835 var keynum;
aoqi@0 836 var keychar;
aoqi@0 837
aoqi@0 838 if (window.event) { // IE
aoqi@0 839 keynum = ev.keyCode;
aoqi@0 840 } else if (ev.which) { // non-IE
aoqi@0 841 keynum = ev.which;
aoqi@0 842 }
aoqi@0 843
aoqi@0 844 keychar = String.fromCharCode(keynum);
aoqi@0 845
aoqi@0 846 if (keychar == "k") {
aoqi@0 847 handlePress(2);
aoqi@0 848 return (0);
aoqi@0 849 } else if (keychar == "j" || keychar == " ") {
aoqi@0 850 handlePress(5);
aoqi@0 851 return (0);
aoqi@0 852 }
aoqi@0 853 return (1);
aoqi@0 854 }
aoqi@0 855
aoqi@0 856 function ValidateDiffNum(){
aoqi@0 857 val = parent.nav.document.diff.display.value;
aoqi@0 858 if (val == "EOF") {
aoqi@0 859 scrollToAnc(999999);
aoqi@0 860 return;
aoqi@0 861 }
aoqi@0 862
aoqi@0 863 if (val == "BOF") {
aoqi@0 864 scrollToAnc(0);
aoqi@0 865 return;
aoqi@0 866 }
aoqi@0 867
aoqi@0 868 i=parseInt(val);
aoqi@0 869 if (isNaN(i)) {
aoqi@0 870 parent.nav.document.diff.display.value = getAncValue();
aoqi@0 871 } else {
aoqi@0 872 scrollToAnc(i);
aoqi@0 873 }
aoqi@0 874 return false;
aoqi@0 875 }
aoqi@0 876
aoqi@0 877 EOF
aoqi@0 878 }
aoqi@0 879
aoqi@0 880 #
aoqi@0 881 # frame_navigation
aoqi@0 882 #
aoqi@0 883 # Output anchor navigation file for framed sdiffs.
aoqi@0 884 #
aoqi@0 885 function frame_navigation
aoqi@0 886 {
aoqi@0 887 print "$HTML<head>$STDHEAD"
aoqi@0 888
aoqi@0 889 cat << \EOF
aoqi@0 890 <title>Anchor Navigation</title>
aoqi@0 891 <meta http-equiv="Content-Script-Type" content="text/javascript" />
aoqi@0 892 <meta http-equiv="Content-Type" content="text/html" />
aoqi@0 893
aoqi@0 894 <style type="text/css">
aoqi@0 895 div.button td { padding-left: 5px; padding-right: 5px;
aoqi@0 896 background-color: #eee; text-align: center;
aoqi@0 897 border: 1px #444 outset; cursor: pointer; }
aoqi@0 898 div.button a { font-weight: bold; color: black }
aoqi@0 899 div.button td:hover { background: #ffcc99; }
aoqi@0 900 </style>
aoqi@0 901 EOF
aoqi@0 902
aoqi@0 903 print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
aoqi@0 904
aoqi@0 905 cat << \EOF
aoqi@0 906 </head>
aoqi@0 907 <body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
aoqi@0 908 onkeypress="keypress(event);">
aoqi@0 909 <noscript lang="javascript">
aoqi@0 910 <center>
aoqi@0 911 <p><big>Framed Navigation controls require Javascript</big><br />
aoqi@0 912 Either this browser is incompatable or javascript is not enabled</p>
aoqi@0 913 </center>
aoqi@0 914 </noscript>
aoqi@0 915 <table width="100%" border="0" align="center">
aoqi@0 916 <tr>
aoqi@0 917 <td valign="middle" width="25%">Diff navigation:
aoqi@0 918 Use 'j' and 'k' for next and previous diffs; or use buttons
aoqi@0 919 at right</td>
aoqi@0 920 <td align="center" valign="top" width="50%">
aoqi@0 921 <div class="button">
aoqi@0 922 <table border="0" align="center">
aoqi@0 923 <tr>
aoqi@0 924 <td>
aoqi@0 925 <a onMouseDown="handlePress(1);return true;"
aoqi@0 926 onMouseUp="handleRelease(1);return true;"
aoqi@0 927 onMouseOut="handleRelease(1);return true;"
aoqi@0 928 onClick="return false;"
aoqi@0 929 title="Go to Beginning Of file">BOF</a></td>
aoqi@0 930 <td>
aoqi@0 931 <a onMouseDown="handlePress(3);return true;"
aoqi@0 932 onMouseUp="handleRelease(3);return true;"
aoqi@0 933 onMouseOut="handleRelease(3);return true;"
aoqi@0 934 title="Scroll Up: Press and Hold to accelerate"
aoqi@0 935 onClick="return false;">Scroll Up</a></td>
aoqi@0 936 <td>
aoqi@0 937 <a onMouseDown="handlePress(2);return true;"
aoqi@0 938 onMouseUp="handleRelease(2);return true;"
aoqi@0 939 onMouseOut="handleRelease(2);return true;"
aoqi@0 940 title="Go to previous Diff"
aoqi@0 941 onClick="return false;">Prev Diff</a>
aoqi@0 942 </td></tr>
aoqi@0 943
aoqi@0 944 <tr>
aoqi@0 945 <td>
aoqi@0 946 <a onMouseDown="handlePress(6);return true;"
aoqi@0 947 onMouseUp="handleRelease(6);return true;"
aoqi@0 948 onMouseOut="handleRelease(6);return true;"
aoqi@0 949 onClick="return false;"
aoqi@0 950 title="Go to End Of File">EOF</a></td>
aoqi@0 951 <td>
aoqi@0 952 <a onMouseDown="handlePress(4);return true;"
aoqi@0 953 onMouseUp="handleRelease(4);return true;"
aoqi@0 954 onMouseOut="handleRelease(4);return true;"
aoqi@0 955 title="Scroll Down: Press and Hold to accelerate"
aoqi@0 956 onClick="return false;">Scroll Down</a></td>
aoqi@0 957 <td>
aoqi@0 958 <a onMouseDown="handlePress(5);return true;"
aoqi@0 959 onMouseUp="handleRelease(5);return true;"
aoqi@0 960 onMouseOut="handleRelease(5);return true;"
aoqi@0 961 title="Go to next Diff"
aoqi@0 962 onClick="return false;">Next Diff</a></td>
aoqi@0 963 </tr>
aoqi@0 964 </table>
aoqi@0 965 </div>
aoqi@0 966 </td>
aoqi@0 967 <th valign="middle" width="25%">
aoqi@0 968 <form action="" name="diff" onsubmit="return ValidateDiffNum();">
aoqi@0 969 <input name="display" value="BOF" size="8" type="text" />
aoqi@0 970 <input name="real" value="0" size="8" type="hidden" />
aoqi@0 971 </form>
aoqi@0 972 </th>
aoqi@0 973 </tr>
aoqi@0 974 </table>
aoqi@0 975 </body>
aoqi@0 976 </html>
aoqi@0 977 EOF
aoqi@0 978 }
aoqi@0 979
aoqi@0 980
aoqi@0 981
aoqi@0 982 #
aoqi@0 983 # diff_to_html <filename> <filepath> { U | C } <comment>
aoqi@0 984 #
aoqi@0 985 # Processes the output of diff to produce an HTML file representing either
aoqi@0 986 # context or unified diffs.
aoqi@0 987 #
aoqi@0 988 diff_to_html()
aoqi@0 989 {
aoqi@0 990 TNAME=$1
aoqi@0 991 TPATH=$2
aoqi@0 992 DIFFTYPE=$3
aoqi@0 993 COMMENT=$4
aoqi@0 994
aoqi@0 995 print "$HTML<head>$STDHEAD"
aoqi@0 996 print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
aoqi@0 997
aoqi@0 998 if [[ $DIFFTYPE == "U" ]]; then
aoqi@0 999 print "$UDIFFCSS"
aoqi@0 1000 fi
aoqi@0 1001
aoqi@0 1002 cat <<-EOF
aoqi@0 1003 </head>
aoqi@0 1004 <body id="SUNWwebrev">
aoqi@0 1005 <h2>$TPATH</h2>
aoqi@0 1006 <a class="print" href="javascript:print()">Print this page</a>
aoqi@0 1007 <pre>$COMMENT</pre>
aoqi@0 1008 <pre>
aoqi@0 1009 EOF
aoqi@0 1010
aoqi@0 1011 html_quote | $AWK '
aoqi@0 1012 /^--- new/ { next }
aoqi@0 1013 /^\+\+\+ new/ { next }
aoqi@0 1014 /^--- old/ { next }
aoqi@0 1015 /^\*\*\* old/ { next }
aoqi@0 1016 /^\*\*\*\*/ { next }
aoqi@0 1017 /^-------/ { printf "<center><h1>%s</h1></center>\n", $0; next }
aoqi@0 1018 /^\@\@.*\@\@$/ { printf "</pre><hr /><pre>\n";
aoqi@0 1019 printf "<span class=\"newmarker\">%s</span>\n", $0;
aoqi@0 1020 next}
aoqi@0 1021
aoqi@0 1022 /^\*\*\*/ { printf "<hr /><span class=\"oldmarker\">%s</span>\n", $0;
aoqi@0 1023 next}
aoqi@0 1024 /^---/ { printf "<span class=\"newmarker\">%s</span>\n", $0;
aoqi@0 1025 next}
aoqi@0 1026 /^\+/ {printf "<span class=\"new\">%s</span>\n", $0; next}
aoqi@0 1027 /^!/ {printf "<span class=\"changed\">%s</span>\n", $0; next}
aoqi@0 1028 /^-/ {printf "<span class=\"removed\">%s</span>\n", $0; next}
aoqi@0 1029 {printf "%s\n", $0; next}
aoqi@0 1030 '
aoqi@0 1031
aoqi@0 1032 print "</pre></body></html>\n"
aoqi@0 1033 }
aoqi@0 1034
aoqi@0 1035
aoqi@0 1036 #
aoqi@0 1037 # source_to_html { new | old } <filename>
aoqi@0 1038 #
aoqi@0 1039 # Process a plain vanilla source file to transform it into an HTML file.
aoqi@0 1040 #
aoqi@0 1041 source_to_html()
aoqi@0 1042 {
aoqi@0 1043 WHICH=$1
aoqi@0 1044 TNAME=$2
aoqi@0 1045
aoqi@0 1046 print "$HTML<head>$STDHEAD"
aoqi@0 1047 print "<title>$WHICH $TNAME</title>"
aoqi@0 1048 print "<body id=\"SUNWwebrev\">"
aoqi@0 1049 print "<pre>"
aoqi@0 1050 html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
aoqi@0 1051 print "</pre></body></html>"
aoqi@0 1052 }
aoqi@0 1053
aoqi@0 1054 comments_from_mercurial()
aoqi@0 1055 {
aoqi@0 1056 fmt=$1
aoqi@0 1057 pfile=$PWS/$2
aoqi@0 1058 cfile=$CWS/$3
aoqi@0 1059
aoqi@0 1060 logdir=`dirname $cfile`
aoqi@0 1061 logf=`basename $cfile`
aoqi@0 1062 if [ -d $logdir ]; then
aoqi@0 1063 ( cd $logdir;
aoqi@0 1064 active=`hg status $logf 2>/dev/null`
aoqi@0 1065 # If the output from 'hg status' is not empty, it means the file
aoqi@0 1066 # hasn't been committed, so don't fetch comments.
aoqi@0 1067 if [[ -z $active ]] ; then
aoqi@0 1068 if [[ -n $ALL_CREV ]]; then
aoqi@0 1069 rev_opt=
aoqi@0 1070 for rev in $ALL_CREV; do
aoqi@0 1071 rev_opt="$rev_opt --rev $rev"
aoqi@0 1072 done
aoqi@0 1073 comm=`hg log $rev_opt --follow --template 'rev {rev} : {desc}\n' $logf`
aoqi@0 1074 elif [[ -n $FIRST_CREV ]]; then
aoqi@0 1075 comm=`hg log --rev $FIRST_CREV:tip --follow --template 'rev {rev} : {desc}\n' $logf`
aoqi@0 1076 else
aoqi@0 1077 comm=`hg log -l1 --follow --template 'rev {rev} : {desc}\n' $logf`
aoqi@0 1078 fi
aoqi@0 1079 else
aoqi@0 1080 comm=""
aoqi@0 1081 fi
aoqi@0 1082 if [[ $fmt == "text" ]]; then
aoqi@0 1083 print "$comm"
aoqi@0 1084 return
aoqi@0 1085 fi
aoqi@0 1086
aoqi@0 1087 print "$comm" | html_quote | bug2url
aoqi@0 1088 )
aoqi@0 1089 fi
aoqi@0 1090 }
aoqi@0 1091
aoqi@0 1092
aoqi@0 1093 #
aoqi@0 1094 # getcomments {text|html} filepath parentpath
aoqi@0 1095 #
aoqi@0 1096 # Fetch the comments depending on what SCM mode we're in.
aoqi@0 1097 #
aoqi@0 1098 getcomments()
aoqi@0 1099 {
aoqi@0 1100 typeset fmt=$1
aoqi@0 1101 typeset p=$2
aoqi@0 1102 typeset pp=$3
aoqi@0 1103
aoqi@0 1104 comments_from_mercurial $fmt $pp $p
aoqi@0 1105 }
aoqi@0 1106
aoqi@0 1107 #
aoqi@0 1108 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
aoqi@0 1109 #
aoqi@0 1110 # Print out Code Inspection figures similar to sccs-prt(1) format.
aoqi@0 1111 #
aoqi@0 1112 function printCI
aoqi@0 1113 {
aoqi@0 1114 integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
aoqi@0 1115 typeset str
aoqi@0 1116 if (( tot == 1 )); then
aoqi@0 1117 str="line"
aoqi@0 1118 else
aoqi@0 1119 str="lines"
aoqi@0 1120 fi
aoqi@0 1121 printf '%d %s changed: %d ins; %d del; %d mod; %d unchg' \
aoqi@0 1122 $tot $str $ins $del $mod $unc
aoqi@0 1123 }
aoqi@0 1124
aoqi@0 1125
aoqi@0 1126 #
aoqi@0 1127 # difflines <oldfile> <newfile>
aoqi@0 1128 #
aoqi@0 1129 # Calculate and emit number of added, removed, modified and unchanged lines,
aoqi@0 1130 # and total lines changed, the sum of added + removed + modified.
aoqi@0 1131 #
aoqi@0 1132 function difflines
aoqi@0 1133 {
aoqi@0 1134 integer tot mod del ins unc err
aoqi@0 1135 typeset filename
aoqi@0 1136
aoqi@0 1137 eval $( diff -e $1 $2 | $AWK '
aoqi@0 1138 # Change range of lines: N,Nc
aoqi@0 1139 /^[0-9]*,[0-9]*c$/ {
aoqi@0 1140 n=split(substr($1,1,length($1)-1), counts, ",");
aoqi@0 1141 if (n != 2) {
aoqi@0 1142 error=2
aoqi@0 1143 exit;
aoqi@0 1144 }
aoqi@0 1145 #
aoqi@0 1146 # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
aoqi@0 1147 # following would be 5 - 3 = 2! Hence +1 for correction.
aoqi@0 1148 #
aoqi@0 1149 r=(counts[2]-counts[1])+1;
aoqi@0 1150
aoqi@0 1151 #
aoqi@0 1152 # Now count replacement lines: each represents a change instead
aoqi@0 1153 # of a delete, so increment c and decrement r.
aoqi@0 1154 #
aoqi@0 1155 while (getline != /^\.$/) {
aoqi@0 1156 c++;
aoqi@0 1157 r--;
aoqi@0 1158 }
aoqi@0 1159 #
aoqi@0 1160 # If there were more replacement lines than original lines,
aoqi@0 1161 # then r will be negative; in this case there are no deletions,
aoqi@0 1162 # but there are r changes that should be counted as adds, and
aoqi@0 1163 # since r is negative, subtract it from a and add it to c.
aoqi@0 1164 #
aoqi@0 1165 if (r < 0) {
aoqi@0 1166 a-=r;
aoqi@0 1167 c+=r;
aoqi@0 1168 }
aoqi@0 1169
aoqi@0 1170 #
aoqi@0 1171 # If there were more original lines than replacement lines, then
aoqi@0 1172 # r will be positive; in this case, increment d by that much.
aoqi@0 1173 #
aoqi@0 1174 if (r > 0) {
aoqi@0 1175 d+=r;
aoqi@0 1176 }
aoqi@0 1177 next;
aoqi@0 1178 }
aoqi@0 1179
aoqi@0 1180 # Change lines: Nc
aoqi@0 1181 /^[0-9].*c$/ {
aoqi@0 1182 # The first line is a replacement; any more are additions.
aoqi@0 1183 if (getline != /^\.$/) {
aoqi@0 1184 c++;
aoqi@0 1185 while (getline != /^\.$/) a++;
aoqi@0 1186 }
aoqi@0 1187 next;
aoqi@0 1188 }
aoqi@0 1189
aoqi@0 1190 # Add lines: both Na and N,Na
aoqi@0 1191 /^[0-9].*a$/ {
aoqi@0 1192 while (getline != /^\.$/) a++;
aoqi@0 1193 next;
aoqi@0 1194 }
aoqi@0 1195
aoqi@0 1196 # Delete range of lines: N,Nd
aoqi@0 1197 /^[0-9]*,[0-9]*d$/ {
aoqi@0 1198 n=split(substr($1,1,length($1)-1), counts, ",");
aoqi@0 1199 if (n != 2) {
aoqi@0 1200 error=2
aoqi@0 1201 exit;
aoqi@0 1202 }
aoqi@0 1203 #
aoqi@0 1204 # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
aoqi@0 1205 # following would be 5 - 3 = 2! Hence +1 for correction.
aoqi@0 1206 #
aoqi@0 1207 r=(counts[2]-counts[1])+1;
aoqi@0 1208 d+=r;
aoqi@0 1209 next;
aoqi@0 1210 }
aoqi@0 1211
aoqi@0 1212 # Delete line: Nd. For example 10d says line 10 is deleted.
aoqi@0 1213 /^[0-9]*d$/ {d++; next}
aoqi@0 1214
aoqi@0 1215 # Should not get here!
aoqi@0 1216 {
aoqi@0 1217 error=1;
aoqi@0 1218 exit;
aoqi@0 1219 }
aoqi@0 1220
aoqi@0 1221 # Finish off - print results
aoqi@0 1222 END {
aoqi@0 1223 printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
aoqi@0 1224 (c+d+a), c, d, a, error);
aoqi@0 1225 }' )
aoqi@0 1226
aoqi@0 1227 # End of $AWK, Check to see if any trouble occurred.
aoqi@0 1228 if (( $? > 0 || err > 0 )); then
aoqi@0 1229 print "Unexpected Error occurred reading" \
aoqi@0 1230 "\`diff -e $1 $2\`: \$?=$?, err=" $err
aoqi@0 1231 return
aoqi@0 1232 fi
aoqi@0 1233
aoqi@0 1234 # Accumulate totals
aoqi@0 1235 (( TOTL += tot ))
aoqi@0 1236 (( TMOD += mod ))
aoqi@0 1237 (( TDEL += del ))
aoqi@0 1238 (( TINS += ins ))
aoqi@0 1239 # Calculate unchanged lines
aoqi@0 1240 unc=`wc -l < $1`
aoqi@0 1241 if (( unc > 0 )); then
aoqi@0 1242 (( unc -= del + mod ))
aoqi@0 1243 (( TUNC += unc ))
aoqi@0 1244 fi
aoqi@0 1245 # print summary
aoqi@0 1246 print "<span class=\"lineschanged\">\c"
aoqi@0 1247 printCI $tot $ins $del $mod $unc
aoqi@0 1248 print "</span>"
aoqi@0 1249 }
aoqi@0 1250
aoqi@0 1251 function outgoing_from_mercurial_forest
aoqi@0 1252 {
aoqi@0 1253 hg foutgoing --template 'rev: {rev}\n' $OUTPWS | $FILTER | $AWK '
aoqi@0 1254 BEGIN {ntree=0}
aoqi@0 1255 /^comparing/ {next}
aoqi@0 1256 /^no changes/ {next}
aoqi@0 1257 /^searching/ {next}
aoqi@0 1258 /^\[.*\]$/ {tree=substr($1,2,length($1)-2);
aoqi@0 1259 trees[ntree++] = tree;
aoqi@0 1260 revs[tree]=-1;
aoqi@0 1261 next}
aoqi@0 1262 /^rev:/ {rev=$2+0;
aoqi@0 1263 if (revs[tree] == -1 || rev < revs[tree])
aoqi@0 1264 { revs[tree] = rev; };
aoqi@0 1265 next;}
aoqi@0 1266 END {for (tree in trees)
aoqi@0 1267 { rev=revs[trees[tree]];
aoqi@0 1268 if (rev > 0)
aoqi@0 1269 {printf("%s %d\n",trees[tree],rev-1)}
aoqi@0 1270 }}' | while read LINE
aoqi@0 1271 do
aoqi@0 1272 set - $LINE
aoqi@0 1273 TREE=$1
aoqi@0 1274 REV=$2
aoqi@0 1275 A=`hg -R $CWS/$TREE log --rev $REV --template '{node}'`
aoqi@0 1276 FSTAT_OPT="--rev $A"
aoqi@0 1277 print "Revision: $A $REV" >> $FLIST
aoqi@0 1278 treestatus $TREE
aoqi@0 1279 done
aoqi@0 1280 }
aoqi@0 1281
aoqi@0 1282 function flist_from_mercurial_forest
aoqi@0 1283 {
aoqi@0 1284 rm -f $FLIST
aoqi@0 1285 if [ -z "$Nflag" ]; then
aoqi@0 1286 print " File list from hg foutgoing $PWS ..."
aoqi@0 1287 outgoing_from_mercurial_forest
aoqi@0 1288 HG_LIST_FROM_COMMIT=1
aoqi@0 1289 fi
aoqi@0 1290 if [ ! -f $FLIST ]; then
aoqi@0 1291 # hg commit hasn't been run see what is lying around
aoqi@0 1292 print "\n No outgoing, perhaps you haven't commited."
aoqi@0 1293 print " File list from hg fstatus -mard ...\c"
aoqi@0 1294 FSTAT_OPT=
aoqi@0 1295 fstatus
aoqi@0 1296 HG_LIST_FROM_COMMIT=
aoqi@0 1297 fi
aoqi@0 1298 print " Done."
aoqi@0 1299 }
aoqi@0 1300
aoqi@0 1301 #
aoqi@0 1302 # Used when dealing with the result of 'hg foutgoing'
aoqi@0 1303 # When now go down the tree and generate the change list
aoqi@0 1304 #
aoqi@0 1305 function treestatus
aoqi@0 1306 {
aoqi@0 1307 TREE=$1
aoqi@0 1308 HGCMD="hg -R $CWS/$TREE status $FSTAT_OPT"
aoqi@0 1309
aoqi@0 1310 $HGCMD -mdn 2>/dev/null | $FILTER | while read F
aoqi@0 1311 do
aoqi@0 1312 echo $TREE/$F
aoqi@0 1313 done >> $FLIST
aoqi@0 1314
aoqi@0 1315 # Then all the added files
aoqi@0 1316 # But some of these could have been "moved" or renamed ones or copied ones
aoqi@0 1317 # so let's make sure we get the proper info
aoqi@0 1318 # hg status -aC will produce something like:
aoqi@0 1319 # A subdir/File3
aoqi@0 1320 # A subdir/File4
aoqi@0 1321 # File4
aoqi@0 1322 # A subdir/File5
aoqi@0 1323 # The first and last are simple addition while the middle one
aoqi@0 1324 # is a move/rename or a copy. We can't distinguish from a rename vs a copy
aoqi@0 1325 # without also getting the status of removed files. The middle case above
aoqi@0 1326 # is a rename if File4 is also shown a being removed. If File4 is not a
aoqi@0 1327 # removed file, then the middle case is a copy from File4 to subdir/File4
aoqi@0 1328 # FIXME - we're not distinguishing copy from rename
aoqi@0 1329 $HGCMD -aC | $FILTER | while read LINE; do
aoqi@0 1330 ldone=""
aoqi@0 1331 while [ -z "$ldone" ]; do
aoqi@0 1332 ldone="1"
aoqi@0 1333 set - $LINE
aoqi@0 1334 if [ $# -eq 2 -a "$1" == "A" ]; then
aoqi@0 1335 AFILE=$2
aoqi@0 1336 if read LINE2; then
aoqi@0 1337 set - $LINE2
aoqi@0 1338 if [ $# -eq 1 ]; then
aoqi@0 1339 echo $TREE/$AFILE $TREE/$1 >>$FLIST
aoqi@0 1340 elif [ $# -eq 2 ]; then
aoqi@0 1341 echo $TREE/$AFILE >>$FLIST
aoqi@0 1342 LINE=$LINE2
aoqi@0 1343 ldone=""
aoqi@0 1344 fi
aoqi@0 1345 else
aoqi@0 1346 echo $TREE/$AFILE >>$FLIST
aoqi@0 1347 fi
aoqi@0 1348 fi
aoqi@0 1349 done
aoqi@0 1350 done
aoqi@0 1351 $HGCMD -rn | $FILTER | while read RFILE; do
aoqi@0 1352 grep "$TREE/$RFILE" $FLIST >/dev/null
aoqi@0 1353 if [ $? -eq 1 ]; then
aoqi@0 1354 echo $TREE/$RFILE >>$FLIST
aoqi@0 1355 fi
aoqi@0 1356 done
aoqi@0 1357 }
aoqi@0 1358
aoqi@0 1359 function fstatus
aoqi@0 1360 {
aoqi@0 1361 #
aoqi@0 1362 # forest extension is still being changed. For instance the output
aoqi@0 1363 # of fstatus used to no prepend the tree path to filenames, but
aoqi@0 1364 # this has changed recently. AWK code below does try to handle both
aoqi@0 1365 # cases
aoqi@0 1366 #
aoqi@0 1367 hg fstatus -mdn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
aoqi@0 1368 /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
aoqi@0 1369 $1 != "" {n=index($1,tree);
aoqi@0 1370 if (n == 0)
aoqi@0 1371 { printf("%s/%s\n",tree,$1)}
aoqi@0 1372 else
aoqi@0 1373 { printf("%s\n",$1)}}' >> $FLIST
aoqi@0 1374
aoqi@0 1375 #
aoqi@0 1376 # There is a bug in the output of fstatus -aC on recent versions: it
aoqi@0 1377 # inserts a space between the name of the tree and the filename of the
aoqi@0 1378 # old file. e.g.:
aoqi@0 1379 #
aoqi@0 1380 # $ hg fstatus -aC
aoqi@0 1381 # [.]
aoqi@0 1382 #
aoqi@0 1383 # [MyWS]
aoqi@0 1384 # A MyWS/subdir/File2
aoqi@0 1385 # MyWS/ File2
aoqi@0 1386 #
aoqi@0 1387 # [MyWS2]
aoqi@0 1388 #
aoqi@0 1389
aoqi@0 1390 hg fstatus -aC $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
aoqi@0 1391 /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
aoqi@0 1392 /^A .*/ {n=index($2,tree);
aoqi@0 1393 if (n == 0)
aoqi@0 1394 { printf("A %s/%s\n",tree,$2)}
aoqi@0 1395 else
aoqi@0 1396 { printf("A %s\n",$2)};
aoqi@0 1397 next}
aoqi@0 1398 /^ / {n=index($1,tree);
aoqi@0 1399 if (n == 0)
aoqi@0 1400 { printf("%s/%s\n",tree,$1)}
aoqi@0 1401 else
aoqi@0 1402 { if (NF == 2)
aoqi@0 1403 printf("%s/%s\n",tree,$2)
aoqi@0 1404 else
aoqi@0 1405 printf("%s\n",$1)
aoqi@0 1406 };
aoqi@0 1407 next}
aoqi@0 1408 ' | while read LINE; do
aoqi@0 1409 ldone=""
aoqi@0 1410 while [ -z "$ldone" ]; do
aoqi@0 1411 ldone="1"
aoqi@0 1412 set - $LINE
aoqi@0 1413 if [ $# -eq 2 -a "$1" == "A" ]; then
aoqi@0 1414 AFILE=$2
aoqi@0 1415 if read LINE2; then
aoqi@0 1416 set - $LINE2
aoqi@0 1417 if [ $# -eq 1 ]; then
aoqi@0 1418 echo $AFILE $1 >>$FLIST
aoqi@0 1419 elif [ $# -eq 2 ]; then
aoqi@0 1420 echo $AFILE >>$FLIST
aoqi@0 1421 LINE=$LINE2
aoqi@0 1422 ldone=""
aoqi@0 1423 fi
aoqi@0 1424 else
aoqi@0 1425 echo $AFILE >>$FLIST
aoqi@0 1426 fi
aoqi@0 1427 fi
aoqi@0 1428 done
aoqi@0 1429 done
aoqi@0 1430 hg fstatus -rn $FSTAT_OPT 2>/dev/null | $FILTER | $AWK '
aoqi@0 1431 /^\[.*\]$/ {tree=substr($1,2,length($1)-2); next}
aoqi@0 1432 $1 != "" {n=index($1,tree);
aoqi@0 1433 if (n == 0)
aoqi@0 1434 { printf("%s/%s\n",tree,$1)}
aoqi@0 1435 else
aoqi@0 1436 { printf("%s\n",$1)}}' | while read RFILE; do
aoqi@0 1437 grep "$RFILE" $FLIST >/dev/null
aoqi@0 1438 if [ $? -eq 1 ]; then
aoqi@0 1439 echo $RFILE >>$FLIST
aoqi@0 1440 fi
aoqi@0 1441 done
aoqi@0 1442 }
aoqi@0 1443
aoqi@0 1444 #
aoqi@0 1445 # flist_from_mercurial $PWS
aoqi@0 1446 #
aoqi@0 1447 # Only local file based repositories are supported at present
aoqi@0 1448 # since even though we can determine the list from the parent finding
aoqi@0 1449 # the changes is harder.
aoqi@0 1450 #
aoqi@0 1451 # We first look for any outgoing files, this is for when the user has
aoqi@0 1452 # run hg commit. If we don't find any then we look with hg status.
aoqi@0 1453 #
aoqi@0 1454 # We need at least one of default-push or default paths set in .hg/hgrc
aoqi@0 1455 # If neither are set we don't know who to compare with.
aoqi@0 1456
aoqi@0 1457 function flist_from_mercurial
aoqi@0 1458 {
aoqi@0 1459 # if [ "${PWS##ssh://}" != "$PWS" -o \
aoqi@0 1460 # "${PWS##http://}" != "$PWS" -o \
aoqi@0 1461 # "${PWS##https://}" != "$PWS" ]; then
aoqi@0 1462 # print "Remote Mercurial repositories not currently supported."
aoqi@0 1463 # print "Set default and/or default-push to a local repository"
aoqi@0 1464 # exit
aoqi@0 1465 # fi
aoqi@0 1466 if [[ -n $forestflag ]]; then
aoqi@0 1467 HG_LIST_FROM_COMMIT=
aoqi@0 1468 flist_from_mercurial_forest
aoqi@0 1469 else
aoqi@0 1470 STATUS_REV=
aoqi@0 1471 if [[ -n $rflag ]]; then
aoqi@0 1472 STATUS_REV="--rev $PARENT_REV"
aoqi@0 1473 elif [[ -n $OUTREV ]]; then
aoqi@0 1474 STATUS_REV="--rev $OUTREV"
aoqi@0 1475 else
aoqi@0 1476 # hg commit hasn't been run see what is lying around
aoqi@0 1477 print "\n No outgoing, perhaps you haven't commited."
aoqi@0 1478 fi
aoqi@0 1479 # First let's list all the modified or deleted files
aoqi@0 1480
aoqi@0 1481 hg status $STATUS_REV -mdn | $FILTER > $FLIST
aoqi@0 1482
aoqi@0 1483 # Then all the added files
aoqi@0 1484 # But some of these could have been "moved" or renamed ones
aoqi@0 1485 # so let's make sure we get the proper info
aoqi@0 1486 # hg status -aC will produce something like:
aoqi@0 1487 # A subdir/File3
aoqi@0 1488 # A subdir/File4
aoqi@0 1489 # File4
aoqi@0 1490 # A subdir/File5
aoqi@0 1491 # The first and last are simple addition while the middle one
aoqi@0 1492 # is a move/rename or a copy. We can't distinguish from a rename vs a copy
aoqi@0 1493 # without also getting the status of removed files. The middle case above
aoqi@0 1494 # is a rename if File4 is also shown a being removed. If File4 is not a
aoqi@0 1495 # removed file, then the middle case is a copy from File4 to subdir/File4
aoqi@0 1496 # FIXME - we're not distinguishing copy from rename
aoqi@0 1497
aoqi@0 1498 hg status $STATUS_REV -aC | $FILTER >$FLIST.temp
aoqi@0 1499 while read LINE; do
aoqi@0 1500 ldone=""
aoqi@0 1501 while [ -z "$ldone" ]; do
aoqi@0 1502 ldone="1"
aoqi@0 1503 set - $LINE
aoqi@0 1504 if [ $# -eq 2 -a "$1" == "A" ]; then
aoqi@0 1505 AFILE=$2
aoqi@0 1506 if read LINE2; then
aoqi@0 1507 set - $LINE2
aoqi@0 1508 if [ $# -eq 1 ]; then
aoqi@0 1509 echo $AFILE $1 >>$FLIST
aoqi@0 1510 elif [ $# -eq 2 ]; then
aoqi@0 1511 echo $AFILE >>$FLIST
aoqi@0 1512 LINE=$LINE2
aoqi@0 1513 ldone=""
aoqi@0 1514 fi
aoqi@0 1515 else
aoqi@0 1516 echo $AFILE >>$FLIST
aoqi@0 1517 fi
aoqi@0 1518 fi
aoqi@0 1519 done
aoqi@0 1520 done < $FLIST.temp
aoqi@0 1521 hg status $STATUS_REV -rn | $FILTER > $FLIST.temp
aoqi@0 1522 while read RFILE; do
aoqi@0 1523 grep "$RFILE" $FLIST >/dev/null
aoqi@0 1524 if [ $? -eq 1 ]; then
aoqi@0 1525 echo $RFILE >>$FLIST
aoqi@0 1526 fi
aoqi@0 1527 done < $FLIST.temp
aoqi@0 1528 rm -f $FLIST.temp
aoqi@0 1529 fi
aoqi@0 1530 }
aoqi@0 1531
aoqi@0 1532 function env_from_flist
aoqi@0 1533 {
aoqi@0 1534 [[ -r $FLIST ]] || return
aoqi@0 1535
aoqi@0 1536 #
aoqi@0 1537 # Use "eval" to set env variables that are listed in the file
aoqi@0 1538 # list. Then copy those into our local versions of those
aoqi@0 1539 # variables if they have not been set already.
aoqi@0 1540 #
aoqi@0 1541 eval `sed -e "s/#.*$//" $FLIST | grep = `
aoqi@0 1542
aoqi@0 1543 [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
aoqi@0 1544
aoqi@0 1545 #
aoqi@0 1546 # Check to see if CODEMGR_PARENT is set in the flist file.
aoqi@0 1547 #
aoqi@0 1548 [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
aoqi@0 1549 codemgr_parent=$CODEMGR_PARENT
aoqi@0 1550 }
aoqi@0 1551
aoqi@0 1552 #
aoqi@0 1553 # detect_scm
aoqi@0 1554 #
aoqi@0 1555 # We dynamically test the SCM type; this allows future extensions to
aoqi@0 1556 # new SCM types
aoqi@0 1557 #
aoqi@0 1558 function detect_scm
aoqi@0 1559 {
aoqi@0 1560 if hg root >/dev/null ; then
aoqi@0 1561 print "mercurial"
aoqi@0 1562 else
aoqi@0 1563 print "unknown"
aoqi@0 1564 fi
aoqi@0 1565 }
aoqi@0 1566
aoqi@0 1567 function look_for_prog
aoqi@0 1568 {
aoqi@0 1569 typeset path
aoqi@0 1570 typeset ppath
aoqi@0 1571 typeset progname=$1
aoqi@0 1572
aoqi@0 1573 DEVTOOLS=
aoqi@0 1574 OS=`uname`
aoqi@0 1575 if [[ "$OS" == "SunOS" ]]; then
aoqi@0 1576 DEVTOOLS="/java/devtools/`uname -p`/bin"
aoqi@0 1577 elif [[ "$OS" == "Linux" ]]; then
aoqi@0 1578 DEVTOOLS="/java/devtools/linux/bin"
aoqi@0 1579 fi
aoqi@0 1580
aoqi@0 1581 ppath=$PATH
aoqi@0 1582 ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
aoqi@0 1583 ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
aoqi@0 1584 ppath=$ppath:/opt/onbld/bin/`uname -p`
aoqi@0 1585 ppath=$ppath:/java/devtools/share/bin:$DEVTOOLS
aoqi@0 1586
aoqi@0 1587 PATH=$ppath prog=`whence $progname`
aoqi@0 1588 if [[ -n $prog ]]; then
aoqi@0 1589 print $prog
aoqi@0 1590 fi
aoqi@0 1591 }
aoqi@0 1592
aoqi@0 1593 #
aoqi@0 1594 # Find the parent for $1
aoqi@0 1595 #
aoqi@0 1596 function find_outrev
aoqi@0 1597 {
aoqi@0 1598 crev=$1
aoqi@0 1599 prev=`hg log -r $crev --template '{parents}\n'`
aoqi@0 1600 if [[ -z "$prev" ]]
aoqi@0 1601 then
aoqi@0 1602 # No specific parent means previous changeset is parent
aoqi@0 1603 prev=`expr $crev - 1`
aoqi@0 1604 else
aoqi@0 1605 # Format is either of the following two:
aoqi@0 1606 # 546:7df6fcf1183b
aoqi@0 1607 # 548:16f1915bb5cd 547:ffaa4e775815
aoqi@0 1608 prev=`echo $prev | sed -e 's/\([0-9]*\):.*/\1/'`
aoqi@0 1609 fi
aoqi@0 1610 print $prev
aoqi@0 1611 }
aoqi@0 1612
aoqi@0 1613 function extract_ssh_infos
aoqi@0 1614 {
aoqi@0 1615 CMD=$1
aoqi@0 1616 if expr "$CMD" : 'ssh://[^/]*@' >/dev/null; then
aoqi@0 1617 ssh_user=`echo $CMD | sed -e 's/ssh:\/\/\(.*\)@.*/\1/'`
aoqi@0 1618 ssh_host=`echo $CMD | sed -e 's/ssh:\/\/.*@\([^/]*\)\/.*/\1/'`
aoqi@0 1619 ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/.*@[^/]*\/\(.*\)/\1/'`
aoqi@0 1620 else
aoqi@0 1621 ssh_user=
aoqi@0 1622 ssh_host=`echo $CMD | sed -e 's/ssh:\/\/\([^/]*\)\/.*/\1/'`
aoqi@0 1623 ssh_dir=`echo $CMD | sed -e 's/ssh:\/\/[^/]*\/\(.*\)/\1/'`
aoqi@0 1624 fi
aoqi@0 1625
aoqi@0 1626 }
aoqi@0 1627
aoqi@0 1628 function build_old_new_mercurial
aoqi@0 1629 {
aoqi@0 1630 olddir=$1
aoqi@0 1631 newdir=$2
aoqi@0 1632 DIR=$3
aoqi@0 1633 F=$4
aoqi@0 1634 #
aoqi@0 1635 # new version of the file.
aoqi@0 1636 #
aoqi@0 1637 rm -rf $newdir/$DIR/$F
aoqi@0 1638 if [ -f $F ]; then
aoqi@0 1639 cp $F $newdir/$DIR/$F
aoqi@0 1640 fi
aoqi@0 1641
aoqi@0 1642 #
aoqi@0 1643 # Old version of the file.
aoqi@0 1644 #
aoqi@0 1645 rm -rf $olddir/$DIR/$F
aoqi@0 1646
aoqi@0 1647 if [ -n "$PWS" ]; then
aoqi@0 1648 if expr "$PWS" : 'ssh://' >/dev/null
aoqi@0 1649 then
aoqi@0 1650 extract_ssh_infos $PWS
aoqi@0 1651 if [ -n "$ssh_user" ]; then
aoqi@0 1652 parent="ssh -l $ssh_user $ssh_host hg -R $ssh_dir --cwd $ssh_dir"
aoqi@0 1653 else
aoqi@0 1654 parent="ssh $ssh_host hg -R $ssh_dir --cwd $ssh_dir"
aoqi@0 1655 fi
aoqi@0 1656 else
aoqi@0 1657 parent="hg -R $PWS --cwd $PWS"
aoqi@0 1658 fi
aoqi@0 1659 else
aoqi@0 1660 parent=""
aoqi@0 1661 fi
aoqi@0 1662
aoqi@0 1663 if [ -z "$rename" ]; then
aoqi@0 1664 if [ -n "$rflag" ]; then
aoqi@0 1665 parentrev=$PARENT_REV
aoqi@0 1666 elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then
aoqi@0 1667 parentrev=$OUTREV
aoqi@0 1668 else
aoqi@0 1669 if [[ -n $HG_BRANCH ]]; then
aoqi@0 1670 parentrev=$HG_BRANCH
aoqi@0 1671 else
aoqi@0 1672 parentrev="tip"
aoqi@0 1673 fi
aoqi@0 1674 fi
aoqi@0 1675
aoqi@0 1676 if [ -n "$parentrev" ]; then
aoqi@0 1677 if [ -z "$parent" ]; then
aoqi@0 1678 hg cat --rev $parentrev --output $olddir/$DIR/$F $F 2>/dev/null
aoqi@0 1679 else
aoqi@0 1680 # when specifying a workspace we have to provide
aoqi@0 1681 # the full path
aoqi@0 1682 $parent cat --rev $parentrev --output $olddir/$DIR/$F $DIR/$F 2>/dev/null
aoqi@0 1683 fi
aoqi@0 1684 fi
aoqi@0 1685 else
aoqi@0 1686 # It's a rename (or a move), or a copy, so let's make sure we move
aoqi@0 1687 # to the right directory first, then restore it once done
aoqi@0 1688 current_dir=`pwd`
aoqi@0 1689 hg_root=`hg root`
aoqi@0 1690 cd $CWS
aoqi@0 1691 if [ -n "$rflag" ]; then
aoqi@0 1692 parentrev=$PARENT_REV
aoqi@0 1693 elif [ "$HG_LIST_FROM_COMMIT" -eq 1 ]; then
aoqi@0 1694 parentrev=$OUTREV
aoqi@0 1695 fi
aoqi@0 1696 if [ -z "$parentrev" ]; then
aoqi@0 1697 parentrev=`hg log -l1 $PDIR/$PF | $AWK -F: '/changeset/ {print $2}'`
aoqi@0 1698 fi
aoqi@0 1699 if [ -n "$parentrev" ]; then
aoqi@0 1700 mkdir -p $olddir/$PDIR
aoqi@0 1701 if [ -z "$parent" ]; then
aoqi@0 1702 hg cat -R $hg_root --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null
aoqi@0 1703 else
aoqi@0 1704 $parent cat --rev $parentrev --output $olddir/$PDIR/$PF $PDIR/$PF 2>/dev/null
aoqi@0 1705 fi
aoqi@0 1706 fi
aoqi@0 1707 cd $current_dir
aoqi@0 1708 fi
aoqi@0 1709 }
aoqi@0 1710
aoqi@0 1711 function build_old_new
aoqi@0 1712 {
aoqi@0 1713 if [[ $SCM_MODE == "mercurial" ]]; then
aoqi@0 1714 build_old_new_mercurial $@
aoqi@0 1715 fi
aoqi@0 1716 }
aoqi@0 1717
aoqi@0 1718
aoqi@0 1719 #
aoqi@0 1720 # Usage message.
aoqi@0 1721 #
aoqi@0 1722 function usage
aoqi@0 1723 {
aoqi@0 1724 print "Usage:\twebrev [options]
aoqi@0 1725 webrev [options] ( <file> | - )
aoqi@0 1726
aoqi@0 1727 Options:
aoqi@0 1728 -v: Print the version of this tool.
aoqi@0 1729 -b: Do not ignore changes in the amount of white space.
aoqi@0 1730 -c <CR#>: Include link to CR (aka bugid) in the main page.
aoqi@0 1731 -i <filename>: Include <filename> in the index.html file.
aoqi@0 1732 -o <outdir>: Output webrev to specified directory.
aoqi@0 1733 -p <compare-against>: Use specified parent wkspc or basis for comparison
aoqi@0 1734 -u <username>: Use that username instead of 'guessing' one.
aoqi@0 1735 -m: Forces the use of Mercurial
aoqi@0 1736
aoqi@0 1737 Mercurial only options:
aoqi@0 1738 -r rev: Compare against a specified revision
aoqi@0 1739 -N: Skip 'hg outgoing', use only 'hg status'
aoqi@0 1740 -f: Use the forest extension
aoqi@0 1741
aoqi@0 1742 Arguments:
aoqi@0 1743 <file>: Optional file containing list of files to include in webrev
aoqi@0 1744 -: read list of files to include in webrev from standard input
aoqi@0 1745
aoqi@0 1746 Environment:
aoqi@0 1747 WDIR: Control the output directory.
aoqi@0 1748 WEBREV_BUGURL: Control the URL prefix for bugids.
aoqi@0 1749
aoqi@0 1750 "
aoqi@0 1751
aoqi@0 1752 exit 2
aoqi@0 1753 }
aoqi@0 1754
aoqi@0 1755 #
aoqi@0 1756 #
aoqi@0 1757 # Main program starts here
aoqi@0 1758 #
aoqi@0 1759 #
aoqi@0 1760 LANG="C"
aoqi@0 1761 LC_ALL="C"
aoqi@0 1762 export LANG LC_ALL
aoqi@0 1763 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
aoqi@0 1764
aoqi@0 1765 set +o noclobber
aoqi@0 1766
aoqi@0 1767 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
aoqi@0 1768 [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
aoqi@0 1769 [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
aoqi@0 1770 [[ -z $PERL ]] && PERL=`look_for_prog perl`
aoqi@0 1771 [[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
aoqi@0 1772 [[ -z $AWK ]] && AWK=`look_for_prog nawk`
aoqi@0 1773 [[ -z $AWK ]] && AWK=`look_for_prog gawk`
aoqi@0 1774 [[ -z $AWK ]] && AWK=`look_for_prog awk`
aoqi@0 1775 [[ -z $JAR ]] && JAR=`look_for_prog jar`
aoqi@0 1776 [[ -z $ZIP ]] && ZIP=`look_for_prog zip`
aoqi@0 1777 [[ -z $GETENT ]] && GETENT=`look_for_prog getent`
aoqi@0 1778 [[ -z $WGET ]] && WGET=`look_for_prog wget`
aoqi@0 1779
aoqi@0 1780 if uname | grep CYGWIN >/dev/null
aoqi@0 1781 then
aoqi@0 1782 ISWIN=1
aoqi@0 1783 # Under windows mercurial outputs '\' instead of '/'
aoqi@0 1784 FILTER="tr '\\\\' '/'"
aoqi@0 1785 else
aoqi@0 1786 FILTER="cat"
aoqi@0 1787 fi
aoqi@0 1788
aoqi@0 1789 if [[ ! -x $PERL ]]; then
aoqi@0 1790 print -u2 "Error: No perl interpreter found. Exiting."
aoqi@0 1791 exit 1
aoqi@0 1792 fi
aoqi@0 1793
aoqi@0 1794 #
aoqi@0 1795 # These aren't fatal, but we want to note them to the user.
aoqi@0 1796 #
aoqi@0 1797 # [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
aoqi@0 1798 # [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
aoqi@0 1799 # [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
aoqi@0 1800
aoqi@0 1801 # Declare global total counters.
aoqi@0 1802 integer TOTL TINS TDEL TMOD TUNC
aoqi@0 1803
aoqi@0 1804 flist_mode=
aoqi@0 1805 flist_file=
aoqi@0 1806 bflag=
aoqi@0 1807 iflag=
aoqi@0 1808 oflag=
aoqi@0 1809 pflag=
aoqi@0 1810 uflag=
aoqi@0 1811 Oflag=
aoqi@0 1812 rflag=
aoqi@0 1813 Nflag=
aoqi@0 1814 forestflag=
aoqi@0 1815 while getopts "c:i:o:p:r:u:mONvfb" opt
aoqi@0 1816 do
aoqi@0 1817 case $opt in
aoqi@0 1818 b) bflag=1;;
aoqi@0 1819
aoqi@0 1820 i) iflag=1
aoqi@0 1821 INCLUDE_FILE=$OPTARG;;
aoqi@0 1822
aoqi@0 1823 o) oflag=1
aoqi@0 1824 WDIR=$OPTARG;;
aoqi@0 1825
aoqi@0 1826 p) pflag=1
aoqi@0 1827 codemgr_parent=$OPTARG;;
aoqi@0 1828
aoqi@0 1829 u) uflag=1
aoqi@0 1830 username=$OPTARG;;
aoqi@0 1831
aoqi@0 1832 c) if [[ -z $CRID ]]; then
aoqi@0 1833 CRID=$OPTARG
aoqi@0 1834 else
aoqi@0 1835 CRID="$CRID $OPTARG"
aoqi@0 1836 fi;;
aoqi@0 1837
aoqi@0 1838 m) SCM_MODE="mercurial";;
aoqi@0 1839
aoqi@0 1840 O) Oflag=1;; # ignored (bugs are now all visible at bugs.openjdk.java.net)
aoqi@0 1841
aoqi@0 1842 N) Nflag=1;;
aoqi@0 1843
aoqi@0 1844 f) forestflag=1;;
aoqi@0 1845
aoqi@0 1846 r) rflag=1
aoqi@0 1847 PARENT_REV=$OPTARG;;
aoqi@0 1848
aoqi@0 1849 v) print "$0 version: $WEBREV_UPDATED";;
aoqi@0 1850
aoqi@0 1851
aoqi@0 1852 ?) usage;;
aoqi@0 1853 esac
aoqi@0 1854 done
aoqi@0 1855
aoqi@0 1856 FLIST=/tmp/$$.flist
aoqi@0 1857 HG_LIST_FROM_COMMIT=
aoqi@0 1858
aoqi@0 1859 if [[ -n $forestflag && -n $rflag ]]; then
aoqi@0 1860 print "The -r <rev> flag is incompatible with the use of forests"
aoqi@0 1861 exit 2
aoqi@0 1862 fi
aoqi@0 1863
aoqi@0 1864 #
aoqi@0 1865 # If this manually set as the parent, and it appears to be an earlier webrev,
aoqi@0 1866 # then note that fact and set the parent to the raw_files/new subdirectory.
aoqi@0 1867 #
aoqi@0 1868 if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
aoqi@0 1869 parent_webrev="$codemgr_parent"
aoqi@0 1870 codemgr_parent="$codemgr_parent/raw_files/new"
aoqi@0 1871 fi
aoqi@0 1872
aoqi@0 1873 shift $(($OPTIND - 1))
aoqi@0 1874
aoqi@0 1875 if [[ $1 == "-" ]]; then
aoqi@0 1876 cat > $FLIST
aoqi@0 1877 flist_mode="stdin"
aoqi@0 1878 flist_done=1
aoqi@0 1879 shift
aoqi@0 1880 elif [[ -n $1 ]]; then
aoqi@0 1881 if [[ ! -r $1 ]]; then
aoqi@0 1882 print -u2 "$1: no such file or not readable"
aoqi@0 1883 usage
aoqi@0 1884 fi
aoqi@0 1885 cat $1 > $FLIST
aoqi@0 1886 flist_mode="file"
aoqi@0 1887 flist_file=$1
aoqi@0 1888 flist_done=1
aoqi@0 1889 shift
aoqi@0 1890 else
aoqi@0 1891 flist_mode="auto"
aoqi@0 1892 fi
aoqi@0 1893
aoqi@0 1894 #
aoqi@0 1895 # Before we go on to further consider -l and -w, work out which SCM we think
aoqi@0 1896 # is in use.
aoqi@0 1897 #
aoqi@0 1898 if [[ -z $SCM_MODE ]]; then
aoqi@0 1899 SCM_MODE=`detect_scm $FLIST`
aoqi@0 1900 fi
aoqi@0 1901 if [[ $SCM_MODE == "unknown" ]]; then
aoqi@0 1902 print -u2 "Unable to determine SCM type currently in use."
aoqi@0 1903 print -u2 "For mercurial: webrev runs 'hg root'."
aoqi@0 1904 exit 1
aoqi@0 1905 fi
aoqi@0 1906
aoqi@0 1907 print -u2 " SCM detected: $SCM_MODE"
aoqi@0 1908
aoqi@0 1909
aoqi@0 1910 if [[ $SCM_MODE == "mercurial" ]]; then
aoqi@0 1911 #
aoqi@0 1912 # determine Workspace and parent workspace paths
aoqi@0 1913 #
aoqi@0 1914 CWS=`hg root | $FILTER`
aoqi@0 1915 if [[ -n $pflag && -z "$PWS" ]]; then
aoqi@0 1916 OUTPWS=$codemgr_parent
aoqi@0 1917 # Let's try to expand it if it's an alias defined in [paths]
aoqi@0 1918 tmp=`hg path $OUTPWS 2>/dev/null | $FILTER`
aoqi@0 1919 if [[ -n $tmp ]]; then
aoqi@0 1920 OUTPWS="$tmp"
aoqi@0 1921 fi
aoqi@0 1922 if [[ -n $rflag ]]; then
aoqi@0 1923 if expr "$codemgr_parent" : 'ssh://.*' >/dev/null; then
aoqi@0 1924 PWS=$codemgr_parent
aoqi@0 1925 else
aoqi@0 1926 PWS=`hg -R "$codemgr_parent" root 2>/dev/null | $FILTER`
aoqi@0 1927 fi
aoqi@0 1928 fi
aoqi@0 1929 fi
aoqi@0 1930 #
aoqi@0 1931 # OUTPWS is the parent repository to use when using 'hg outgoing'
aoqi@0 1932 #
aoqi@0 1933 if [[ -z $Nflag ]]; then
aoqi@0 1934 if [[ -n $forestflag ]]; then
aoqi@0 1935 #
aoqi@0 1936 # for forest we have to rely on properly set default and
aoqi@0 1937 # default-push because they can be different from the top one.
aoqi@0 1938 # unless of course it was explicitly specified with -p
aoqi@0 1939 if [[ -z $pflag ]]; then
aoqi@0 1940 OUTPWS=
aoqi@0 1941 fi
aoqi@0 1942 else
aoqi@0 1943 #
aoqi@0 1944 # Unfortunately mercurial is bugged and doesn't handle
aoqi@0 1945 # aliases correctly in 'hg path default'
aoqi@0 1946 # So let's do it ourselves. Sigh...
aoqi@0 1947 if [[ -z "$OUTPWS" ]]; then
aoqi@0 1948 OUTPWS=`grep default-push $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER`
aoqi@0 1949 fi
aoqi@0 1950 # Still empty, means no default-push
aoqi@0 1951 if [[ -z "$OUTPWS" ]]; then
aoqi@0 1952 OUTPWS=`grep 'default =' $CWS/.hg/hgrc | $AWK '{print $3}' | $FILTER`
aoqi@0 1953 fi
aoqi@0 1954 # Let's try to expand it if it's an alias defined in [paths]
aoqi@0 1955 tmp=`hg path $OUTPWS 2>/dev/null | $FILTER`
aoqi@0 1956 if [[ -n $tmp ]]; then
aoqi@0 1957 OUTPWS="$tmp"
aoqi@0 1958 fi
aoqi@0 1959 fi
aoqi@0 1960 fi
aoqi@0 1961 #
aoqi@0 1962 # OUTPWS may contain username:password, let's make sure we remove the
aoqi@0 1963 # sensitive information before we print out anything in the HTML
aoqi@0 1964 #
aoqi@0 1965 OUTPWS2=$OUTPWS
aoqi@0 1966 if [[ -n $OUTPWS ]]; then
aoqi@0 1967 if [[ `expr "$OUTPWS" : '.*://[^/]*@.*'` -gt 0 ]]; then
aoqi@0 1968 # Remove everything between '://' and '@'
aoqi@0 1969 OUTPWS2=`echo $OUTPWS | sed -e 's/\(.*:\/\/\).*@\(.*\)/\1\2/'`
aoqi@0 1970 fi
aoqi@0 1971 fi
aoqi@0 1972
aoqi@0 1973 if [[ -z $HG_BRANCH ]]; then
aoqi@0 1974 HG_BRANCH=`hg branch`
aoqi@0 1975 if [ "$HG_BRANCH" == "default" ]; then
aoqi@0 1976 #
aoqi@0 1977 # 'default' means no particular branch, so let's cancel that
aoqi@0 1978 #
aoqi@0 1979 HG_BRANCH=
aoqi@0 1980 fi
aoqi@0 1981 fi
aoqi@0 1982
aoqi@0 1983 if [[ -z $forestflag ]]; then
aoqi@0 1984 if [[ -z $Nflag ]]; then
aoqi@0 1985 #
aoqi@0 1986 # If no "-N", always do "hg outgoing" against parent
aoqi@0 1987 # repository to determine list of outgoing revisions.
aoqi@0 1988 #
aoqi@0 1989 ALL_CREV=`hg outgoing -q --template '{rev}\n' $OUTPWS | sort -n`
aoqi@0 1990 if [[ -n $ALL_CREV ]]; then
aoqi@0 1991 FIRST_CREV=`echo "$ALL_CREV" | head -1`
aoqi@0 1992 #
aoqi@0 1993 # If no "-r", choose revision to compare against by
aoqi@0 1994 # finding the latest revision not in the outgoing list.
aoqi@0 1995 #
aoqi@0 1996 if [[ -z $rflag ]]; then
aoqi@0 1997 OUTREV=`find_outrev "$FIRST_CREV"`
aoqi@0 1998 if [[ -n $OUTREV ]]; then
aoqi@0 1999 HG_LIST_FROM_COMMIT=1
aoqi@0 2000 fi
aoqi@0 2001 fi
aoqi@0 2002 fi
aoqi@0 2003 elif [[ -n $rflag ]]; then
aoqi@0 2004 #
aoqi@0 2005 # If skipping "hg outgoing" but still comparing against a
aoqi@0 2006 # specific revision (not the tip), set revision for comment
aoqi@0 2007 # accumulation.
aoqi@0 2008 #
aoqi@0 2009 FIRST_CREV=`hg log --rev $PARENT_REV --template '{rev}'`
aoqi@0 2010 FIRST_CREV=`expr $FIRST_CREV + 1`
aoqi@0 2011 fi
aoqi@0 2012 fi
aoqi@0 2013 #Let's check if a merge is needed, if so, issue a warning
aoqi@0 2014 PREV=`hg parent | grep '^tag:.*tip$'`
aoqi@0 2015 if [[ -z $PREV ]]; then
aoqi@0 2016 print "WARNING: parent rev is not tip. Maybe an update or merge is needed"
aoqi@0 2017 fi
aoqi@0 2018 fi
aoqi@0 2019
aoqi@0 2020 if [[ $flist_mode == "stdin" ]]; then
aoqi@0 2021 print -u2 " File list from: standard input"
aoqi@0 2022 elif [[ $flist_mode == "file" ]]; then
aoqi@0 2023 print -u2 " File list from: $flist_file"
aoqi@0 2024 fi
aoqi@0 2025
aoqi@0 2026 if [[ $# -gt 0 ]]; then
aoqi@0 2027 print -u2 "WARNING: unused arguments: $*"
aoqi@0 2028 fi
aoqi@0 2029
aoqi@0 2030 if [[ $SCM_MODE == "mercurial" ]]; then
aoqi@0 2031 if [[ -z $flist_done ]]; then
aoqi@0 2032 flist_from_mercurial $PWS
aoqi@0 2033 fi
aoqi@0 2034 fi
aoqi@0 2035
aoqi@0 2036 #
aoqi@0 2037 # If the user didn't specify a -i option, check to see if there is a
aoqi@0 2038 # webrev-info file in the workspace directory.
aoqi@0 2039 #
aoqi@0 2040 if [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
aoqi@0 2041 iflag=1
aoqi@0 2042 INCLUDE_FILE="$CWS/webrev-info"
aoqi@0 2043 fi
aoqi@0 2044
aoqi@0 2045 if [[ -n $iflag ]]; then
aoqi@0 2046 if [[ ! -r $INCLUDE_FILE ]]; then
aoqi@0 2047 print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
aoqi@0 2048 "not readable."
aoqi@0 2049 exit 1
aoqi@0 2050 else
aoqi@0 2051 #
aoqi@0 2052 # $INCLUDE_FILE may be a relative path, and the script alters
aoqi@0 2053 # PWD, so we just stash a copy in /tmp.
aoqi@0 2054 #
aoqi@0 2055 cp $INCLUDE_FILE /tmp/$$.include
aoqi@0 2056 fi
aoqi@0 2057 fi
aoqi@0 2058
aoqi@0 2059 #
aoqi@0 2060 # Output directory.
aoqi@0 2061 #
aoqi@0 2062 if [[ -z $WDIR ]]; then
aoqi@0 2063 WDIR=$CWS/webrev
aoqi@0 2064 else
aoqi@0 2065 # If the output directory doesn't end with '/webrev' or '/webrev/'
aoqi@0 2066 # then add '/webrev'. This is for backward compatibility
aoqi@0 2067 if ! expr $WDIR : '.*/webrev/\?$' >/dev/null
aoqi@0 2068 then
aoqi@0 2069 WDIR=$WDIR/webrev
aoqi@0 2070 fi
aoqi@0 2071 fi
aoqi@0 2072 # WDIR=${WDIR:-$CWS/webrev}
aoqi@0 2073
aoqi@0 2074 #
aoqi@0 2075 # Name of the webrev, derived from the workspace name; in the
aoqi@0 2076 # future this could potentially be an option.
aoqi@0 2077 #
aoqi@0 2078 # Let's keep what's after the last '/'
aoqi@0 2079 WNAME=${CWS##*/}
aoqi@0 2080
aoqi@0 2081 #
aoqi@0 2082 # If WDIR doesn't start with '/' or 'x:' prepend the current dir
aoqi@0 2083 #
aoqi@0 2084 if [ ${WDIR%%/*} ]; then
aoqi@0 2085 if [[ -n $ISWIN ]]; then
aoqi@0 2086 if [ ${WDIR%%[A-Za-z]:*} ]; then
aoqi@0 2087 WDIR=$PWD/$WDIR
aoqi@0 2088 fi
aoqi@0 2089 else
aoqi@0 2090 WDIR=$PWD/$WDIR
aoqi@0 2091 fi
aoqi@0 2092 fi
aoqi@0 2093
aoqi@0 2094 if [[ ! -d $WDIR ]]; then
aoqi@0 2095 mkdir -p $WDIR
aoqi@0 2096 [[ $? != 0 ]] && exit 1
aoqi@0 2097 fi
aoqi@0 2098
aoqi@0 2099 #
aoqi@0 2100 # Summarize what we're going to do.
aoqi@0 2101 #
aoqi@0 2102 print " Workspace: $CWS"
aoqi@0 2103 if [[ -n $parent_webrev ]]; then
aoqi@0 2104 print "Compare against: webrev at $parent_webrev"
aoqi@0 2105 elif [[ -n $OUTPWS2 ]]; then
aoqi@0 2106 print "Compare against: $OUTPWS2"
aoqi@0 2107 fi
aoqi@0 2108 if [[ -n $HG_BRANCH ]]; then
aoqi@0 2109 print " Branch: $HG_BRANCH"
aoqi@0 2110 fi
aoqi@0 2111 if [[ -n $rflag ]]; then
aoqi@0 2112 print "Compare against version: $PARENT_REV"
aoqi@0 2113 fi
aoqi@0 2114 [[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE"
aoqi@0 2115 print " Output to: $WDIR"
aoqi@0 2116
aoqi@0 2117 #
aoqi@0 2118 # Save the file list in the webrev dir
aoqi@0 2119 #
aoqi@0 2120 [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
aoqi@0 2121
aoqi@0 2122 #
aoqi@0 2123 # Bug IDs will be replaced by a URL. Order of precedence
aoqi@0 2124 # is: default location, $WEBREV_BUGURL
aoqi@0 2125 #
aoqi@0 2126 BUGURL='https://bugs.openjdk.java.net/browse/'
aoqi@0 2127 [[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
aoqi@0 2128 IDPREFIX='JDK-'
aoqi@0 2129
aoqi@0 2130
aoqi@0 2131 rm -f $WDIR/$WNAME.patch
aoqi@0 2132 rm -f $WDIR/$WNAME.changeset
aoqi@0 2133 rm -f $WDIR/$WNAME.ps
aoqi@0 2134 rm -f $WDIR/$WNAME.pdf
aoqi@0 2135
aoqi@0 2136 touch $WDIR/$WNAME.patch
aoqi@0 2137
aoqi@0 2138 print " Output Files:"
aoqi@0 2139
aoqi@0 2140 #
aoqi@0 2141 # Clean up the file list: Remove comments, blank lines and env variables.
aoqi@0 2142 #
aoqi@0 2143 sed -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean
aoqi@0 2144 FLIST=/tmp/$$.flist.clean
aoqi@0 2145
aoqi@0 2146 #
aoqi@0 2147 # Clean up residual raw files
aoqi@0 2148 #
aoqi@0 2149 if [ -d $WDIR/raw_files ]; then
aoqi@0 2150 rm -rf $WDIR/raw_files 2>/dev/null
aoqi@0 2151 fi
aoqi@0 2152
aoqi@0 2153 #
aoqi@0 2154 # Should we ignore changes in white spaces when generating diffs?
aoqi@0 2155 #
aoqi@0 2156 if [[ -n $bflag ]]; then
aoqi@0 2157 DIFFOPTS="-t"
aoqi@0 2158 else
aoqi@0 2159 DIFFOPTS="-bt"
aoqi@0 2160 fi
aoqi@0 2161 #
aoqi@0 2162 # First pass through the files: generate the per-file webrev HTML-files.
aoqi@0 2163 #
aoqi@0 2164 while read LINE
aoqi@0 2165 do
aoqi@0 2166 set - $LINE
aoqi@0 2167 P=$1
aoqi@0 2168
aoqi@0 2169 if [[ $1 == "Revision:" ]]; then
aoqi@0 2170 OUTREV=$2
aoqi@0 2171 continue
aoqi@0 2172 fi
aoqi@0 2173 #
aoqi@0 2174 # Normally, each line in the file list is just a pathname of a
aoqi@0 2175 # file that has been modified or created in the child. A file
aoqi@0 2176 # that is renamed in the child workspace has two names on the
aoqi@0 2177 # line: new name followed by the old name.
aoqi@0 2178 #
aoqi@0 2179 oldname=""
aoqi@0 2180 oldpath=""
aoqi@0 2181 rename=
aoqi@0 2182 if [[ $# -eq 2 ]]; then
aoqi@0 2183 PP=$2 # old filename
aoqi@0 2184 oldname=" (was $PP)"
aoqi@0 2185 oldpath="$PP"
aoqi@0 2186 rename=1
aoqi@0 2187 PDIR=${PP%/*}
aoqi@0 2188 if [[ $PDIR == $PP ]]; then
aoqi@0 2189 PDIR="." # File at root of workspace
aoqi@0 2190 fi
aoqi@0 2191
aoqi@0 2192 PF=${PP##*/}
aoqi@0 2193
aoqi@0 2194 DIR=${P%/*}
aoqi@0 2195 if [[ $DIR == $P ]]; then
aoqi@0 2196 DIR="." # File at root of workspace
aoqi@0 2197 fi
aoqi@0 2198
aoqi@0 2199 F=${P##*/}
aoqi@0 2200 else
aoqi@0 2201 DIR=${P%/*}
aoqi@0 2202 if [[ "$DIR" == "$P" ]]; then
aoqi@0 2203 DIR="." # File at root of workspace
aoqi@0 2204 fi
aoqi@0 2205
aoqi@0 2206 F=${P##*/}
aoqi@0 2207
aoqi@0 2208 PP=$P
aoqi@0 2209 PDIR=$DIR
aoqi@0 2210 PF=$F
aoqi@0 2211 fi
aoqi@0 2212
aoqi@0 2213 # Make the webrev directory if necessary as it may have been
aoqi@0 2214 # removed because it was empty
aoqi@0 2215 if [ ! -d $CWS/$DIR ]; then
aoqi@0 2216 mkdir -p $CWS/$DIR
aoqi@0 2217 fi
aoqi@0 2218
aoqi@0 2219 COMM=`getcomments html $P $PP`
aoqi@0 2220
aoqi@0 2221 print "\t$P$oldname\n\t\t\c"
aoqi@0 2222
aoqi@0 2223 # Make the webrev mirror directory if necessary
aoqi@0 2224 mkdir -p $WDIR/$DIR
aoqi@0 2225
aoqi@0 2226 # cd to the directory so the names are short
aoqi@0 2227 cd $CWS/$DIR
aoqi@0 2228
aoqi@0 2229 #
aoqi@0 2230 # We stash old and new files into parallel directories in /tmp
aoqi@0 2231 # and do our diffs there. This makes it possible to generate
aoqi@0 2232 # clean looking diffs which don't have absolute paths present.
aoqi@0 2233 #
aoqi@0 2234 olddir=$WDIR/raw_files/old
aoqi@0 2235 newdir=$WDIR/raw_files/new
aoqi@0 2236 mkdir -p $olddir
aoqi@0 2237 mkdir -p $newdir
aoqi@0 2238 mkdir -p $olddir/$PDIR
aoqi@0 2239 mkdir -p $newdir/$DIR
aoqi@0 2240
aoqi@0 2241 build_old_new $olddir $newdir $DIR $F
aoqi@0 2242
aoqi@0 2243 if [[ ! -f $F && ! -f $olddir/$DIR/$F ]]; then
aoqi@0 2244 print "*** Error: file not in parent or child"
aoqi@0 2245 continue
aoqi@0 2246 fi
aoqi@0 2247
aoqi@0 2248 cd $WDIR/raw_files
aoqi@0 2249 ofile=old/$PDIR/$PF
aoqi@0 2250 nfile=new/$DIR/$F
aoqi@0 2251
aoqi@0 2252 mv_but_nodiff=
aoqi@0 2253 cmp $ofile $nfile > /dev/null 2>&1
aoqi@0 2254 if [[ $? == 0 && $rename == 1 ]]; then
aoqi@0 2255 mv_but_nodiff=1
aoqi@0 2256 fi
aoqi@0 2257
aoqi@0 2258 #
aoqi@0 2259 # Cleaning up
aoqi@0 2260 #
aoqi@0 2261 rm -f $WDIR/$DIR/$F.cdiff.html
aoqi@0 2262 rm -f $WDIR/$DIR/$F.udiff.html
aoqi@0 2263 rm -f $WDIR/$DIR/$F.wdiff.html
aoqi@0 2264 rm -f $WDIR/$DIR/$F.sdiff.html
aoqi@0 2265 rm -f $WDIR/$DIR/$F-.html
aoqi@0 2266 rm -f $WDIR/$DIR/$F.html
aoqi@0 2267
aoqi@0 2268 its_a_jar=
aoqi@0 2269 if expr $F : '.*\.jar' \| $F : '.*\.zip' >/dev/null; then
aoqi@0 2270 its_a_jar=1
aoqi@0 2271 # It's a JAR or ZIP file, let's do it differently
aoqi@0 2272 if [[ -z $JAR ]]; then
aoqi@0 2273 print "No access to jar, so can't produce diffs for jar or zip files"
aoqi@0 2274 else
aoqi@0 2275 if [ -f $ofile ]; then
aoqi@0 2276 $JAR -tvf $ofile >"$ofile".lst
aoqi@0 2277 fi
aoqi@0 2278 if [ -f $nfile ]; then
aoqi@0 2279 $JAR -tvf $nfile >"$nfile".lst
aoqi@0 2280 fi
aoqi@0 2281
aoqi@0 2282 if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
aoqi@0 2283
aoqi@0 2284 ${CDIFFCMD:-diff -bt -C 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.cdiff
aoqi@0 2285 diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
aoqi@0 2286 > $WDIR/$DIR/$F.cdiff.html
aoqi@0 2287 print " cdiffs\c"
aoqi@0 2288
aoqi@0 2289 ${UDIFFCMD:-diff -bt -U 5} $ofile.lst $nfile.lst > $WDIR/$DIR/$F.udiff
aoqi@0 2290 diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
aoqi@0 2291 > $WDIR/$DIR/$F.udiff.html
aoqi@0 2292
aoqi@0 2293 print " udiffs\c"
aoqi@0 2294
aoqi@0 2295 if [[ -x $WDIFF ]]; then
aoqi@0 2296 $WDIFF -c "$COMM" \
aoqi@0 2297 -t "$WNAME Wdiff $DIR/$F" $ofile.lst $nfile.lst > \
aoqi@0 2298 $WDIR/$DIR/$F.wdiff.html 2>/dev/null
aoqi@0 2299 if [[ $? -eq 0 ]]; then
aoqi@0 2300 print " wdiffs\c"
aoqi@0 2301 else
aoqi@0 2302 print " wdiffs[fail]\c"
aoqi@0 2303 fi
aoqi@0 2304 fi
aoqi@0 2305
aoqi@0 2306 sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
aoqi@0 2307 > $WDIR/$DIR/$F.sdiff.html
aoqi@0 2308 print " sdiffs\c"
aoqi@0 2309
aoqi@0 2310 print " frames\c"
aoqi@0 2311
aoqi@0 2312 rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
aoqi@0 2313
aoqi@0 2314 difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count
aoqi@0 2315
aoqi@0 2316 elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
aoqi@0 2317 # renamed file: may also have differences
aoqi@0 2318 difflines $ofile.lst $nfile.lst > $WDIR/$DIR/$F.count
aoqi@0 2319 elif [[ -f $nfile ]]; then
aoqi@0 2320 # new file: count added lines
aoqi@0 2321 difflines /dev/null $nfile.lst > $WDIR/$DIR/$F.count
aoqi@0 2322 elif [[ -f $ofile ]]; then
aoqi@0 2323 # old file: count deleted lines
aoqi@0 2324 difflines $ofile.lst /dev/null > $WDIR/$DIR/$F.count
aoqi@0 2325 fi
aoqi@0 2326 fi
aoqi@0 2327 else
aoqi@0 2328
aoqi@0 2329 #
aoqi@0 2330 # If we have old and new versions of the file then run the
aoqi@0 2331 # appropriate diffs. This is complicated by a couple of factors:
aoqi@0 2332 #
aoqi@0 2333 # - renames must be handled specially: we emit a 'remove'
aoqi@0 2334 # diff and an 'add' diff
aoqi@0 2335 # - new files and deleted files must be handled specially
aoqi@0 2336 # - Solaris patch(1m) can't cope with file creation
aoqi@0 2337 # (and hence renames) as of this writing.
aoqi@0 2338 # - To make matters worse, gnu patch doesn't interpret the
aoqi@0 2339 # output of Solaris diff properly when it comes to
aoqi@0 2340 # adds and deletes. We need to do some "cleansing"
aoqi@0 2341 # transformations:
aoqi@0 2342 # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@
aoqi@0 2343 # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@
aoqi@0 2344 #
aoqi@0 2345 cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
aoqi@0 2346 cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
aoqi@0 2347
aoqi@0 2348 if [[ ! "$HG_LIST_FROM_COMMIT" -eq 1 || ! $flist_mode == "auto" ]];
aoqi@0 2349 then
aoqi@0 2350 # Only need to generate a patch file here if there are no commits in outgoing
aoqi@0 2351 # or if we've specified a file list
aoqi@0 2352 rm -f $WDIR/$DIR/$F.patch
aoqi@0 2353 if [[ -z $rename ]]; then
aoqi@0 2354 if [ ! -f $ofile ]; then
aoqi@0 2355 diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
aoqi@0 2356 > $WDIR/$DIR/$F.patch
aoqi@0 2357 elif [ ! -f $nfile ]; then
aoqi@0 2358 diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
aoqi@0 2359 > $WDIR/$DIR/$F.patch
aoqi@0 2360 else
aoqi@0 2361 diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
aoqi@0 2362 fi
aoqi@0 2363 else
aoqi@0 2364 diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
aoqi@0 2365 > $WDIR/$DIR/$F.patch
aoqi@0 2366
aoqi@0 2367 diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
aoqi@0 2368 >> $WDIR/$DIR/$F.patch
aoqi@0 2369
aoqi@0 2370 fi
aoqi@0 2371
aoqi@0 2372
aoqi@0 2373 #
aoqi@0 2374 # Tack the patch we just made onto the accumulated patch for the
aoqi@0 2375 # whole wad.
aoqi@0 2376 #
aoqi@0 2377 cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
aoqi@0 2378 fi
aoqi@0 2379
aoqi@0 2380 print " patch\c"
aoqi@0 2381
aoqi@0 2382 if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
aoqi@0 2383
aoqi@0 2384 ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
aoqi@0 2385 diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
aoqi@0 2386 > $WDIR/$DIR/$F.cdiff.html
aoqi@0 2387 print " cdiffs\c"
aoqi@0 2388
aoqi@0 2389 ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
aoqi@0 2390 diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
aoqi@0 2391 > $WDIR/$DIR/$F.udiff.html
aoqi@0 2392
aoqi@0 2393 print " udiffs\c"
aoqi@0 2394
aoqi@0 2395 if [[ -x $WDIFF ]]; then
aoqi@0 2396 $WDIFF -c "$COMM" \
aoqi@0 2397 -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
aoqi@0 2398 $WDIR/$DIR/$F.wdiff.html 2>/dev/null
aoqi@0 2399 if [[ $? -eq 0 ]]; then
aoqi@0 2400 print " wdiffs\c"
aoqi@0 2401 else
aoqi@0 2402 print " wdiffs[fail]\c"
aoqi@0 2403 fi
aoqi@0 2404 fi
aoqi@0 2405
aoqi@0 2406 sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
aoqi@0 2407 > $WDIR/$DIR/$F.sdiff.html
aoqi@0 2408 print " sdiffs\c"
aoqi@0 2409
aoqi@0 2410 print " frames\c"
aoqi@0 2411
aoqi@0 2412 rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
aoqi@0 2413
aoqi@0 2414 difflines $ofile $nfile > $WDIR/$DIR/$F.count
aoqi@0 2415
aoqi@0 2416 elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
aoqi@0 2417 # renamed file: may also have differences
aoqi@0 2418 difflines $ofile $nfile > $WDIR/$DIR/$F.count
aoqi@0 2419 elif [[ -f $nfile ]]; then
aoqi@0 2420 # new file: count added lines
aoqi@0 2421 difflines /dev/null $nfile > $WDIR/$DIR/$F.count
aoqi@0 2422 elif [[ -f $ofile ]]; then
aoqi@0 2423 # old file: count deleted lines
aoqi@0 2424 difflines $ofile /dev/null > $WDIR/$DIR/$F.count
aoqi@0 2425 fi
aoqi@0 2426 fi
aoqi@0 2427 #
aoqi@0 2428 # Now we generate the postscript for this file. We generate diffs
aoqi@0 2429 # only in the event that there is delta, or the file is new (it seems
aoqi@0 2430 # tree-killing to print out the contents of deleted files).
aoqi@0 2431 #
aoqi@0 2432 if [[ -f $nfile ]]; then
aoqi@0 2433 ocr=$ofile
aoqi@0 2434 [[ ! -f $ofile ]] && ocr=/dev/null
aoqi@0 2435
aoqi@0 2436 if [[ -z $mv_but_nodiff ]]; then
aoqi@0 2437 textcomm=`getcomments text $P $PP`
aoqi@0 2438 if [[ -x $CODEREVIEW ]]; then
aoqi@0 2439 $CODEREVIEW -y "$textcomm" \
aoqi@0 2440 -e $ocr $nfile \
aoqi@0 2441 > /tmp/$$.psfile 2>/dev/null &&
aoqi@0 2442 cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
aoqi@0 2443 if [[ $? -eq 0 ]]; then
aoqi@0 2444 print " ps\c"
aoqi@0 2445 else
aoqi@0 2446 print " ps[fail]\c"
aoqi@0 2447 fi
aoqi@0 2448 fi
aoqi@0 2449 fi
aoqi@0 2450 fi
aoqi@0 2451
aoqi@0 2452 if [[ -f $ofile && -z $mv_but_nodiff ]]; then
aoqi@0 2453 if [[ -n $its_a_jar ]]; then
aoqi@0 2454 source_to_html Old $P < $ofile.lst > $WDIR/$DIR/$F-.html
aoqi@0 2455 else
aoqi@0 2456 source_to_html Old $P < $ofile > $WDIR/$DIR/$F-.html
aoqi@0 2457 fi
aoqi@0 2458 print " old\c"
aoqi@0 2459 fi
aoqi@0 2460
aoqi@0 2461 if [[ -f $nfile ]]; then
aoqi@0 2462 if [[ -n $its_a_jar ]]; then
aoqi@0 2463 source_to_html New $P < $nfile.lst > $WDIR/$DIR/$F.html
aoqi@0 2464 else
aoqi@0 2465 source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
aoqi@0 2466 fi
aoqi@0 2467 print " new\c"
aoqi@0 2468 fi
aoqi@0 2469
aoqi@0 2470 print
aoqi@0 2471 done < $FLIST
aoqi@0 2472
aoqi@0 2473 # Create the new style mercurial patch here using hg export -r [all-revs] -g -o $CHANGESETPATH
aoqi@0 2474 if [[ $SCM_MODE == "mercurial" ]]; then
aoqi@0 2475 if [[ "$HG_LIST_FROM_COMMIT" -eq 1 && $flist_mode == "auto" ]]; then
aoqi@0 2476 EXPORTCHANGESET="$WNAME.changeset"
aoqi@0 2477 CHANGESETPATH=${WDIR}/${EXPORTCHANGESET}
aoqi@0 2478 rm -f $CHANGESETPATH
aoqi@0 2479 touch $CHANGESETPATH
aoqi@0 2480 if [[ -n $ALL_CREV ]]; then
aoqi@0 2481 rev_opt=
aoqi@0 2482 for rev in $ALL_CREV; do
aoqi@0 2483 rev_opt="$rev_opt --rev $rev"
aoqi@0 2484 done
aoqi@0 2485 elif [[ -n $FIRST_CREV ]]; then
aoqi@0 2486 rev_opt="--rev $FIRST_CREV"
aoqi@0 2487 fi
aoqi@0 2488
aoqi@0 2489 if [[ -n $rev_opt ]]; then
aoqi@0 2490 (cd $CWS;hg export -g $rev_opt -o $CHANGESETPATH)
aoqi@0 2491 echo "Created changeset: $CHANGESETPATH" 1>&2
aoqi@0 2492 # Use it in place of the jdk.patch created above
aoqi@0 2493 rm -f $WDIR/$WNAME.patch
aoqi@0 2494 fi
aoqi@0 2495 set +x
aoqi@0 2496 fi
aoqi@0 2497 fi
aoqi@0 2498
aoqi@0 2499 frame_nav_js > $WDIR/ancnav.js
aoqi@0 2500 frame_navigation > $WDIR/ancnav.html
aoqi@0 2501
aoqi@0 2502 if [[ -f $WDIR/$WNAME.ps && -x $CODEREVIEW && -x $PS2PDF ]]; then
aoqi@0 2503 print " Generating PDF: \c"
aoqi@0 2504 fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
aoqi@0 2505 print "Done."
aoqi@0 2506 fi
aoqi@0 2507
aoqi@0 2508 # Now build the index.html file that contains
aoqi@0 2509 # links to the source files and their diffs.
aoqi@0 2510
aoqi@0 2511 cd $CWS
aoqi@0 2512
aoqi@0 2513 # Save total changed lines for Code Inspection.
aoqi@0 2514 print "$TOTL" > $WDIR/TotalChangedLines
aoqi@0 2515
aoqi@0 2516 print " index.html: \c"
aoqi@0 2517 INDEXFILE=$WDIR/index.html
aoqi@0 2518 exec 3<&1 # duplicate stdout to FD3.
aoqi@0 2519 exec 1<&- # Close stdout.
aoqi@0 2520 exec > $INDEXFILE # Open stdout to index file.
aoqi@0 2521
aoqi@0 2522 print "$HTML<head>"
aoqi@0 2523 print "<meta name=\"scm\" content=\"$SCM_MODE\" />"
aoqi@0 2524 print "$STDHEAD"
aoqi@0 2525 print "<title>$WNAME</title>"
aoqi@0 2526 print "</head>"
aoqi@0 2527 print "<body id=\"SUNWwebrev\">"
aoqi@0 2528 print "<div class=\"summary\">"
aoqi@0 2529 print "<h2>Code Review for $WNAME</h2>"
aoqi@0 2530
aoqi@0 2531 print "<table>"
aoqi@0 2532
aoqi@0 2533 if [[ -z $uflag ]]; then
aoqi@0 2534 if [[ $SCM_MODE == "mercurial" ]]; then
aoqi@0 2535 #
aoqi@0 2536 # Let's try to extract the user name from the .hgrc file
aoqi@0 2537 #
aoqi@0 2538 username=`grep '^username' $HOME/.hgrc | sed 's/^username[ ]*=[ ]*\(.*\)/\1/'`
aoqi@0 2539 fi
aoqi@0 2540
aoqi@0 2541 if [[ -z $username ]]; then
aoqi@0 2542 #
aoqi@0 2543 # Figure out the username and gcos name. To maintain compatibility
aoqi@0 2544 # with passwd(4), we must support '&' substitutions.
aoqi@0 2545 #
aoqi@0 2546 username=`id | cut -d '(' -f 2 | cut -d ')' -f 1`
aoqi@0 2547 if [[ -x $GETENT ]]; then
aoqi@0 2548 realname=`$GETENT passwd $username | cut -d':' -f 5 | cut -d ',' -f 1`
aoqi@0 2549 fi
aoqi@0 2550 userupper=`print "$username" | sed 's/\<./\u&/g'`
aoqi@0 2551 realname=`print $realname | sed s/\&/$userupper/`
aoqi@0 2552 fi
aoqi@0 2553 fi
aoqi@0 2554
aoqi@0 2555 date="on `date`"
aoqi@0 2556
aoqi@0 2557 if [[ -n "$username" && -n "$realname" ]]; then
aoqi@0 2558 print "<tr><th>Prepared by:</th>"
aoqi@0 2559 print "<td>$realname ($username) $date</td></tr>"
aoqi@0 2560 elif [[ -n "$username" ]]; then
aoqi@0 2561 print "<tr><th>Prepared by:</th><td>$username $date</td></tr>"
aoqi@0 2562 fi
aoqi@0 2563
aoqi@0 2564 print "<tr><th>Workspace:</th><td>$CWS</td></tr>"
aoqi@0 2565 if [[ -n $parent_webrev ]]; then
aoqi@0 2566 print "<tr><th>Compare against:</th><td>"
aoqi@0 2567 print "webrev at $parent_webrev"
aoqi@0 2568 else
aoqi@0 2569 if [[ -n $OUTPWS2 ]]; then
aoqi@0 2570 print "<tr><th>Compare against:</th><td>"
aoqi@0 2571 print "$OUTPWS2"
aoqi@0 2572 fi
aoqi@0 2573 fi
aoqi@0 2574 print "</td></tr>"
aoqi@0 2575 if [[ -n $rflag ]]; then
aoqi@0 2576 print "<tr><th>Compare against version:</th><td>$PARENT_REV</td></tr>"
aoqi@0 2577 elif [[ -n $OUTREV ]]; then
aoqi@0 2578 if [[ -z $forestflag ]]; then
aoqi@0 2579 print "<tr><th>Compare against version:</th><td>$OUTREV</td></tr>"
aoqi@0 2580 fi
aoqi@0 2581 fi
aoqi@0 2582 if [[ -n $HG_BRANCH ]]; then
aoqi@0 2583 print "<tr><th>Branch:</th><td>$HG_BRANCH</td></tr>"
aoqi@0 2584 fi
aoqi@0 2585
aoqi@0 2586 print "<tr><th>Summary of changes:</th><td>"
aoqi@0 2587 printCI $TOTL $TINS $TDEL $TMOD $TUNC
aoqi@0 2588 print "</td></tr>"
aoqi@0 2589
aoqi@0 2590 if [[ -f $WDIR/$WNAME.patch ]]; then
aoqi@0 2591 print "<tr><th>Patch of changes:</th><td>"
aoqi@0 2592 print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
aoqi@0 2593 elif [[ -f $CHANGESETPATH ]]; then
aoqi@0 2594 print "<tr><th>Changeset:</th><td>"
aoqi@0 2595 print "<a href=\"$EXPORTCHANGESET\">$EXPORTCHANGESET</a></td></tr>"
aoqi@0 2596 fi
aoqi@0 2597
aoqi@0 2598 if [[ -f $WDIR/$WNAME.pdf ]]; then
aoqi@0 2599 print "<tr><th>Printable review:</th><td>"
aoqi@0 2600 print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
aoqi@0 2601 fi
aoqi@0 2602
aoqi@0 2603 if [[ -n "$iflag" ]]; then
aoqi@0 2604 print "<tr><th>Author comments:</th><td><div>"
aoqi@0 2605 cat /tmp/$$.include
aoqi@0 2606 print "</div></td></tr>"
aoqi@0 2607 fi
aoqi@0 2608 # Add links to referenced CRs, if any
aoqi@0 2609 # URL has a <title> like:
aoqi@0 2610 # <title>[#JDK-8024688] b106-lambda: j.u.Map.merge doesn&#39;t work as specified if contains key:null pair - Java Bug System</title>
aoqi@0 2611 # we format this to:
aoqi@0 2612 # JDK-8024688: b106-lambda: j.u.Map.merge doesn't work as specified if contains key:null pair
aoqi@0 2613 if [[ -n $CRID ]]; then
aoqi@0 2614 for id in $CRID
aoqi@0 2615 do
aoqi@0 2616 #add "JDK-" to raw bug id for openjdk.java.net links.
aoqi@0 2617 id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'`
aoqi@0 2618
aoqi@0 2619 print "<tr><th>Bug id:</th><td>"
aoqi@0 2620 url="${BUGURL}${id}"
aoqi@0 2621
aoqi@0 2622 if [[ -n $WGET ]]; then
aoqi@0 2623 msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '<title>' | sed 's/<title>\[#\(.*\)\] \(.*\) - Java Bug System<\/title>/\1 : \2/' | html_dequote | html_quote`
aoqi@0 2624 fi
aoqi@0 2625 if [[ -z $msg ]]; then
aoqi@0 2626 msg="${id}"
aoqi@0 2627 fi
aoqi@0 2628
aoqi@0 2629 print "<a href=\"$url\">$msg</a>"
aoqi@0 2630
aoqi@0 2631 print "</td></tr>"
aoqi@0 2632 done
aoqi@0 2633 fi
aoqi@0 2634 print "<tr><th>Legend:</th><td>"
aoqi@0 2635 print "<b>Modified file</b><br><font color=red><b>Deleted file</b></font><br><font color=green><b>New file</b></font></td></tr>"
aoqi@0 2636 print "</table>"
aoqi@0 2637 print "</div>"
aoqi@0 2638
aoqi@0 2639 #
aoqi@0 2640 # Second pass through the files: generate the rest of the index file
aoqi@0 2641 #
aoqi@0 2642 while read LINE
aoqi@0 2643 do
aoqi@0 2644 set - $LINE
aoqi@0 2645 if [[ $1 == "Revision:" ]]; then
aoqi@0 2646 FIRST_CREV=`expr $3 + 1`
aoqi@0 2647 continue
aoqi@0 2648 fi
aoqi@0 2649 P=$1
aoqi@0 2650
aoqi@0 2651 if [[ $# == 2 ]]; then
aoqi@0 2652 PP=$2
aoqi@0 2653 oldname=" <i>(was $PP)</i>"
aoqi@0 2654
aoqi@0 2655 else
aoqi@0 2656 PP=$P
aoqi@0 2657 oldname=""
aoqi@0 2658 fi
aoqi@0 2659
aoqi@0 2660 DIR=${P%/*}
aoqi@0 2661 if [[ $DIR == $P ]]; then
aoqi@0 2662 DIR="." # File at root of workspace
aoqi@0 2663 fi
aoqi@0 2664
aoqi@0 2665 # Avoid processing the same file twice.
aoqi@0 2666 # It's possible for renamed files to
aoqi@0 2667 # appear twice in the file list
aoqi@0 2668
aoqi@0 2669 F=$WDIR/$P
aoqi@0 2670
aoqi@0 2671 print "<p><code>"
aoqi@0 2672
aoqi@0 2673 # If there's a diffs file, make diffs links
aoqi@0 2674
aoqi@0 2675 NODIFFS=
aoqi@0 2676 if [[ -f $F.cdiff.html ]]; then
aoqi@0 2677 print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
aoqi@0 2678 print "<a href=\"$P.udiff.html\">Udiffs</a>"
aoqi@0 2679
aoqi@0 2680 if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
aoqi@0 2681 print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
aoqi@0 2682 fi
aoqi@0 2683
aoqi@0 2684 print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
aoqi@0 2685
aoqi@0 2686 print "<a href=\"$P.frames.html\">Frames</a>"
aoqi@0 2687 else
aoqi@0 2688 NODIFFS=1
aoqi@0 2689 print " ------ ------ ------"
aoqi@0 2690
aoqi@0 2691 if [[ -x $WDIFF ]]; then
aoqi@0 2692 print " ------"
aoqi@0 2693 fi
aoqi@0 2694
aoqi@0 2695 print " ------"
aoqi@0 2696 fi
aoqi@0 2697
aoqi@0 2698 # If there's an old file, make the link
aoqi@0 2699
aoqi@0 2700 NOOLD=
aoqi@0 2701 if [[ -f $F-.html ]]; then
aoqi@0 2702 print "<a href=\"$P-.html\">Old</a>"
aoqi@0 2703 else
aoqi@0 2704 NOOLD=1
aoqi@0 2705 print " ---"
aoqi@0 2706 fi
aoqi@0 2707
aoqi@0 2708 # If there's an new file, make the link
aoqi@0 2709
aoqi@0 2710 NONEW=
aoqi@0 2711 if [[ -f $F.html ]]; then
aoqi@0 2712 print "<a href=\"$P.html\">New</a>"
aoqi@0 2713 else
aoqi@0 2714 NONEW=1
aoqi@0 2715 print " ---"
aoqi@0 2716 fi
aoqi@0 2717
aoqi@0 2718 if [[ -f $F.patch ]]; then
aoqi@0 2719 print "<a href=\"$P.patch\">Patch</a>"
aoqi@0 2720 else
aoqi@0 2721 print " -----"
aoqi@0 2722 fi
aoqi@0 2723
aoqi@0 2724 if [[ -f $WDIR/raw_files/new/$P ]]; then
aoqi@0 2725 print "<a href=\"raw_files/new/$P\">Raw</a>"
aoqi@0 2726 else
aoqi@0 2727 print " ---"
aoqi@0 2728 fi
aoqi@0 2729 print "</code>"
aoqi@0 2730 if [[ -n $NODIFFS && -z $oldname ]]; then
aoqi@0 2731 if [[ -n $NOOLD ]]; then
aoqi@0 2732 print "<font color=green><b>$P</b></font>"
aoqi@0 2733 elif [[ -n $NONEW ]]; then
aoqi@0 2734 print "<font color=red><b>$P</b></font>"
aoqi@0 2735 fi
aoqi@0 2736 else
aoqi@0 2737 print "<b>$P</b> $oldname"
aoqi@0 2738 fi
aoqi@0 2739
aoqi@0 2740 print "</p><blockquote>\c"
aoqi@0 2741 # Insert delta comments if any
aoqi@0 2742 comments=`getcomments html $P $PP`
aoqi@0 2743 if [ -n "$comments" ]; then
aoqi@0 2744 print "<pre>$comments</pre>"
aoqi@0 2745 fi
aoqi@0 2746
aoqi@0 2747 # Add additional comments comment
aoqi@0 2748
aoqi@0 2749 print "<!-- Add comments to explain changes in $P here -->"
aoqi@0 2750
aoqi@0 2751 # Add count of changes.
aoqi@0 2752
aoqi@0 2753 if [[ -f $F.count ]]; then
aoqi@0 2754 cat $F.count
aoqi@0 2755 rm $F.count
aoqi@0 2756 fi
aoqi@0 2757 print "</blockquote>"
aoqi@0 2758 done < $FLIST
aoqi@0 2759
aoqi@0 2760 print
aoqi@0 2761 print
aoqi@0 2762 print "<hr />"
aoqi@0 2763 print "<p style=\"font-size: small\">"
aoqi@0 2764 print "This code review page was prepared using <b>$0</b>"
aoqi@0 2765 print "(vers $WEBREV_UPDATED)."
aoqi@0 2766 print "</body>"
aoqi@0 2767 print "</html>"
aoqi@0 2768
aoqi@0 2769 if [[ -n $ZIP ]]; then
aoqi@0 2770 # Let's generate a zip file for convenience
aoqi@0 2771 cd $WDIR/..
aoqi@0 2772 if [ -f webrev.zip ]; then
aoqi@0 2773 rm webrev.zip
aoqi@0 2774 fi
aoqi@0 2775 $ZIP -r webrev webrev >/dev/null 2>&1
aoqi@0 2776 fi
aoqi@0 2777
aoqi@0 2778 exec 1<&- # Close FD 1.
aoqi@0 2779 exec 1<&3 # dup FD 3 to restore stdout.
aoqi@0 2780 exec 3<&- # close FD 3.
aoqi@0 2781
aoqi@0 2782 print "Done."
aoqi@0 2783 print "Output to: $WDIR"

mercurial