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