source: trunk/openjdk/make/scripts/webrev.ksh@ 337

Last change on this file since 337 was 309, checked in by dmik, 14 years ago

trunk: Merged in openjdk6 b24 from branches/vendor/oracle.

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