Print this page
Let webrev recognize git
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/tools/scripts/webrev.sh
+++ new/usr/src/tools/scripts/webrev.sh
1 1 #!/usr/bin/ksh93 -p
2 2 #
3 3 # CDDL HEADER START
4 4 #
5 5 # The contents of this file are subject to the terms of the
6 6 # Common Development and Distribution License (the "License").
7 7 # You may not use this file except in compliance with the License.
8 8 #
9 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 # or http://www.opensolaris.org/os/licensing.
11 11 # See the License for the specific language governing permissions
12 12 # and limitations under the License.
13 13 #
14 14 # When distributing Covered Code, include this CDDL HEADER in each
15 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 # If applicable, add the following below this CDDL HEADER, with the
17 17 # fields enclosed by brackets "[]" replaced with your own identifying
18 18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 19 #
20 20 # CDDL HEADER END
21 21 #
22 22
23 23 #
24 24 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 25 # Use is subject to license terms.
26 26 #
27 27
28 28 #
29 29 # This script takes a file list and a workspace and builds a set of html files
30 30 # suitable for doing a code review of source changes via a web page.
31 31 # Documentation is available via the manual page, webrev.1, or just
32 32 # type 'webrev -h'.
33 33 #
34 34 # Acknowledgements to contributors to webrev are listed in the webrev(1)
35 35 # man page.
36 36 #
37 37
38 38 REMOVED_COLOR=brown
39 39 CHANGED_COLOR=blue
40 40 NEW_COLOR=blue
41 41
42 42 HTML='<?xml version="1.0"?>
43 43 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
44 44 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
45 45 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
46 46
47 47 FRAMEHTML='<?xml version="1.0"?>
48 48 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
49 49 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
50 50 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
51 51
52 52 STDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
53 53 <meta http-equiv="Pragma" content="no-cache"></meta>
54 54 <meta http-equiv="Expires" content="-1"></meta>
55 55 <!--
56 56 Note to customizers: the body of the webrev is IDed as SUNWwebrev
57 57 to allow easy overriding by users of webrev via the userContent.css
58 58 mechanism available in some browsers.
59 59
60 60 For example, to have all "removed" information be red instead of
61 61 brown, set a rule in your userContent.css file like:
62 62
63 63 body#SUNWwebrev span.removed { color: red ! important; }
64 64 -->
65 65 <style type="text/css" media="screen">
66 66 body {
67 67 background-color: #eeeeee;
68 68 }
69 69 hr {
70 70 border: none 0;
71 71 border-top: 1px solid #aaa;
72 72 height: 1px;
73 73 }
74 74 div.summary {
75 75 font-size: .8em;
76 76 border-bottom: 1px solid #aaa;
77 77 padding-left: 1em;
78 78 padding-right: 1em;
79 79 }
80 80 div.summary h2 {
81 81 margin-bottom: 0.3em;
82 82 }
83 83 div.summary table th {
84 84 text-align: right;
85 85 vertical-align: top;
86 86 white-space: nowrap;
87 87 }
88 88 span.lineschanged {
89 89 font-size: 0.7em;
90 90 }
91 91 span.oldmarker {
92 92 color: red;
93 93 font-size: large;
94 94 font-weight: bold;
95 95 }
96 96 span.newmarker {
97 97 color: green;
98 98 font-size: large;
99 99 font-weight: bold;
100 100 }
101 101 span.removed {
102 102 color: brown;
103 103 }
104 104 span.changed {
105 105 color: blue;
106 106 }
107 107 span.new {
108 108 color: blue;
109 109 font-weight: bold;
110 110 }
111 111 span.chmod {
112 112 font-size: 0.7em;
113 113 color: #db7800;
114 114 }
115 115 a.print { font-size: x-small; }
116 116 a:hover { background-color: #ffcc99; }
117 117 </style>
118 118
119 119 <style type="text/css" media="print">
120 120 pre { font-size: 0.8em; font-family: courier, monospace; }
121 121 span.removed { color: #444; font-style: italic }
122 122 span.changed { font-weight: bold; }
123 123 span.new { font-weight: bold; }
124 124 span.newmarker { font-size: 1.2em; font-weight: bold; }
125 125 span.oldmarker { font-size: 1.2em; font-weight: bold; }
126 126 a.print {display: none}
127 127 hr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
128 128 </style>
129 129 '
130 130
131 131 #
132 132 # UDiffs need a slightly different CSS rule for 'new' items (we don't
133 133 # want them to be bolded as we do in cdiffs or sdiffs).
134 134 #
135 135 UDIFFCSS='
136 136 <style type="text/css" media="screen">
137 137 span.new {
138 138 color: blue;
139 139 font-weight: normal;
140 140 }
141 141 </style>
142 142 '
143 143
144 144 #
145 145 # Display remote target with prefix and trailing slash.
146 146 #
147 147 function print_upload_header
148 148 {
149 149 typeset -r prefix=$1
150 150 typeset display_target
151 151
152 152 if [[ -z $tflag ]]; then
153 153 display_target=${prefix}${remote_target}
154 154 else
155 155 display_target=${remote_target}
156 156 fi
157 157
158 158 if [[ ${display_target} != */ ]]; then
159 159 display_target=${display_target}/
160 160 fi
161 161
162 162 print " Upload to: ${display_target}\n" \
163 163 " Uploading: \c"
164 164 }
165 165
166 166 #
167 167 # Upload the webrev via rsync. Return 0 on success, 1 on error.
168 168 #
169 169 function rsync_upload
170 170 {
171 171 if (( $# != 2 )); then
172 172 print "\nERROR: rsync_upload: wrong usage ($#)"
173 173 exit 1
174 174 fi
175 175
176 176 typeset -r dst=$1
177 177 integer -r print_err_msg=$2
178 178
179 179 print_upload_header ${rsync_prefix}
180 180 print "rsync ... \c"
181 181 typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
182 182 if [[ -z $err_msg ]]; then
183 183 print "\nERROR: rsync_upload: cannot create temporary file"
184 184 return 1
185 185 fi
186 186 #
187 187 # The source directory must end with a slash in order to copy just
188 188 # directory contents, not the whole directory.
189 189 #
190 190 typeset src_dir=$WDIR
191 191 if [[ ${src_dir} != */ ]]; then
192 192 src_dir=${src_dir}/
193 193 fi
194 194 $RSYNC -r -q ${src_dir} $dst 2>$err_msg
195 195 if (( $? != 0 )); then
196 196 if (( ${print_err_msg} > 0 )); then
197 197 print "Failed.\nERROR: rsync failed"
198 198 print "src dir: '${src_dir}'\ndst dir: '$dst'"
199 199 print "error messages:"
200 200 $SED 's/^/> /' $err_msg
201 201 rm -f $err_msg
202 202 fi
203 203 return 1
204 204 fi
205 205
206 206 rm -f $err_msg
207 207 print "Done."
208 208 return 0
209 209 }
210 210
211 211 #
212 212 # Create directories on remote host using SFTP. Return 0 on success,
213 213 # 1 on failure.
214 214 #
215 215 function remote_mkdirs
216 216 {
217 217 typeset -r dir_spec=$1
218 218
219 219 #
220 220 # If the supplied path is absolute we assume all directories are
221 221 # created, otherwise try to create all directories in the path
222 222 # except the last one which will be created by scp.
223 223 #
224 224 if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
225 225 print "mkdirs \c"
226 226 #
227 227 # Remove the last directory from directory specification.
228 228 #
229 229 typeset -r dirs_mk=${dir_spec%/*}
230 230 typeset -r batch_file_mkdir=$( $MKTEMP \
231 231 /tmp/webrev_mkdir.XXXXXX )
232 232 if [[ -z $batch_file_mkdir ]]; then
233 233 print "\nERROR: remote_mkdirs:" \
234 234 "cannot create temporary file for batch file"
235 235 return 1
236 236 fi
237 237 OLDIFS=$IFS
238 238 IFS=/
239 239 typeset dir
240 240 for dir in ${dirs_mk}; do
241 241 #
242 242 # Use the '-' prefix to ignore mkdir errors in order
243 243 # to avoid an error in case the directory already
244 244 # exists. We check the directory with chdir to be sure
245 245 # there is one.
246 246 #
247 247 print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
248 248 print "chdir ${dir}" >> ${batch_file_mkdir}
249 249 done
250 250 IFS=$OLDIFS
251 251 typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
252 252 if [[ -z ${sftp_err_msg} ]]; then
253 253 print "\nERROR: remote_mkdirs:" \
254 254 "cannot create temporary file for error messages"
255 255 return 1
256 256 fi
257 257 $SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
258 258 if (( $? != 0 )); then
259 259 print "\nERROR: failed to create remote directories"
260 260 print "error messages:"
261 261 $SED 's/^/> /' ${sftp_err_msg}
262 262 rm -f ${sftp_err_msg} ${batch_file_mkdir}
263 263 return 1
264 264 fi
265 265 rm -f ${sftp_err_msg} ${batch_file_mkdir}
266 266 fi
267 267
268 268 return 0
269 269 }
270 270
271 271 #
272 272 # Upload the webrev via SSH. Return 0 on success, 1 on error.
273 273 #
274 274 function ssh_upload
275 275 {
276 276 if (( $# != 1 )); then
277 277 print "\nERROR: ssh_upload: wrong number of arguments"
278 278 exit 1
279 279 fi
280 280
281 281 typeset dst=$1
282 282 typeset -r host_spec=${dst%%:*}
283 283 typeset -r dir_spec=${dst#*:}
284 284
285 285 #
286 286 # Display the upload information before calling delete_webrev
287 287 # because it will also print its progress.
288 288 #
289 289 print_upload_header ${ssh_prefix}
290 290
291 291 #
292 292 # If the deletion was explicitly requested there is no need
293 293 # to perform it again.
294 294 #
295 295 if [[ -z $Dflag ]]; then
296 296 #
297 297 # We do not care about return value because this might be
298 298 # the first time this directory is uploaded.
299 299 #
300 300 delete_webrev 0
301 301 fi
302 302
303 303 #
304 304 # Create remote directories. Any error reporting will be done
305 305 # in remote_mkdirs function.
306 306 #
307 307 remote_mkdirs ${dir_spec}
308 308 if (( $? != 0 )); then
309 309 return 1
310 310 fi
311 311
312 312 print "upload ... \c"
313 313 typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
314 314 if [[ -z ${scp_err_msg} ]]; then
315 315 print "\nERROR: ssh_upload:" \
316 316 "cannot create temporary file for error messages"
317 317 return 1
318 318 fi
319 319 $SCP -q -C -B -o PreferredAuthentications=publickey -r \
320 320 $WDIR $dst 2>${scp_err_msg}
321 321 if (( $? != 0 )); then
322 322 print "Failed.\nERROR: scp failed"
323 323 print "src dir: '$WDIR'\ndst dir: '$dst'"
324 324 print "error messages:"
325 325 $SED 's/^/> /' ${scp_err_msg}
326 326 rm -f ${scp_err_msg}
327 327 return 1
328 328 fi
329 329
330 330 rm -f ${scp_err_msg}
331 331 print "Done."
332 332 return 0
333 333 }
334 334
335 335 #
336 336 # Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
337 337 # on failure. If first argument is 1 then perform the check of sftp return
338 338 # value otherwise ignore it. If second argument is present it means this run
339 339 # only performs deletion.
340 340 #
341 341 function delete_webrev
342 342 {
343 343 if (( $# < 1 )); then
344 344 print "delete_webrev: wrong number of arguments"
345 345 exit 1
346 346 fi
347 347
348 348 integer -r check=$1
349 349 integer delete_only=0
350 350 if (( $# == 2 )); then
351 351 delete_only=1
352 352 fi
353 353
354 354 #
355 355 # Strip the transport specification part of remote target first.
356 356 #
357 357 typeset -r stripped_target=${remote_target##*://}
358 358 typeset -r host_spec=${stripped_target%%:*}
359 359 typeset -r dir_spec=${stripped_target#*:}
360 360 typeset dir_rm
361 361
362 362 #
363 363 # Do not accept an absolute path.
364 364 #
365 365 if [[ ${dir_spec} == /* ]]; then
366 366 return 1
367 367 fi
368 368
369 369 #
370 370 # Strip the ending slash.
371 371 #
372 372 if [[ ${dir_spec} == */ ]]; then
373 373 dir_rm=${dir_spec%%/}
374 374 else
375 375 dir_rm=${dir_spec}
376 376 fi
377 377
378 378 if (( ${delete_only} > 0 )); then
379 379 print " Removing: \c"
380 380 else
381 381 print "rmdir \c"
382 382 fi
383 383 if [[ -z "$dir_rm" ]]; then
384 384 print "\nERROR: empty directory for removal"
385 385 return 1
386 386 fi
387 387
388 388 #
389 389 # Prepare batch file.
390 390 #
391 391 typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
392 392 if [[ -z $batch_file_rm ]]; then
393 393 print "\nERROR: delete_webrev: cannot create temporary file"
394 394 return 1
395 395 fi
396 396 print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
397 397
398 398 #
399 399 # Perform remote deletion and remove the batch file.
400 400 #
401 401 typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
402 402 if [[ -z ${sftp_err_msg} ]]; then
403 403 print "\nERROR: delete_webrev:" \
404 404 "cannot create temporary file for error messages"
405 405 return 1
406 406 fi
407 407 $SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
408 408 integer -r ret=$?
409 409 rm -f $batch_file_rm
410 410 if (( $ret != 0 && $check > 0 )); then
411 411 print "Failed.\nERROR: failed to remove remote directories"
412 412 print "error messages:"
413 413 $SED 's/^/> /' ${sftp_err_msg}
414 414 rm -f ${sftp_err_msg}
415 415 return $ret
416 416 fi
417 417 rm -f ${sftp_err_msg}
418 418 if (( ${delete_only} > 0 )); then
419 419 print "Done."
420 420 fi
421 421
422 422 return 0
423 423 }
424 424
425 425 #
426 426 # Upload webrev to remote site
427 427 #
428 428 function upload_webrev
429 429 {
430 430 integer ret
431 431
432 432 if [[ ! -d "$WDIR" ]]; then
433 433 print "\nERROR: webrev directory '$WDIR' does not exist"
434 434 return 1
435 435 fi
436 436
437 437 #
438 438 # Perform a late check to make sure we do not upload closed source
439 439 # to remote target when -n is used. If the user used custom remote
440 440 # target he probably knows what he is doing.
441 441 #
442 442 if [[ -n $nflag && -z $tflag ]]; then
443 443 $FIND $WDIR -type d -name closed \
444 444 | $GREP closed >/dev/null
445 445 if (( $? == 0 )); then
446 446 print "\nERROR: directory '$WDIR' contains" \
447 447 "\"closed\" directory"
448 448 return 1
449 449 fi
450 450 fi
451 451
452 452
453 453 #
454 454 # We have the URI for remote destination now so let's start the upload.
455 455 #
456 456 if [[ -n $tflag ]]; then
457 457 if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
458 458 rsync_upload ${remote_target##$rsync_prefix} 1
459 459 ret=$?
460 460 return $ret
461 461 elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
462 462 ssh_upload ${remote_target##$ssh_prefix}
463 463 ret=$?
464 464 return $ret
465 465 fi
466 466 else
467 467 #
468 468 # Try rsync first and fallback to SSH in case it fails.
469 469 #
470 470 rsync_upload ${remote_target} 0
471 471 ret=$?
472 472 if (( $ret != 0 )); then
473 473 print "Failed. (falling back to SSH)"
474 474 ssh_upload ${remote_target}
475 475 ret=$?
476 476 fi
477 477 return $ret
478 478 fi
479 479 }
480 480
481 481 #
482 482 # input_cmd | url_encode | output_cmd
483 483 #
484 484 # URL-encode (percent-encode) reserved characters as defined in RFC 3986.
485 485 #
486 486 # Reserved characters are: :/?#[]@!$&'()*+,;=
487 487 #
488 488 # While not a reserved character itself, percent '%' is reserved by definition
489 489 # so encode it first to avoid recursive transformation, and skip '/' which is
490 490 # a path delimiter.
491 491 #
492 492 # The quotation character is deliberately not escaped in order to make
493 493 # the substitution work with GNU sed.
494 494 #
495 495 function url_encode
496 496 {
497 497 $SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
498 498 -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
499 499 -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
500 500 -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
501 501 -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
502 502 -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
503 503 }
504 504
505 505 #
506 506 # input_cmd | html_quote | output_cmd
507 507 # or
508 508 # html_quote filename | output_cmd
509 509 #
510 510 # Make a piece of source code safe for display in an HTML <pre> block.
511 511 #
512 512 html_quote()
513 513 {
514 514 $SED -e "s/&/\&/g" -e "s/</\</g" -e "s/>/\>/g" "$@" | expand
515 515 }
516 516
517 517 #
518 518 # input_cmd | its2url | output_cmd
519 519 #
520 520 # Scan for information tracking system references and insert <a> links to the
521 521 # relevant databases.
522 522 #
523 523 its2url()
524 524 {
525 525 $SED -f ${its_sed_script}
526 526 }
527 527
528 528 #
529 529 # strip_unchanged <infile> | output_cmd
530 530 #
531 531 # Removes chunks of sdiff documents that have not changed. This makes it
532 532 # easier for a code reviewer to find the bits that have changed.
533 533 #
534 534 # Deleted lines of text are replaced by a horizontal rule. Some
535 535 # identical lines are retained before and after the changed lines to
536 536 # provide some context. The number of these lines is controlled by the
537 537 # variable C in the $AWK script below.
538 538 #
539 539 # The script detects changed lines as any line that has a "<span class="
540 540 # string embedded (unchanged lines have no particular class and are not
541 541 # part of a <span>). Blank lines (without a sequence number) are also
542 542 # detected since they flag lines that have been inserted or deleted.
543 543 #
544 544 strip_unchanged()
545 545 {
546 546 $AWK '
547 547 BEGIN { C = c = 20 }
548 548 NF == 0 || /<span class="/ {
549 549 if (c > C) {
550 550 c -= C
551 551 inx = 0
552 552 if (c > C) {
553 553 print "\n</pre><hr></hr><pre>"
554 554 inx = c % C
555 555 c = C
556 556 }
557 557
558 558 for (i = 0; i < c; i++)
559 559 print ln[(inx + i) % C]
560 560 }
561 561 c = 0;
562 562 print
563 563 next
564 564 }
565 565 { if (c >= C) {
566 566 ln[c % C] = $0
567 567 c++;
568 568 next;
569 569 }
570 570 c++;
571 571 print
572 572 }
573 573 END { if (c > (C * 2)) print "\n</pre><hr></hr>" }
574 574
575 575 ' $1
576 576 }
577 577
578 578 #
579 579 # sdiff_to_html
580 580 #
581 581 # This function takes two files as arguments, obtains their diff, and
582 582 # processes the diff output to present the files as an HTML document with
583 583 # the files displayed side-by-side, differences shown in color. It also
584 584 # takes a delta comment, rendered as an HTML snippet, as the third
585 585 # argument. The function takes two files as arguments, then the name of
586 586 # file, the path, and the comment. The HTML will be delivered on stdout,
587 587 # e.g.
588 588 #
589 589 # $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
590 590 # new/usr/src/tools/scripts/webrev.sh \
591 591 # webrev.sh usr/src/tools/scripts \
592 592 # '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
593 593 # 1234567</a> my bugid' > <file>.html
594 594 #
595 595 # framed_sdiff() is then called which creates $2.frames.html
596 596 # in the webrev tree.
597 597 #
598 598 # FYI: This function is rather unusual in its use of awk. The initial
599 599 # diff run produces conventional diff output showing changed lines mixed
600 600 # with editing codes. The changed lines are ignored - we're interested in
601 601 # the editing codes, e.g.
602 602 #
603 603 # 8c8
604 604 # 57a61
605 605 # 63c66,76
606 606 # 68,93d80
607 607 # 106d90
608 608 # 108,110d91
609 609 #
610 610 # These editing codes are parsed by the awk script and used to generate
611 611 # another awk script that generates HTML, e.g the above lines would turn
612 612 # into something like this:
613 613 #
614 614 # BEGIN { printf "<pre>\n" }
615 615 # function sp(n) {for (i=0;i<n;i++)printf "\n"}
616 616 # function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
617 617 # NR==8 {wl("#7A7ADD");next}
618 618 # NR==54 {wl("#7A7ADD");sp(3);next}
619 619 # NR==56 {wl("#7A7ADD");next}
620 620 # NR==57 {wl("black");printf "\n"; next}
621 621 # : :
622 622 #
623 623 # This script is then run on the original source file to generate the
624 624 # HTML that corresponds to the source file.
625 625 #
626 626 # The two HTML files are then combined into a single piece of HTML that
627 627 # uses an HTML table construct to present the files side by side. You'll
628 628 # notice that the changes are color-coded:
629 629 #
630 630 # black - unchanged lines
631 631 # blue - changed lines
632 632 # bold blue - new lines
633 633 # brown - deleted lines
634 634 #
635 635 # Blank lines are inserted in each file to keep unchanged lines in sync
636 636 # (side-by-side). This format is familiar to users of sdiff(1) or
637 637 # Teamware's filemerge tool.
638 638 #
639 639 sdiff_to_html()
640 640 {
641 641 diff -b $1 $2 > /tmp/$$.diffs
642 642
643 643 TNAME=$3
644 644 TPATH=$4
645 645 COMMENT=$5
646 646
647 647 #
648 648 # Now we have the diffs, generate the HTML for the old file.
649 649 #
650 650 $AWK '
651 651 BEGIN {
652 652 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
653 653 printf "function removed() "
654 654 printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
655 655 printf "function changed() "
656 656 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
657 657 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
658 658 }
659 659 /^</ {next}
660 660 /^>/ {next}
661 661 /^---/ {next}
662 662
663 663 {
664 664 split($1, a, /[cad]/) ;
665 665 if (index($1, "a")) {
666 666 if (a[1] == 0) {
667 667 n = split(a[2], r, /,/);
668 668 if (n == 1)
669 669 printf "BEGIN\t\t{sp(1)}\n"
670 670 else
671 671 printf "BEGIN\t\t{sp(%d)}\n",\
672 672 (r[2] - r[1]) + 1
673 673 next
674 674 }
675 675
676 676 printf "NR==%s\t\t{", a[1]
677 677 n = split(a[2], r, /,/);
678 678 s = r[1];
679 679 if (n == 1)
680 680 printf "bl();printf \"\\n\"; next}\n"
681 681 else {
682 682 n = r[2] - r[1]
683 683 printf "bl();sp(%d);next}\n",\
684 684 (r[2] - r[1]) + 1
685 685 }
686 686 next
687 687 }
688 688 if (index($1, "d")) {
689 689 n = split(a[1], r, /,/);
690 690 n1 = r[1]
691 691 n2 = r[2]
692 692 if (n == 1)
693 693 printf "NR==%s\t\t{removed(); next}\n" , n1
694 694 else
695 695 printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
696 696 next
697 697 }
698 698 if (index($1, "c")) {
699 699 n = split(a[1], r, /,/);
700 700 n1 = r[1]
701 701 n2 = r[2]
702 702 final = n2
703 703 d1 = 0
704 704 if (n == 1)
705 705 printf "NR==%s\t\t{changed();" , n1
706 706 else {
707 707 d1 = n2 - n1
708 708 printf "NR==%s,NR==%s\t{changed();" , n1, n2
709 709 }
710 710 m = split(a[2], r, /,/);
711 711 n1 = r[1]
712 712 n2 = r[2]
713 713 if (m > 1) {
714 714 d2 = n2 - n1
715 715 if (d2 > d1) {
716 716 if (n > 1) printf "if (NR==%d)", final
717 717 printf "sp(%d);", d2 - d1
718 718 }
719 719 }
720 720 printf "next}\n" ;
721 721
722 722 next
723 723 }
724 724 }
725 725
726 726 END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
727 727 ' /tmp/$$.diffs > /tmp/$$.file1
728 728
729 729 #
730 730 # Now generate the HTML for the new file
731 731 #
732 732 $AWK '
733 733 BEGIN {
734 734 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
735 735 printf "function new() "
736 736 printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
737 737 printf "function changed() "
738 738 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
739 739 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
740 740 }
741 741
742 742 /^</ {next}
743 743 /^>/ {next}
744 744 /^---/ {next}
745 745
746 746 {
747 747 split($1, a, /[cad]/) ;
748 748 if (index($1, "d")) {
749 749 if (a[2] == 0) {
750 750 n = split(a[1], r, /,/);
751 751 if (n == 1)
752 752 printf "BEGIN\t\t{sp(1)}\n"
753 753 else
754 754 printf "BEGIN\t\t{sp(%d)}\n",\
755 755 (r[2] - r[1]) + 1
756 756 next
757 757 }
758 758
759 759 printf "NR==%s\t\t{", a[2]
760 760 n = split(a[1], r, /,/);
761 761 s = r[1];
762 762 if (n == 1)
763 763 printf "bl();printf \"\\n\"; next}\n"
764 764 else {
765 765 n = r[2] - r[1]
766 766 printf "bl();sp(%d);next}\n",\
767 767 (r[2] - r[1]) + 1
768 768 }
769 769 next
770 770 }
771 771 if (index($1, "a")) {
772 772 n = split(a[2], r, /,/);
773 773 n1 = r[1]
774 774 n2 = r[2]
775 775 if (n == 1)
776 776 printf "NR==%s\t\t{new() ; next}\n" , n1
777 777 else
778 778 printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
779 779 next
780 780 }
781 781 if (index($1, "c")) {
782 782 n = split(a[2], r, /,/);
783 783 n1 = r[1]
784 784 n2 = r[2]
785 785 final = n2
786 786 d2 = 0;
787 787 if (n == 1) {
788 788 final = n1
789 789 printf "NR==%s\t\t{changed();" , n1
790 790 } else {
791 791 d2 = n2 - n1
792 792 printf "NR==%s,NR==%s\t{changed();" , n1, n2
793 793 }
794 794 m = split(a[1], r, /,/);
795 795 n1 = r[1]
796 796 n2 = r[2]
797 797 if (m > 1) {
798 798 d1 = n2 - n1
799 799 if (d1 > d2) {
800 800 if (n > 1) printf "if (NR==%d)", final
801 801 printf "sp(%d);", d1 - d2
802 802 }
803 803 }
804 804 printf "next}\n" ;
805 805 next
806 806 }
807 807 }
808 808 END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
809 809 ' /tmp/$$.diffs > /tmp/$$.file2
810 810
811 811 #
812 812 # Post-process the HTML files by running them back through $AWK
813 813 #
814 814 html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
815 815
816 816 html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
817 817
818 818 #
819 819 # Now combine into a valid HTML file and side-by-side into a table
820 820 #
821 821 print "$HTML<head>$STDHEAD"
822 822 print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
823 823 print "</head><body id=\"SUNWwebrev\">"
824 824 print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
825 825 print "<pre>$COMMENT</pre>\n"
826 826 print "<table><tr valign=\"top\">"
827 827 print "<td><pre>"
828 828
829 829 strip_unchanged /tmp/$$.file1.html
830 830
831 831 print "</pre></td><td><pre>"
832 832
833 833 strip_unchanged /tmp/$$.file2.html
834 834
835 835 print "</pre></td>"
836 836 print "</tr></table>"
837 837 print "</body></html>"
838 838
839 839 framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
840 840 "$COMMENT"
841 841 }
842 842
843 843
844 844 #
845 845 # framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
846 846 #
847 847 # Expects lefthand and righthand side html files created by sdiff_to_html.
848 848 # We use insert_anchors() to augment those with HTML navigation anchors,
849 849 # and then emit the main frame. Content is placed into:
850 850 #
851 851 # $WDIR/DIR/$TNAME.lhs.html
852 852 # $WDIR/DIR/$TNAME.rhs.html
853 853 # $WDIR/DIR/$TNAME.frames.html
854 854 #
855 855 # NOTE: We rely on standard usage of $WDIR and $DIR.
856 856 #
857 857 function framed_sdiff
858 858 {
859 859 typeset TNAME=$1
860 860 typeset TPATH=$2
861 861 typeset lhsfile=$3
862 862 typeset rhsfile=$4
863 863 typeset comments=$5
864 864 typeset RTOP
865 865
866 866 # Enable html files to access WDIR via a relative path.
867 867 RTOP=$(relative_dir $TPATH $WDIR)
868 868
869 869 # Make the rhs/lhs files and output the frameset file.
870 870 print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
871 871
872 872 cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
873 873 <script type="text/javascript" src="${RTOP}ancnav.js"></script>
874 874 </head>
875 875 <body id="SUNWwebrev" onkeypress="keypress(event);">
876 876 <a name="0"></a>
877 877 <pre>$comments</pre><hr></hr>
878 878 EOF
879 879
880 880 cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
881 881
882 882 insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
883 883 insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
884 884
885 885 close='</body></html>'
886 886
887 887 print $close >> $WDIR/$DIR/$TNAME.lhs.html
888 888 print $close >> $WDIR/$DIR/$TNAME.rhs.html
889 889
890 890 print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
891 891 print "<title>$WNAME Framed-Sdiff " \
892 892 "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
893 893 cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
894 894 <frameset rows="*,60">
895 895 <frameset cols="50%,50%">
896 896 <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
897 897 <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
898 898 </frameset>
899 899 <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
900 900 marginheight="0" name="nav"></frame>
901 901 <noframes>
902 902 <body id="SUNWwebrev">
903 903 Alas 'frames' webrev requires that your browser supports frames
904 904 and has the feature enabled.
905 905 </body>
906 906 </noframes>
907 907 </frameset>
908 908 </html>
909 909 EOF
910 910 }
911 911
912 912
913 913 #
914 914 # fix_postscript
915 915 #
916 916 # Merge codereview output files to a single conforming postscript file, by:
917 917 # - removing all extraneous headers/trailers
918 918 # - making the page numbers right
919 919 # - removing pages devoid of contents which confuse some
920 920 # postscript readers.
921 921 #
922 922 # From Casper.
923 923 #
924 924 function fix_postscript
925 925 {
926 926 infile=$1
927 927
928 928 cat > /tmp/$$.crmerge.pl << \EOF
929 929
930 930 print scalar(<>); # %!PS-Adobe---
931 931 print "%%Orientation: Landscape\n";
932 932
933 933 $pno = 0;
934 934 $doprint = 1;
935 935
936 936 $page = "";
937 937
938 938 while (<>) {
939 939 next if (/^%%Pages:\s*\d+/);
940 940
941 941 if (/^%%Page:/) {
942 942 if ($pno == 0 || $page =~ /\)S/) {
943 943 # Header or single page containing text
944 944 print "%%Page: ? $pno\n" if ($pno > 0);
945 945 print $page;
946 946 $pno++;
947 947 } else {
948 948 # Empty page, skip it.
949 949 }
950 950 $page = "";
951 951 $doprint = 1;
952 952 next;
953 953 }
954 954
955 955 # Skip from %%Trailer of one document to Endprolog
956 956 # %%Page of the next
957 957 $doprint = 0 if (/^%%Trailer/);
958 958 $page .= $_ if ($doprint);
959 959 }
960 960
961 961 if ($page =~ /\)S/) {
962 962 print "%%Page: ? $pno\n";
963 963 print $page;
964 964 } else {
965 965 $pno--;
966 966 }
967 967 print "%%Trailer\n%%Pages: $pno\n";
968 968 EOF
969 969
970 970 $PERL /tmp/$$.crmerge.pl < $infile
971 971 }
972 972
973 973
974 974 #
975 975 # input_cmd | insert_anchors | output_cmd
976 976 #
977 977 # Flag blocks of difference with sequentially numbered invisible
978 978 # anchors. These are used to drive the frames version of the
979 979 # sdiffs output.
980 980 #
981 981 # NOTE: Anchor zero flags the top of the file irrespective of changes,
982 982 # an additional anchor is also appended to flag the bottom.
983 983 #
984 984 # The script detects changed lines as any line that has a "<span
985 985 # class=" string embedded (unchanged lines have no class set and are
986 986 # not part of a <span>. Blank lines (without a sequence number)
987 987 # are also detected since they flag lines that have been inserted or
988 988 # deleted.
989 989 #
990 990 function insert_anchors
991 991 {
992 992 $AWK '
993 993 function ia() {
994 994 printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
995 995 }
996 996
997 997 BEGIN {
998 998 anc=1;
999 999 inblock=1;
1000 1000 printf "<pre>\n";
1001 1001 }
1002 1002 NF == 0 || /^<span class=/ {
1003 1003 if (inblock == 0) {
1004 1004 ia();
1005 1005 inblock=1;
1006 1006 }
1007 1007 print;
1008 1008 next;
1009 1009 }
1010 1010 {
1011 1011 inblock=0;
1012 1012 print;
1013 1013 }
1014 1014 END {
1015 1015 ia();
1016 1016
1017 1017 printf "<b style=\"font-size: large; color: red\">";
1018 1018 printf "--- EOF ---</b>"
1019 1019 for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1020 1020 printf "</pre>"
1021 1021 printf "<form name=\"eof\">";
1022 1022 printf "<input name=\"value\" value=\"%d\" " \
1023 1023 "type=\"hidden\"></input>", anc - 1;
1024 1024 printf "</form>";
1025 1025 }
1026 1026 ' $1
1027 1027 }
1028 1028
1029 1029
1030 1030 #
1031 1031 # relative_dir
1032 1032 #
1033 1033 # Print a relative return path from $1 to $2. For example if
1034 1034 # $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1035 1035 # this function would print "../../../../".
1036 1036 #
1037 1037 # In the event that $1 is not in $2 a warning is printed to stderr,
1038 1038 # and $2 is returned-- the result of this is that the resulting webrev
1039 1039 # is not relocatable.
1040 1040 #
1041 1041 function relative_dir
1042 1042 {
1043 1043 typeset cur="${1##$2?(/)}"
1044 1044
1045 1045 #
1046 1046 # If the first path was specified absolutely, and it does
1047 1047 # not start with the second path, it's an error.
1048 1048 #
1049 1049 if [[ "$cur" = "/${1#/}" ]]; then
1050 1050 # Should never happen.
1051 1051 print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1052 1052 print -u2 "to \"$2\". Check input paths. Framed webrev "
1053 1053 print -u2 "will not be relocatable!"
1054 1054 print $2
1055 1055 return
1056 1056 fi
1057 1057
1058 1058 #
1059 1059 # This is kind of ugly. The sed script will do the following:
1060 1060 #
1061 1061 # 1. Strip off a leading "." or "./": this is important to get
1062 1062 # the correct arcnav links for files in $WDIR.
1063 1063 # 2. Strip off a trailing "/": this is not strictly necessary,
1064 1064 # but is kind of nice, since it doesn't end up in "//" at
1065 1065 # the end of a relative path.
1066 1066 # 3. Replace all remaining sequences of non-"/" with "..": the
1067 1067 # assumption here is that each dirname represents another
1068 1068 # level of relative separation.
1069 1069 # 4. Append a trailing "/" only for non-empty paths: this way
1070 1070 # the caller doesn't need to duplicate this logic, and does
1071 1071 # not end up using $RTOP/file for files in $WDIR.
1072 1072 #
1073 1073 print $cur | $SED -e '{
1074 1074 s:^\./*::
1075 1075 s:/$::
1076 1076 s:[^/][^/]*:..:g
1077 1077 s:^\(..*\)$:\1/:
1078 1078 }'
1079 1079 }
1080 1080
1081 1081 #
1082 1082 # frame_nav_js
1083 1083 #
1084 1084 # Emit javascript for frame navigation
1085 1085 #
1086 1086 function frame_nav_js
1087 1087 {
1088 1088 cat << \EOF
1089 1089 var myInt;
1090 1090 var scrolling=0;
1091 1091 var sfactor = 3;
1092 1092 var scount=10;
1093 1093
1094 1094 function scrollByPix() {
1095 1095 if (scount<=0) {
1096 1096 sfactor*=1.2;
1097 1097 scount=10;
1098 1098 }
1099 1099 parent.lhs.scrollBy(0,sfactor);
1100 1100 parent.rhs.scrollBy(0,sfactor);
1101 1101 scount--;
1102 1102 }
1103 1103
1104 1104 function scrollToAnc(num) {
1105 1105
1106 1106 // Update the value of the anchor in the form which we use as
1107 1107 // storage for this value. setAncValue() will take care of
1108 1108 // correcting for overflow and underflow of the value and return
1109 1109 // us the new value.
1110 1110 num = setAncValue(num);
1111 1111
1112 1112 // Set location and scroll back a little to expose previous
1113 1113 // lines.
1114 1114 //
1115 1115 // Note that this could be improved: it is possible although
1116 1116 // complex to compute the x and y position of an anchor, and to
1117 1117 // scroll to that location directly.
1118 1118 //
1119 1119 parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
1120 1120 parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1121 1121
1122 1122 parent.lhs.scrollBy(0,-30);
1123 1123 parent.rhs.scrollBy(0,-30);
1124 1124 }
1125 1125
1126 1126 function getAncValue()
1127 1127 {
1128 1128 return (parseInt(parent.nav.document.diff.real.value));
1129 1129 }
1130 1130
1131 1131 function setAncValue(val)
1132 1132 {
1133 1133 if (val <= 0) {
1134 1134 val = 0;
1135 1135 parent.nav.document.diff.real.value = val;
1136 1136 parent.nav.document.diff.display.value = "BOF";
1137 1137 return (val);
1138 1138 }
1139 1139
1140 1140 //
1141 1141 // The way we compute the max anchor value is to stash it
1142 1142 // inline in the left and right hand side pages-- it's the same
1143 1143 // on each side, so we pluck from the left.
1144 1144 //
1145 1145 maxval = parent.lhs.document.eof.value.value;
1146 1146 if (val < maxval) {
1147 1147 parent.nav.document.diff.real.value = val;
1148 1148 parent.nav.document.diff.display.value = val.toString();
1149 1149 return (val);
1150 1150 }
1151 1151
1152 1152 // this must be: val >= maxval
1153 1153 val = maxval;
1154 1154 parent.nav.document.diff.real.value = val;
1155 1155 parent.nav.document.diff.display.value = "EOF";
1156 1156 return (val);
1157 1157 }
1158 1158
1159 1159 function stopScroll() {
1160 1160 if (scrolling==1) {
1161 1161 clearInterval(myInt);
1162 1162 scrolling=0;
1163 1163 }
1164 1164 }
1165 1165
1166 1166 function startScroll() {
1167 1167 stopScroll();
1168 1168 scrolling=1;
1169 1169 myInt=setInterval("scrollByPix()",10);
1170 1170 }
1171 1171
1172 1172 function handlePress(b) {
1173 1173
1174 1174 switch (b) {
1175 1175 case 1 :
1176 1176 scrollToAnc(-1);
1177 1177 break;
1178 1178 case 2 :
1179 1179 scrollToAnc(getAncValue() - 1);
1180 1180 break;
1181 1181 case 3 :
1182 1182 sfactor=-3;
1183 1183 startScroll();
1184 1184 break;
1185 1185 case 4 :
1186 1186 sfactor=3;
1187 1187 startScroll();
1188 1188 break;
1189 1189 case 5 :
1190 1190 scrollToAnc(getAncValue() + 1);
1191 1191 break;
1192 1192 case 6 :
1193 1193 scrollToAnc(999999);
1194 1194 break;
1195 1195 }
1196 1196 }
1197 1197
1198 1198 function handleRelease(b) {
1199 1199 stopScroll();
1200 1200 }
1201 1201
1202 1202 function keypress(ev) {
1203 1203 var keynum;
1204 1204 var keychar;
1205 1205
1206 1206 if (window.event) { // IE
1207 1207 keynum = ev.keyCode;
1208 1208 } else if (ev.which) { // non-IE
1209 1209 keynum = ev.which;
1210 1210 }
1211 1211
1212 1212 keychar = String.fromCharCode(keynum);
1213 1213
1214 1214 if (keychar == "k") {
1215 1215 handlePress(2);
1216 1216 return (0);
1217 1217 } else if (keychar == "j" || keychar == " ") {
1218 1218 handlePress(5);
1219 1219 return (0);
1220 1220 }
1221 1221 return (1);
1222 1222 }
1223 1223
1224 1224 function ValidateDiffNum(){
1225 1225 val = parent.nav.document.diff.display.value;
1226 1226 if (val == "EOF") {
1227 1227 scrollToAnc(999999);
1228 1228 return;
1229 1229 }
1230 1230
1231 1231 if (val == "BOF") {
1232 1232 scrollToAnc(0);
1233 1233 return;
1234 1234 }
1235 1235
1236 1236 i=parseInt(val);
1237 1237 if (isNaN(i)) {
1238 1238 parent.nav.document.diff.display.value = getAncValue();
1239 1239 } else {
1240 1240 scrollToAnc(i);
1241 1241 }
1242 1242 return false;
1243 1243 }
1244 1244
1245 1245 EOF
1246 1246 }
1247 1247
1248 1248 #
1249 1249 # frame_navigation
1250 1250 #
1251 1251 # Output anchor navigation file for framed sdiffs.
1252 1252 #
1253 1253 function frame_navigation
1254 1254 {
1255 1255 print "$HTML<head>$STDHEAD"
1256 1256
1257 1257 cat << \EOF
1258 1258 <title>Anchor Navigation</title>
1259 1259 <meta http-equiv="Content-Script-Type" content="text/javascript">
1260 1260 <meta http-equiv="Content-Type" content="text/html">
1261 1261
1262 1262 <style type="text/css">
1263 1263 div.button td { padding-left: 5px; padding-right: 5px;
1264 1264 background-color: #eee; text-align: center;
1265 1265 border: 1px #444 outset; cursor: pointer; }
1266 1266 div.button a { font-weight: bold; color: black }
1267 1267 div.button td:hover { background: #ffcc99; }
1268 1268 </style>
1269 1269 EOF
1270 1270
1271 1271 print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1272 1272
1273 1273 cat << \EOF
1274 1274 </head>
1275 1275 <body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1276 1276 onkeypress="keypress(event);">
1277 1277 <noscript lang="javascript">
1278 1278 <center>
1279 1279 <p><big>Framed Navigation controls require Javascript</big><br></br>
1280 1280 Either this browser is incompatable or javascript is not enabled</p>
1281 1281 </center>
1282 1282 </noscript>
1283 1283 <table width="100%" border="0" align="center">
1284 1284 <tr>
1285 1285 <td valign="middle" width="25%">Diff navigation:
1286 1286 Use 'j' and 'k' for next and previous diffs; or use buttons
1287 1287 at right</td>
1288 1288 <td align="center" valign="top" width="50%">
1289 1289 <div class="button">
1290 1290 <table border="0" align="center">
1291 1291 <tr>
1292 1292 <td>
1293 1293 <a onMouseDown="handlePress(1);return true;"
1294 1294 onMouseUp="handleRelease(1);return true;"
1295 1295 onMouseOut="handleRelease(1);return true;"
1296 1296 onClick="return false;"
1297 1297 title="Go to Beginning Of file">BOF</a></td>
1298 1298 <td>
1299 1299 <a onMouseDown="handlePress(3);return true;"
1300 1300 onMouseUp="handleRelease(3);return true;"
1301 1301 onMouseOut="handleRelease(3);return true;"
1302 1302 title="Scroll Up: Press and Hold to accelerate"
1303 1303 onClick="return false;">Scroll Up</a></td>
1304 1304 <td>
1305 1305 <a onMouseDown="handlePress(2);return true;"
1306 1306 onMouseUp="handleRelease(2);return true;"
1307 1307 onMouseOut="handleRelease(2);return true;"
1308 1308 title="Go to previous Diff"
1309 1309 onClick="return false;">Prev Diff</a>
1310 1310 </td></tr>
1311 1311
1312 1312 <tr>
1313 1313 <td>
1314 1314 <a onMouseDown="handlePress(6);return true;"
1315 1315 onMouseUp="handleRelease(6);return true;"
1316 1316 onMouseOut="handleRelease(6);return true;"
1317 1317 onClick="return false;"
1318 1318 title="Go to End Of File">EOF</a></td>
1319 1319 <td>
1320 1320 <a onMouseDown="handlePress(4);return true;"
1321 1321 onMouseUp="handleRelease(4);return true;"
1322 1322 onMouseOut="handleRelease(4);return true;"
1323 1323 title="Scroll Down: Press and Hold to accelerate"
1324 1324 onClick="return false;">Scroll Down</a></td>
1325 1325 <td>
1326 1326 <a onMouseDown="handlePress(5);return true;"
1327 1327 onMouseUp="handleRelease(5);return true;"
1328 1328 onMouseOut="handleRelease(5);return true;"
1329 1329 title="Go to next Diff"
1330 1330 onClick="return false;">Next Diff</a></td>
1331 1331 </tr>
1332 1332 </table>
1333 1333 </div>
1334 1334 </td>
1335 1335 <th valign="middle" width="25%">
1336 1336 <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1337 1337 <input name="display" value="BOF" size="8" type="text"></input>
1338 1338 <input name="real" value="0" size="8" type="hidden"></input>
1339 1339 </form>
1340 1340 </th>
1341 1341 </tr>
1342 1342 </table>
1343 1343 </body>
1344 1344 </html>
1345 1345 EOF
1346 1346 }
1347 1347
1348 1348
1349 1349
1350 1350 #
1351 1351 # diff_to_html <filename> <filepath> { U | C } <comment>
1352 1352 #
1353 1353 # Processes the output of diff to produce an HTML file representing either
1354 1354 # context or unified diffs.
1355 1355 #
1356 1356 diff_to_html()
1357 1357 {
1358 1358 TNAME=$1
1359 1359 TPATH=$2
1360 1360 DIFFTYPE=$3
1361 1361 COMMENT=$4
1362 1362
1363 1363 print "$HTML<head>$STDHEAD"
1364 1364 print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1365 1365
1366 1366 if [[ $DIFFTYPE == "U" ]]; then
1367 1367 print "$UDIFFCSS"
1368 1368 fi
1369 1369
1370 1370 cat <<-EOF
1371 1371 </head>
1372 1372 <body id="SUNWwebrev">
1373 1373 <a class="print" href="javascript:print()">Print this page</a>
1374 1374 <pre>$COMMENT</pre>
1375 1375 <pre>
1376 1376 EOF
1377 1377
1378 1378 html_quote | $AWK '
1379 1379 /^--- new/ { next }
1380 1380 /^\+\+\+ new/ { next }
1381 1381 /^--- old/ { next }
1382 1382 /^\*\*\* old/ { next }
1383 1383 /^\*\*\*\*/ { next }
1384 1384 /^-------/ { printf "<center><h1>%s</h1></center>\n", $0; next }
1385 1385 /^\@\@.*\@\@$/ { printf "</pre><hr></hr><pre>\n";
1386 1386 printf "<span class=\"newmarker\">%s</span>\n", $0;
1387 1387 next}
1388 1388
1389 1389 /^\*\*\*/ { printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1390 1390 next}
1391 1391 /^---/ { printf "<span class=\"newmarker\">%s</span>\n", $0;
1392 1392 next}
1393 1393 /^\+/ {printf "<span class=\"new\">%s</span>\n", $0; next}
1394 1394 /^!/ {printf "<span class=\"changed\">%s</span>\n", $0; next}
1395 1395 /^-/ {printf "<span class=\"removed\">%s</span>\n", $0; next}
1396 1396 {printf "%s\n", $0; next}
1397 1397 '
1398 1398
1399 1399 print "</pre></body></html>\n"
1400 1400 }
1401 1401
1402 1402
1403 1403 #
1404 1404 # source_to_html { new | old } <filename>
1405 1405 #
1406 1406 # Process a plain vanilla source file to transform it into an HTML file.
1407 1407 #
1408 1408 source_to_html()
1409 1409 {
1410 1410 WHICH=$1
1411 1411 TNAME=$2
1412 1412
1413 1413 print "$HTML<head>$STDHEAD"
1414 1414 print "<title>$WNAME $WHICH $TNAME</title>"
1415 1415 print "<body id=\"SUNWwebrev\">"
1416 1416 print "<pre>"
1417 1417 html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1418 1418 print "</pre></body></html>"
1419 1419 }
1420 1420
1421 1421 #
1422 1422 # comments_from_teamware {text|html} parent-file child-file
1423 1423 #
1424 1424 # Find the first delta in the child that's not in the parent. Get the
1425 1425 # newest delta from the parent, get all deltas from the child starting
1426 1426 # with that delta, and then get all info starting with the second oldest
1427 1427 # delta in that list (the first delta unique to the child).
1428 1428 #
1429 1429 # This code adapted from Bill Shannon's "spc" script
1430 1430 #
1431 1431 comments_from_teamware()
1432 1432 {
1433 1433 fmt=$1
1434 1434 pfile=$PWS/$2
1435 1435 cfile=$CWS/$3
1436 1436
1437 1437 if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1438 1438 pfile=$RWS/$2
1439 1439 fi
1440 1440
1441 1441 if [[ -f $pfile ]]; then
1442 1442 psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
1443 1443 else
1444 1444 psid=1.1
1445 1445 fi
1446 1446
1447 1447 set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
1448 1448 N=${#sids[@]}
1449 1449
1450 1450 nawkprg='
1451 1451 /^COMMENTS:/ {p=1; continue}
1452 1452 /^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1453 1453 NF == 0u { continue }
1454 1454 {if (p==0) continue; print $0 }'
1455 1455
1456 1456 if [[ $N -ge 2 ]]; then
1457 1457 sid1=${sids[$((N-2))]} # Gets 2nd to last sid
1458 1458
1459 1459 if [[ $fmt == "text" ]]; then
1460 1460 $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \
1461 1461 $AWK "$nawkprg"
1462 1462 return
1463 1463 fi
1464 1464
1465 1465 $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \
1466 1466 html_quote | its2url | $AWK "$nawkprg"
1467 1467 fi
1468 1468 }
1469 1469
1470 1470 #
1471 1471 # comments_from_wx {text|html} filepath
1472 1472 #
1473 1473 # Given the pathname of a file, find its location in a "wx" active
1474 1474 # file list and print the following comment. Output is either text or
1475 1475 # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1476 1476 # are turned into URLs.
1477 1477 #
1478 1478 # This is also used with Mercurial and the file list provided by hg-active.
1479 1479 #
1480 1480 comments_from_wx()
1481 1481 {
1482 1482 typeset fmt=$1
1483 1483 typeset p=$2
1484 1484
1485 1485 comm=`$AWK '
1486 1486 $1 == "'$p'" {
1487 1487 do getline ; while (NF > 0)
1488 1488 getline
1489 1489 while (NF > 0) { print ; getline }
1490 1490 exit
1491 1491 }' < $wxfile`
1492 1492
1493 1493 if [[ -z $comm ]]; then
1494 1494 comm="*** NO COMMENTS ***"
1495 1495 fi
1496 1496
1497 1497 if [[ $fmt == "text" ]]; then
1498 1498 print -- "$comm"
1499 1499 return
1500 1500 fi
1501 1501
1502 1502 print -- "$comm" | html_quote | its2url
1503 1503
1504 1504 }
1505 1505
1506 1506 #
1507 1507 # getcomments {text|html} filepath parentpath
1508 1508 #
1509 1509 # Fetch the comments depending on what SCM mode we're in.
1510 1510 #
1511 1511 getcomments()
1512 1512 {
1513 1513 typeset fmt=$1
1514 1514 typeset p=$2
1515 1515 typeset pp=$3
1516 1516
1517 1517 if [[ -n $Nflag ]]; then
1518 1518 return
1519 1519 fi
1520 1520 #
1521 1521 # Mercurial support uses a file list in wx format, so this
1522 1522 # will be used there, too
1523 1523 #
1524 1524 if [[ -n $wxfile ]]; then
1525 1525 comments_from_wx $fmt $p
1526 1526 else
1527 1527 if [[ $SCM_MODE == "teamware" ]]; then
1528 1528 comments_from_teamware $fmt $pp $p
1529 1529 fi
1530 1530 fi
1531 1531 }
1532 1532
1533 1533 #
1534 1534 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1535 1535 #
1536 1536 # Print out Code Inspection figures similar to sccs-prt(1) format.
1537 1537 #
1538 1538 function printCI
1539 1539 {
1540 1540 integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1541 1541 typeset str
1542 1542 if (( tot == 1 )); then
1543 1543 str="line"
1544 1544 else
1545 1545 str="lines"
1546 1546 fi
1547 1547 printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1548 1548 $tot $str $ins $del $mod $unc
1549 1549 }
1550 1550
1551 1551
1552 1552 #
1553 1553 # difflines <oldfile> <newfile>
1554 1554 #
1555 1555 # Calculate and emit number of added, removed, modified and unchanged lines,
1556 1556 # and total lines changed, the sum of added + removed + modified.
1557 1557 #
1558 1558 function difflines
1559 1559 {
1560 1560 integer tot mod del ins unc err
1561 1561 typeset filename
1562 1562
1563 1563 eval $( diff -e $1 $2 | $AWK '
1564 1564 # Change range of lines: N,Nc
1565 1565 /^[0-9]*,[0-9]*c$/ {
1566 1566 n=split(substr($1,1,length($1)-1), counts, ",");
1567 1567 if (n != 2) {
1568 1568 error=2
1569 1569 exit;
1570 1570 }
1571 1571 #
1572 1572 # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1573 1573 # following would be 5 - 3 = 2! Hence +1 for correction.
1574 1574 #
1575 1575 r=(counts[2]-counts[1])+1;
1576 1576
1577 1577 #
1578 1578 # Now count replacement lines: each represents a change instead
1579 1579 # of a delete, so increment c and decrement r.
1580 1580 #
1581 1581 while (getline != /^\.$/) {
1582 1582 c++;
1583 1583 r--;
1584 1584 }
1585 1585 #
1586 1586 # If there were more replacement lines than original lines,
1587 1587 # then r will be negative; in this case there are no deletions,
1588 1588 # but there are r changes that should be counted as adds, and
1589 1589 # since r is negative, subtract it from a and add it to c.
1590 1590 #
1591 1591 if (r < 0) {
1592 1592 a-=r;
1593 1593 c+=r;
1594 1594 }
1595 1595
1596 1596 #
1597 1597 # If there were more original lines than replacement lines, then
1598 1598 # r will be positive; in this case, increment d by that much.
1599 1599 #
1600 1600 if (r > 0) {
1601 1601 d+=r;
1602 1602 }
1603 1603 next;
1604 1604 }
1605 1605
1606 1606 # Change lines: Nc
1607 1607 /^[0-9].*c$/ {
1608 1608 # The first line is a replacement; any more are additions.
1609 1609 if (getline != /^\.$/) {
1610 1610 c++;
1611 1611 while (getline != /^\.$/) a++;
1612 1612 }
1613 1613 next;
1614 1614 }
1615 1615
1616 1616 # Add lines: both Na and N,Na
1617 1617 /^[0-9].*a$/ {
1618 1618 while (getline != /^\.$/) a++;
1619 1619 next;
1620 1620 }
1621 1621
1622 1622 # Delete range of lines: N,Nd
1623 1623 /^[0-9]*,[0-9]*d$/ {
1624 1624 n=split(substr($1,1,length($1)-1), counts, ",");
1625 1625 if (n != 2) {
1626 1626 error=2
1627 1627 exit;
1628 1628 }
1629 1629 #
1630 1630 # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1631 1631 # following would be 5 - 3 = 2! Hence +1 for correction.
1632 1632 #
1633 1633 r=(counts[2]-counts[1])+1;
1634 1634 d+=r;
1635 1635 next;
1636 1636 }
1637 1637
1638 1638 # Delete line: Nd. For example 10d says line 10 is deleted.
1639 1639 /^[0-9]*d$/ {d++; next}
1640 1640
1641 1641 # Should not get here!
1642 1642 {
1643 1643 error=1;
1644 1644 exit;
1645 1645 }
1646 1646
1647 1647 # Finish off - print results
1648 1648 END {
1649 1649 printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
1650 1650 (c+d+a), c, d, a, error);
1651 1651 }' )
1652 1652
1653 1653 # End of $AWK, Check to see if any trouble occurred.
1654 1654 if (( $? > 0 || err > 0 )); then
1655 1655 print "Unexpected Error occurred reading" \
1656 1656 "\`diff -e $1 $2\`: \$?=$?, err=" $err
1657 1657 return
1658 1658 fi
1659 1659
1660 1660 # Accumulate totals
1661 1661 (( TOTL += tot ))
1662 1662 (( TMOD += mod ))
1663 1663 (( TDEL += del ))
1664 1664 (( TINS += ins ))
1665 1665 # Calculate unchanged lines
1666 1666 unc=`wc -l < $1`
1667 1667 if (( unc > 0 )); then
1668 1668 (( unc -= del + mod ))
1669 1669 (( TUNC += unc ))
1670 1670 fi
1671 1671 # print summary
1672 1672 print "<span class=\"lineschanged\">"
1673 1673 printCI $tot $ins $del $mod $unc
1674 1674 print "</span>"
1675 1675 }
1676 1676
1677 1677
1678 1678 #
1679 1679 # flist_from_wx
1680 1680 #
1681 1681 # Sets up webrev to source its information from a wx-formatted file.
1682 1682 # Sets the global 'wxfile' variable.
1683 1683 #
1684 1684 function flist_from_wx
1685 1685 {
1686 1686 typeset argfile=$1
1687 1687 if [[ -n ${argfile%%/*} ]]; then
1688 1688 #
1689 1689 # If the wx file pathname is relative then make it absolute
1690 1690 # because the webrev does a "cd" later on.
1691 1691 #
1692 1692 wxfile=$PWD/$argfile
1693 1693 else
1694 1694 wxfile=$argfile
1695 1695 fi
1696 1696
1697 1697 $AWK '{ c = 1; print;
1698 1698 while (getline) {
1699 1699 if (NF == 0) { c = -c; continue }
1700 1700 if (c > 0) print
1701 1701 }
1702 1702 }' $wxfile > $FLIST
1703 1703
1704 1704 print " Done."
1705 1705 }
1706 1706
1707 1707 #
1708 1708 # flist_from_teamware [ <args-to-putback-n> ]
1709 1709 #
1710 1710 # Generate the file list by extracting file names from a putback -n. Some
1711 1711 # names may come from the "update/create" messages and others from the
1712 1712 # "currently checked out" warning. Renames are detected here too. Extract
1713 1713 # values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1714 1714 # -n as well, but remove them if they are already defined.
1715 1715 #
1716 1716 function flist_from_teamware
1717 1717 {
1718 1718 if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1719 1719 if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1720 1720 print -u2 "parent $codemgr_parent doesn't look like a" \
1721 1721 "valid teamware workspace"
1722 1722 exit 1
1723 1723 fi
1724 1724 parent_args="-p $codemgr_parent"
1725 1725 fi
1726 1726
1727 1727 print " File list from: 'putback -n $parent_args $*' ... \c"
1728 1728
1729 1729 putback -n $parent_args $* 2>&1 |
1730 1730 $AWK '
1731 1731 /^update:|^create:/ {print $2}
1732 1732 /^Parent workspace:/ {printf("CODEMGR_PARENT=%s\n",$3)}
1733 1733 /^Child workspace:/ {printf("CODEMGR_WS=%s\n",$3)}
1734 1734 /^The following files are currently checked out/ {p = 1; continue}
1735 1735 NF == 0 {p=0 ; continue}
1736 1736 /^rename/ {old=$3}
1737 1737 $1 == "to:" {print $2, old}
1738 1738 /^"/ {continue}
1739 1739 p == 1 {print $1}' |
1740 1740 sort -r -k 1,1 -u | sort > $FLIST
1741 1741
1742 1742 print " Done."
1743 1743 }
1744 1744
1745 1745 #
1746 1746 # Call hg-active to get the active list output in the wx active list format
1747 1747 #
1748 1748 function hg_active_wxfile
1749 1749 {
1750 1750 typeset child=$1
1751 1751 typeset parent=$2
1752 1752
1753 1753 TMPFLIST=/tmp/$$.active
1754 1754 $HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1755 1755 wxfile=$TMPFLIST
1756 1756 }
1757 1757
1758 1758 #
1759 1759 # flist_from_mercurial
1760 1760 # Call hg-active to get a wx-style active list, and hand it off to
1761 1761 # flist_from_wx
1762 1762 #
1763 1763 function flist_from_mercurial
1764 1764 {
1765 1765 typeset child=$1
1766 1766 typeset parent=$2
1767 1767
1768 1768 print " File list from: hg-active -p $parent ...\c"
1769 1769
1770 1770 if [[ ! -x $HG_ACTIVE ]]; then
1771 1771 print # Blank line for the \c above
|
↓ open down ↓ |
1771 lines elided |
↑ open up ↑ |
1772 1772 print -u2 "Error: hg-active tool not found. Exiting"
1773 1773 exit 1
1774 1774 fi
1775 1775 hg_active_wxfile $child $parent
1776 1776
1777 1777 # flist_from_wx prints the Done, so we don't have to.
1778 1778 flist_from_wx $TMPFLIST
1779 1779 }
1780 1780
1781 1781 #
1782 +# Call git-active to get the active list output in the wx active list format
1783 +#
1784 +function git_active_wxfile
1785 +{
1786 + typeset child=$1
1787 + typeset parent=$2
1788 +
1789 + TMPFLIST=/tmp/$$.active
1790 + $GIT_ACTIVE -w $child -p $parent -o $TMPFLIST
1791 + wxfile=$TMPFLIST
1792 +}
1793 +
1794 +#
1795 +# flist_from_git
1796 +# Call git-active to get a wx-style active list, and hand it off to
1797 +# flist_from_wx
1798 +#
1799 +function flist_from_git
1800 +{
1801 + typeset child=$1
1802 + typeset parent=$2
1803 +
1804 + print " File list from: git-active -p $parent ...\c"
1805 +
1806 + if [[ ! -x $GIT_ACTIVE ]]; then
1807 + print # Blank line for the \c above
1808 + print -u2 "Error: git-active tool not found. Exiting"
1809 + exit 1
1810 + fi
1811 + git_active_wxfile $child $parent
1812 +
1813 + # flist_from_wx prints the Done, so we don't have to.
1814 + flist_from_wx $TMPFLIST
1815 +}
1816 +
1817 +#
1782 1818 # flist_from_subversion
1783 1819 #
1784 1820 # Generate the file list by extracting file names from svn status.
1785 1821 #
1786 1822 function flist_from_subversion
1787 1823 {
1788 1824 CWS=$1
1789 1825 OLDPWD=$2
1790 1826
1791 1827 cd $CWS
1792 1828 print -u2 " File list from: svn status ... \c"
1793 1829 svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1794 1830 print -u2 " Done."
1795 1831 cd $OLDPWD
1796 1832 }
1797 1833
1798 1834 function env_from_flist
1799 1835 {
1800 1836 [[ -r $FLIST ]] || return
1801 1837
1802 1838 #
1803 1839 # Use "eval" to set env variables that are listed in the file
1804 1840 # list. Then copy those into our local versions of those
1805 1841 # variables if they have not been set already.
1806 1842 #
1807 1843 eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
1808 1844
1809 1845 if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1810 1846 codemgr_ws=$CODEMGR_WS
1811 1847 export CODEMGR_WS
1812 1848 fi
1813 1849
1814 1850 #
1815 1851 # Check to see if CODEMGR_PARENT is set in the flist file.
1816 1852 #
1817 1853 if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1818 1854 codemgr_parent=$CODEMGR_PARENT
1819 1855 export CODEMGR_PARENT
1820 1856 fi
1821 1857 }
1822 1858
1823 1859 function look_for_prog
1824 1860 {
1825 1861 typeset path
1826 1862 typeset ppath
1827 1863 typeset progname=$1
1828 1864
1829 1865 ppath=$PATH
1830 1866 ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
1831 1867 ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1832 1868 ppath=$ppath:/opt/onbld/bin/`uname -p`
1833 1869
1834 1870 PATH=$ppath prog=`whence $progname`
1835 1871 if [[ -n $prog ]]; then
1836 1872 print $prog
1837 1873 fi
1838 1874 }
1839 1875
1840 1876 function get_file_mode
1841 1877 {
1842 1878 $PERL -e '
1843 1879 if (@stat = stat($ARGV[0])) {
1844 1880 $mode = $stat[2] & 0777;
1845 1881 printf "%03o\n", $mode;
1846 1882 exit 0;
1847 1883 } else {
1848 1884 exit 1;
1849 1885 }
1850 1886 ' $1
1851 1887 }
1852 1888
1853 1889 function build_old_new_teamware
1854 1890 {
1855 1891 typeset olddir="$1"
1856 1892 typeset newdir="$2"
1857 1893
1858 1894 # If the child's version doesn't exist then
1859 1895 # get a readonly copy.
1860 1896
1861 1897 if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1862 1898 $SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1863 1899 fi
1864 1900
1865 1901 # The following two sections propagate file permissions the
1866 1902 # same way SCCS does. If the file is already under version
1867 1903 # control, always use permissions from the SCCS/s.file. If
1868 1904 # the file is not under SCCS control, use permissions from the
1869 1905 # working copy. In all cases, the file copied to the webrev
1870 1906 # is set to read only, and group/other permissions are set to
1871 1907 # match those of the file owner. This way, even if the file
1872 1908 # is currently checked out, the webrev will display the final
1873 1909 # permissions that would result after check in.
1874 1910
1875 1911 #
1876 1912 # Snag new version of file.
1877 1913 #
1878 1914 rm -f $newdir/$DIR/$F
1879 1915 cp $CWS/$DIR/$F $newdir/$DIR/$F
1880 1916 if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1881 1917 chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1882 1918 $newdir/$DIR/$F
1883 1919 fi
1884 1920 chmod u-w,go=u $newdir/$DIR/$F
1885 1921
1886 1922 #
1887 1923 # Get the parent's version of the file. First see whether the
1888 1924 # child's version is checked out and get the parent's version
1889 1925 # with keywords expanded or unexpanded as appropriate.
1890 1926 #
1891 1927 if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1892 1928 ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1893 1929 # Parent is not a real workspace, but just a raw
1894 1930 # directory tree - use the file that's there as
1895 1931 # the old file.
1896 1932
1897 1933 rm -f $olddir/$PDIR/$PF
1898 1934 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1899 1935 else
1900 1936 if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1901 1937 real_parent=$PWS
1902 1938 else
1903 1939 real_parent=$RWS
1904 1940 fi
1905 1941
1906 1942 rm -f $olddir/$PDIR/$PF
1907 1943
1908 1944 if [[ -f $real_parent/$PDIR/$PF ]]; then
1909 1945 if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1910 1946 $SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1911 1947 $olddir/$PDIR/$PF
1912 1948 else
1913 1949 $SCCS get -s -p $real_parent/$PDIR/$PF > \
1914 1950 $olddir/$PDIR/$PF
1915 1951 fi
1916 1952 chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1917 1953 $olddir/$PDIR/$PF
1918 1954 fi
1919 1955 fi
1920 1956 if [[ -f $olddir/$PDIR/$PF ]]; then
1921 1957 chmod u-w,go=u $olddir/$PDIR/$PF
1922 1958 fi
1923 1959 }
1924 1960
1925 1961 function build_old_new_mercurial
1926 1962 {
1927 1963 typeset olddir="$1"
1928 1964 typeset newdir="$2"
1929 1965 typeset old_mode=
1930 1966 typeset new_mode=
1931 1967 typeset file
1932 1968
1933 1969 #
1934 1970 # Get old file mode, from the parent revision manifest entry.
1935 1971 # Mercurial only stores a "file is executable" flag, but the
1936 1972 # manifest will display an octal mode "644" or "755".
1937 1973 #
1938 1974 if [[ "$PDIR" == "." ]]; then
1939 1975 file="$PF"
1940 1976 else
1941 1977 file="$PDIR/$PF"
1942 1978 fi
1943 1979 file=`echo $file | $SED 's#/#\\\/#g'`
1944 1980 # match the exact filename, and return only the permission digits
1945 1981 old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1946 1982 < $HG_PARENT_MANIFEST`
1947 1983
1948 1984 #
1949 1985 # Get new file mode, directly from the filesystem.
1950 1986 # Normalize the mode to match Mercurial's behavior.
1951 1987 #
1952 1988 new_mode=`get_file_mode $CWS/$DIR/$F`
1953 1989 if [[ -n "$new_mode" ]]; then
1954 1990 if [[ "$new_mode" = *[1357]* ]]; then
1955 1991 new_mode=755
1956 1992 else
1957 1993 new_mode=644
1958 1994 fi
1959 1995 fi
1960 1996
1961 1997 #
1962 1998 # new version of the file.
1963 1999 #
1964 2000 rm -rf $newdir/$DIR/$F
1965 2001 if [[ -e $CWS/$DIR/$F ]]; then
1966 2002 cp $CWS/$DIR/$F $newdir/$DIR/$F
1967 2003 if [[ -n $new_mode ]]; then
1968 2004 chmod $new_mode $newdir/$DIR/$F
1969 2005 else
1970 2006 # should never happen
1971 2007 print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1972 2008 fi
1973 2009 fi
1974 2010
1975 2011 #
1976 2012 # parent's version of the file
1977 2013 #
1978 2014 # Note that we get this from the last version common to both
1979 2015 # ourselves and the parent. References are via $CWS since we have no
1980 2016 # guarantee that the parent workspace is reachable via the filesystem.
1981 2017 #
1982 2018 if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1983 2019 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1984 2020 elif [[ -n $HG_PARENT ]]; then
1985 2021 hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1986 2022 $olddir/$PDIR/$PF 2>/dev/null
1987 2023
1988 2024 if (( $? != 0 )); then
1989 2025 rm -f $olddir/$PDIR/$PF
1990 2026 else
|
↓ open down ↓ |
199 lines elided |
↑ open up ↑ |
1991 2027 if [[ -n $old_mode ]]; then
1992 2028 chmod $old_mode $olddir/$PDIR/$PF
1993 2029 else
1994 2030 # should never happen
1995 2031 print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1996 2032 fi
1997 2033 fi
1998 2034 fi
1999 2035 }
2000 2036
2037 +function build_old_new_git
2038 +{
2039 + typeset olddir="$1"
2040 + typeset newdir="$2"
2041 + typeset old_mode=
2042 + typeset new_mode=
2043 + typeset old_object=
2044 + typeset new_object=
2045 + typeset file
2046 + typeset type
2047 +
2048 + #
2049 + # Get old file and its mode from the git object tree
2050 + #
2051 + if [[ "$PDIR" == "." ]]; then
2052 + file="$PF"
2053 + else
2054 + file="$PDIR/$PF"
2055 + fi
2056 + git ls-tree $GIT_PARENT $file | read old_mode type old_object junk
2057 + git cat-file $type $old_object > $olddir/$file 2>/dev/null
2058 +
2059 + if (( $? != 0 )); then
2060 + rm -f $olddir/$PDIR/$PF
2061 + else
2062 + if [[ -n $old_mode ]]; then
2063 + chmod $old_mode $olddir/$PDIR/$PF
2064 + else
2065 + # should never happen
2066 + print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
2067 + fi
2068 + fi
2069 +
2070 + #
2071 + # new version of the file.
2072 + #
2073 + rm -rf $newdir/$DIR/$F
2074 + if [[ -e $CWS/../$DIR/$F ]]; then
2075 + cp $CWS/../$DIR/$F $newdir/$DIR/$F
2076 + # Temporary new_node = old_mode
2077 + new_mode=$old_mode
2078 + if [[ -n $new_mode ]]; then
2079 + chmod $new_mode $newdir/$DIR/$F
2080 + else
2081 + # should never happen
2082 + print -u2 "ERROR: set mode of $newdir/$DIR/$F"
2083 + fi
2084 + fi
2085 +
2086 +}
2087 +
2001 2088 function build_old_new_subversion
2002 2089 {
2003 2090 typeset olddir="$1"
2004 2091 typeset newdir="$2"
2005 2092
2006 2093 # Snag new version of file.
2007 2094 rm -f $newdir/$DIR/$F
2008 2095 [[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2009 2096
2010 2097 if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2011 2098 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2012 2099 else
2013 2100 # Get the parent's version of the file.
2014 2101 svn status $CWS/$DIR/$F | read stat file
2015 2102 if [[ $stat != "A" ]]; then
2016 2103 svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2017 2104 fi
2018 2105 fi
2019 2106 }
2020 2107
2021 2108 function build_old_new_unknown
2022 2109 {
2023 2110 typeset olddir="$1"
2024 2111 typeset newdir="$2"
2025 2112
2026 2113 #
2027 2114 # Snag new version of file.
2028 2115 #
2029 2116 rm -f $newdir/$DIR/$F
2030 2117 [[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2031 2118
2032 2119 #
2033 2120 # Snag the parent's version of the file.
2034 2121 #
2035 2122 if [[ -f $PWS/$PDIR/$PF ]]; then
2036 2123 rm -f $olddir/$PDIR/$PF
2037 2124 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2038 2125 fi
2039 2126 }
2040 2127
2041 2128 function build_old_new
2042 2129 {
2043 2130 typeset WDIR=$1
2044 2131 typeset PWS=$2
2045 2132 typeset PDIR=$3
2046 2133 typeset PF=$4
2047 2134 typeset CWS=$5
2048 2135 typeset DIR=$6
2049 2136 typeset F=$7
2050 2137
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
2051 2138 typeset olddir="$WDIR/raw_files/old"
2052 2139 typeset newdir="$WDIR/raw_files/new"
2053 2140
2054 2141 mkdir -p $olddir/$PDIR
2055 2142 mkdir -p $newdir/$DIR
2056 2143
2057 2144 if [[ $SCM_MODE == "teamware" ]]; then
2058 2145 build_old_new_teamware "$olddir" "$newdir"
2059 2146 elif [[ $SCM_MODE == "mercurial" ]]; then
2060 2147 build_old_new_mercurial "$olddir" "$newdir"
2148 + elif [[ $SCM_MODE == "git" ]]; then
2149 + build_old_new_git "$olddir" "$newdir"
2061 2150 elif [[ $SCM_MODE == "subversion" ]]; then
2062 2151 build_old_new_subversion "$olddir" "$newdir"
2063 2152 elif [[ $SCM_MODE == "unknown" ]]; then
2064 2153 build_old_new_unknown "$olddir" "$newdir"
2065 2154 fi
2066 2155
2067 2156 if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2068 2157 print "*** Error: file not in parent or child"
2069 2158 return 1
2070 2159 fi
2071 2160 return 0
2072 2161 }
2073 2162
2074 2163
2075 2164 #
2076 2165 # Usage message.
2077 2166 #
2078 2167 function usage
2079 2168 {
2080 2169 print 'Usage:\twebrev [common-options]
2081 2170 webrev [common-options] ( <file> | - )
2082 2171 webrev [common-options] -w <wx file>
2083 2172
2084 2173 Options:
2085 2174 -C <filename>: Use <filename> for the information tracking configuration.
2086 2175 -D: delete remote webrev
2087 2176 -i <filename>: Include <filename> in the index.html file.
2088 2177 -I <filename>: Use <filename> for the information tracking registry.
2089 2178 -n: do not generate the webrev (useful with -U)
2090 2179 -O: Print bugids/arc cases suitable for OpenSolaris.
2091 2180 -o <outdir>: Output webrev to specified directory.
2092 2181 -p <compare-against>: Use specified parent wkspc or basis for comparison
2093 2182 -t <remote_target>: Specify remote destination for webrev upload
2094 2183 -U: upload the webrev to remote destination
2095 2184 -w <wxfile>: Use specified wx active file.
2096 2185
2097 2186 Environment:
2098 2187 WDIR: Control the output directory.
2099 2188 WEBREV_TRASH_DIR: Set directory for webrev delete.
2100 2189
2101 2190 SCM Specific Options:
2102 2191 TeamWare: webrev [common-options] -l [arguments to 'putback']
2103 2192
2104 2193 SCM Environment:
2105 2194 CODEMGR_WS: Workspace location.
2106 2195 CODEMGR_PARENT: Parent workspace location.
2107 2196 '
2108 2197
2109 2198 exit 2
2110 2199 }
2111 2200
2112 2201 #
2113 2202 #
2114 2203 # Main program starts here
2115 2204 #
2116 2205 #
|
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
2117 2206
2118 2207 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2119 2208
2120 2209 set +o noclobber
2121 2210
2122 2211 PATH=$(dirname $(whence $0)):$PATH
2123 2212
2124 2213 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
2125 2214 [[ -z $WX ]] && WX=`look_for_prog wx`
2126 2215 [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2216 +[[ -z $GIT_ACTIVE ]] && GIT_ACTIVE=`look_for_prog git-active`
2127 2217 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
2128 2218 [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
2129 2219 [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
2130 2220 [[ -z $PERL ]] && PERL=`look_for_prog perl`
2131 2221 [[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2132 2222 [[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2133 2223 [[ -z $AWK ]] && AWK=`look_for_prog nawk`
2134 2224 [[ -z $AWK ]] && AWK=`look_for_prog gawk`
2135 2225 [[ -z $AWK ]] && AWK=`look_for_prog awk`
2136 2226 [[ -z $SCP ]] && SCP=`look_for_prog scp`
2137 2227 [[ -z $SED ]] && SED=`look_for_prog sed`
2138 2228 [[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2139 2229 [[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
2140 2230 [[ -z $GREP ]] && GREP=`look_for_prog grep`
2141 2231 [[ -z $FIND ]] && FIND=`look_for_prog find`
2142 2232
2143 2233 # set name of trash directory for remote webrev deletion
2144 2234 TRASH_DIR=".trash"
2145 2235 [[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
2146 2236
2147 2237 if [[ ! -x $PERL ]]; then
2148 2238 print -u2 "Error: No perl interpreter found. Exiting."
2149 2239 exit 1
2150 2240 fi
2151 2241
2152 2242 if [[ ! -x $WHICH_SCM ]]; then
2153 2243 print -u2 "Error: Could not find which_scm. Exiting."
2154 2244 exit 1
2155 2245 fi
2156 2246
2157 2247 #
2158 2248 # These aren't fatal, but we want to note them to the user.
2159 2249 # We don't warn on the absence of 'wx' until later when we've
2160 2250 # determined that we actually need to try to invoke it.
2161 2251 #
2162 2252 [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
2163 2253 [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
2164 2254 [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2165 2255
2166 2256 # Declare global total counters.
2167 2257 integer TOTL TINS TDEL TMOD TUNC
2168 2258
2169 2259 # default remote host for upload/delete
2170 2260 typeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2171 2261 # prefixes for upload targets
2172 2262 typeset -r rsync_prefix="rsync://"
2173 2263 typeset -r ssh_prefix="ssh://"
2174 2264
2175 2265 Cflag=
2176 2266 Dflag=
2177 2267 flist_mode=
2178 2268 flist_file=
2179 2269 iflag=
2180 2270 Iflag=
2181 2271 lflag=
2182 2272 Nflag=
2183 2273 nflag=
2184 2274 Oflag=
2185 2275 oflag=
2186 2276 pflag=
2187 2277 tflag=
2188 2278 uflag=
2189 2279 Uflag=
2190 2280 wflag=
2191 2281 remote_target=
2192 2282
2193 2283 #
2194 2284 # NOTE: when adding/removing options it is necessary to sync the list
2195 2285 # with usr/src/tools/onbld/hgext/cdm.py
2196 2286 #
2197 2287 while getopts "C:Di:I:lnNo:Op:t:Uw" opt
2198 2288 do
2199 2289 case $opt in
2200 2290 C) Cflag=1
2201 2291 ITSCONF=$OPTARG;;
2202 2292
2203 2293 D) Dflag=1;;
2204 2294
2205 2295 i) iflag=1
2206 2296 INCLUDE_FILE=$OPTARG;;
2207 2297
2208 2298 I) Iflag=1
2209 2299 ITSREG=$OPTARG;;
2210 2300
2211 2301 #
2212 2302 # If -l has been specified, we need to abort further options
2213 2303 # processing, because subsequent arguments are going to be
2214 2304 # arguments to 'putback -n'.
2215 2305 #
2216 2306 l) lflag=1
2217 2307 break;;
2218 2308
2219 2309 N) Nflag=1;;
2220 2310
2221 2311 n) nflag=1;;
2222 2312
2223 2313 O) Oflag=1;;
2224 2314
2225 2315 o) oflag=1
2226 2316 WDIR=$OPTARG;;
2227 2317
2228 2318 p) pflag=1
2229 2319 codemgr_parent=$OPTARG;;
2230 2320
2231 2321 t) tflag=1
2232 2322 remote_target=$OPTARG;;
2233 2323
2234 2324 U) Uflag=1;;
2235 2325
2236 2326 w) wflag=1;;
2237 2327
2238 2328 ?) usage;;
2239 2329 esac
2240 2330 done
2241 2331
2242 2332 FLIST=/tmp/$$.flist
2243 2333
2244 2334 if [[ -n $wflag && -n $lflag ]]; then
2245 2335 usage
2246 2336 fi
2247 2337
2248 2338 # more sanity checking
2249 2339 if [[ -n $nflag && -z $Uflag ]]; then
2250 2340 print "it does not make sense to skip webrev generation" \
2251 2341 "without -U"
2252 2342 exit 1
2253 2343 fi
2254 2344
2255 2345 if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2256 2346 echo "remote target has to be used only for upload or delete"
2257 2347 exit 1
2258 2348 fi
2259 2349
2260 2350 #
2261 2351 # For the invocation "webrev -n -U" with no other options, webrev will assume
2262 2352 # that the webrev exists in ${CWS}/webrev, but will upload it using the name
2263 2353 # $(basename ${CWS}). So we need to get CWS set before we skip any remaining
2264 2354 # logic.
2265 2355 #
2266 2356 $WHICH_SCM | read SCM_MODE junk || exit 1
2267 2357 if [[ $SCM_MODE == "teamware" ]]; then
2268 2358 #
2269 2359 # Teamware priorities:
2270 2360 # 1. CODEMGR_WS from the environment
2271 2361 # 2. workspace name
2272 2362 #
2273 2363 [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2274 2364 if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2275 2365 print -u2 "$codemgr_ws: no such workspace"
2276 2366 exit 1
2277 2367 fi
2278 2368 [[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
2279 2369 codemgr_ws=$(cd $codemgr_ws;print $PWD)
2280 2370 CODEMGR_WS=$codemgr_ws
2281 2371 CWS=$codemgr_ws
|
↓ open down ↓ |
145 lines elided |
↑ open up ↑ |
2282 2372 elif [[ $SCM_MODE == "mercurial" ]]; then
2283 2373 #
2284 2374 # Mercurial priorities:
2285 2375 # 1. hg root from CODEMGR_WS environment variable
2286 2376 # 2. hg root from directory of invocation
2287 2377 #
2288 2378 [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2289 2379 codemgr_ws=$(hg root -R $CODEMGR_WS 2>/dev/null)
2290 2380 [[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
2291 2381 CWS=$codemgr_ws
2382 +elif [[ $SCM_MODE == "git" ]]; then
2383 + #
2384 + # Git priorities:
2385 + # 1. git rev-parse --git-dir from CODEMGR_WS environment variable
2386 + # 2. git rev-parse --git-dir from directory of invocation
2387 + #
2388 + [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2389 + codemgr_ws=$(git --git-dir=$CODEMGR_WS rev-parse --git-dir \
2390 + 2>/dev/null)
2391 + [[ -z $codemgr_ws ]] && \
2392 + codemgr_ws=$(git rev-parse --git-dir 2>/dev/null)
2393 + CWS=$codemgr_ws
2292 2394 elif [[ $SCM_MODE == "subversion" ]]; then
2293 2395 #
2294 2396 # Subversion priorities:
2295 2397 # 1. CODEMGR_WS from environment
2296 2398 # 2. Relative path from current directory to SVN repository root
2297 2399 #
2298 2400 if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2299 2401 CWS=$CODEMGR_WS
2300 2402 else
2301 2403 svn info | while read line; do
2302 2404 if [[ $line == "URL: "* ]]; then
2303 2405 url=${line#URL: }
2304 2406 elif [[ $line == "Repository Root: "* ]]; then
2305 2407 repo=${line#Repository Root: }
2306 2408 fi
2307 2409 done
2308 2410
2309 2411 rel=${url#$repo}
2310 2412 CWS=${PWD%$rel}
2311 2413 fi
2312 2414 fi
2313 2415
2314 2416 #
2315 2417 # If no SCM has been determined, take either the environment setting
2316 2418 # setting for CODEMGR_WS, or the current directory if that wasn't set.
2317 2419 #
2318 2420 if [[ -z ${CWS} ]]; then
2319 2421 CWS=${CODEMGR_WS:-.}
2320 2422 fi
2321 2423
2322 2424
2323 2425
2324 2426 #
2325 2427 # If the command line options indicate no webrev generation, either
2326 2428 # explicitly (-n) or implicitly (-D but not -U), then there's a whole
2327 2429 # ton of logic we can skip.
2328 2430 #
2329 2431 # Instead of increasing indentation, we intentionally leave this loop
2330 2432 # body open here, and exit via break from multiple points within.
2331 2433 # Search for DO_EVERYTHING below to find the break points and closure.
2332 2434 #
2333 2435 for do_everything in 1; do
2334 2436
2335 2437 # DO_EVERYTHING: break point
2336 2438 if [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
2337 2439 break
2338 2440 fi
2339 2441
2340 2442 #
2341 2443 # If this manually set as the parent, and it appears to be an earlier webrev,
2342 2444 # then note that fact and set the parent to the raw_files/new subdirectory.
2343 2445 #
2344 2446 if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2345 2447 parent_webrev="$codemgr_parent"
2346 2448 codemgr_parent="$codemgr_parent/raw_files/new"
2347 2449 fi
2348 2450
2349 2451 if [[ -z $wflag && -z $lflag ]]; then
2350 2452 shift $(($OPTIND - 1))
2351 2453
2352 2454 if [[ $1 == "-" ]]; then
2353 2455 cat > $FLIST
2354 2456 flist_mode="stdin"
2355 2457 flist_done=1
2356 2458 shift
2357 2459 elif [[ -n $1 ]]; then
2358 2460 if [[ ! -r $1 ]]; then
2359 2461 print -u2 "$1: no such file or not readable"
2360 2462 usage
2361 2463 fi
2362 2464 cat $1 > $FLIST
2363 2465 flist_mode="file"
2364 2466 flist_file=$1
2365 2467 flist_done=1
2366 2468 shift
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
2367 2469 else
2368 2470 flist_mode="auto"
2369 2471 fi
2370 2472 fi
2371 2473
2372 2474 #
2373 2475 # Before we go on to further consider -l and -w, work out which SCM we think
2374 2476 # is in use.
2375 2477 #
2376 2478 case "$SCM_MODE" in
2377 -teamware|mercurial|subversion)
2479 +teamware|mercurial|git|subversion)
2378 2480 ;;
2379 2481 unknown)
2380 2482 if [[ $flist_mode == "auto" ]]; then
2381 2483 print -u2 "Unable to determine SCM in use and file list not specified"
2382 2484 print -u2 "See which_scm(1) for SCM detection information."
2383 2485 exit 1
2384 2486 fi
2385 2487 ;;
2386 2488 *)
2387 2489 if [[ $flist_mode == "auto" ]]; then
2388 2490 print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2389 2491 exit 1
2390 2492 fi
2391 2493 ;;
2392 2494 esac
2393 2495
2394 2496 print -u2 " SCM detected: $SCM_MODE"
2395 2497
2396 2498 if [[ -n $lflag ]]; then
2397 2499 #
2398 2500 # If the -l flag is given instead of the name of a file list,
2399 2501 # then generate the file list by extracting file names from a
2400 2502 # putback -n.
2401 2503 #
2402 2504 shift $(($OPTIND - 1))
2403 2505 if [[ $SCM_MODE == "teamware" ]]; then
2404 2506 flist_from_teamware "$*"
2405 2507 else
2406 2508 print -u2 -- "Error: -l option only applies to TeamWare"
2407 2509 exit 1
2408 2510 fi
2409 2511 flist_done=1
2410 2512 shift $#
2411 2513 elif [[ -n $wflag ]]; then
2412 2514 #
2413 2515 # If the -w is given then assume the file list is in Bonwick's "wx"
2414 2516 # command format, i.e. pathname lines alternating with SCCS comment
2415 2517 # lines with blank lines as separators. Use the SCCS comments later
2416 2518 # in building the index.html file.
2417 2519 #
2418 2520 shift $(($OPTIND - 1))
2419 2521 wxfile=$1
2420 2522 if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2421 2523 if [[ -r $CODEMGR_WS/wx/active ]]; then
2422 2524 wxfile=$CODEMGR_WS/wx/active
2423 2525 fi
2424 2526 fi
2425 2527
2426 2528 [[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2427 2529 "be auto-detected (check \$CODEMGR_WS)" && exit 1
2428 2530
2429 2531 if [[ ! -r $wxfile ]]; then
2430 2532 print -u2 "$wxfile: no such file or not readable"
2431 2533 usage
2432 2534 fi
2433 2535
2434 2536 print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2435 2537 flist_from_wx $wxfile
2436 2538 flist_done=1
2437 2539 if [[ -n "$*" ]]; then
2438 2540 shift
2439 2541 fi
2440 2542 elif [[ $flist_mode == "stdin" ]]; then
2441 2543 print -u2 " File list from: standard input"
2442 2544 elif [[ $flist_mode == "file" ]]; then
2443 2545 print -u2 " File list from: $flist_file"
2444 2546 fi
2445 2547
2446 2548 if [[ $# -gt 0 ]]; then
2447 2549 print -u2 "WARNING: unused arguments: $*"
2448 2550 fi
2449 2551
2450 2552 #
2451 2553 # Before we entered the DO_EVERYTHING loop, we should have already set CWS
2452 2554 # and CODEMGR_WS as needed. Here, we set the parent workspace.
2453 2555 #
2454 2556
2455 2557 if [[ $SCM_MODE == "teamware" ]]; then
2456 2558
2457 2559 #
2458 2560 # Teamware priorities:
2459 2561 #
2460 2562 # 1) via -p command line option
2461 2563 # 2) in the user environment
2462 2564 # 3) in the flist
2463 2565 # 4) automatically based on the workspace
2464 2566 #
2465 2567
2466 2568 #
2467 2569 # For 1, codemgr_parent will already be set. Here's 2:
2468 2570 #
2469 2571 [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2470 2572 codemgr_parent=$CODEMGR_PARENT
2471 2573 if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2472 2574 print -u2 "$codemgr_parent: no such directory"
2473 2575 exit 1
2474 2576 fi
2475 2577
2476 2578 #
2477 2579 # If we're in auto-detect mode and we haven't already gotten the file
2478 2580 # list, then see if we can get it by probing for wx.
2479 2581 #
2480 2582 if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
2481 2583 if [[ ! -x $WX ]]; then
2482 2584 print -u2 "WARNING: wx not found!"
2483 2585 fi
2484 2586
2485 2587 #
2486 2588 # We need to use wx list -w so that we get renamed files, etc.
2487 2589 # but only if a wx active file exists-- otherwise wx will
2488 2590 # hang asking us to initialize our wx information.
2489 2591 #
2490 2592 if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2491 2593 print -u2 " File list from: 'wx list -w' ... \c"
2492 2594 $WX list -w > $FLIST
2493 2595 $WX comments > /tmp/$$.wx_comments
2494 2596 wxfile=/tmp/$$.wx_comments
2495 2597 print -u2 "done"
2496 2598 flist_done=1
2497 2599 fi
2498 2600 fi
2499 2601
2500 2602 #
2501 2603 # If by hook or by crook we've gotten a file list by now (perhaps
2502 2604 # from the command line), eval it to extract environment variables from
2503 2605 # it: This is method 3 for finding the parent.
2504 2606 #
2505 2607 if [[ -z $flist_done ]]; then
2506 2608 flist_from_teamware
2507 2609 fi
2508 2610 env_from_flist
2509 2611
2510 2612 #
|
↓ open down ↓ |
123 lines elided |
↑ open up ↑ |
2511 2613 # (4) If we still don't have a value for codemgr_parent, get it
2512 2614 # from workspace.
2513 2615 #
2514 2616 [[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2515 2617 if [[ ! -d $codemgr_parent ]]; then
2516 2618 print -u2 "$CODEMGR_PARENT: no such parent workspace"
2517 2619 exit 1
2518 2620 fi
2519 2621
2520 2622 PWS=$codemgr_parent
2521 -
2623 +\
2624 +
2522 2625 [[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2523 2626
2524 2627 elif [[ $SCM_MODE == "mercurial" ]]; then
2525 2628 #
2526 2629 # Parent can either be specified with -p
2527 2630 # Specified with CODEMGR_PARENT in the environment
2528 2631 # or taken from hg's default path.
2529 2632 #
2530 2633
2531 2634 if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2532 2635 codemgr_parent=$CODEMGR_PARENT
2533 2636 fi
2534 2637
2535 2638 if [[ -z $codemgr_parent ]]; then
2536 2639 codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2537 2640 fi
2538 2641
2539 2642 CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2540 2643 PWS=$codemgr_parent
2541 2644
2542 2645 #
2543 2646 # If the parent is a webrev, we want to do some things against
2544 2647 # the natural workspace parent (file list, comments, etc)
2545 2648 #
2546 2649 if [[ -n $parent_webrev ]]; then
2547 2650 real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2548 2651 else
2549 2652 real_parent=$PWS
2550 2653 fi
2551 2654
2552 2655 #
2553 2656 # If hg-active exists, then we run it. In the case of no explicit
2554 2657 # flist given, we'll use it for our comments. In the case of an
2555 2658 # explicit flist given we'll try to use it for comments for any
2556 2659 # files mentioned in the flist.
2557 2660 #
2558 2661 if [[ -z $flist_done ]]; then
2559 2662 flist_from_mercurial $CWS $real_parent
2560 2663 flist_done=1
2561 2664 fi
2562 2665
2563 2666 #
2564 2667 # If we have a file list now, pull out any variables set
2565 2668 # therein. We do this now (rather than when we possibly use
2566 2669 # hg-active to find comments) to avoid stomping specifications
2567 2670 # in the user-specified flist.
2568 2671 #
2569 2672 if [[ -n $flist_done ]]; then
2570 2673 env_from_flist
2571 2674 fi
2572 2675
2573 2676 #
2574 2677 # Only call hg-active if we don't have a wx formatted file already
2575 2678 #
2576 2679 if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2577 2680 print " Comments from: hg-active -p $real_parent ...\c"
2578 2681 hg_active_wxfile $CWS $real_parent
2579 2682 print " Done."
2580 2683 fi
2581 2684
2582 2685 #
2583 2686 # At this point we must have a wx flist either from hg-active,
2584 2687 # or in general. Use it to try and find our parent revision,
2585 2688 # if we don't have one.
2586 2689 #
2587 2690 if [[ -z $HG_PARENT ]]; then
2588 2691 eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2589 2692 fi
2590 2693
2591 2694 #
2592 2695 # If we still don't have a parent, we must have been given a
|
↓ open down ↓ |
61 lines elided |
↑ open up ↑ |
2593 2696 # wx-style active list with no HG_PARENT specification, run
2594 2697 # hg-active and pull an HG_PARENT out of it, ignore the rest.
2595 2698 #
2596 2699 if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2597 2700 $HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2598 2701 eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2599 2702 elif [[ -z $HG_PARENT ]]; then
2600 2703 print -u2 "Error: Cannot discover parent revision"
2601 2704 exit 1
2602 2705 fi
2706 +elif [[ $SCM_MODE == "git" ]]; then
2707 + #
2708 + # Parent can either be specified with -p
2709 + # Specified with CODEMGR_PARENT in the environment
2710 + # or taken from git config.
2711 + #
2712 +
2713 + if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2714 + codemgr_parent=$CODEMGR_PARENT
2715 + fi
2716 +
2717 + if [[ -z $codemgr_parent ]]; then
2718 + codemgr_parent=$(git --git-dir=$codemgr_ws config \
2719 + remote.origin.url 2>/dev/null)
2720 + fi
2721 +
2722 + CWS_REV=$(git --git-dir=$codemgr_ws rev-parse HEAD 2>/dev/null)
2723 + PWS=$codemgr_parent
2724 +
2725 + #
2726 + # If the parent is a webrev, we want to do some things against
2727 + # the natural workspace parent (file list, comments, etc)
2728 + #
2729 + if [[ -n $parent_webrev ]]; then
2730 + real_parent=$(git --git-dir $codemgr_ws config \
2731 + remote.origin.url 2>/dev/null)
2732 + else
2733 + real_parent=$PWS
2734 + fi
2735 +
2736 + #
2737 + # If git-active exists, then we run it. In the case of no explicit
2738 + # flist given, we'll use it for our comments. In the case of an
2739 + # explicit flist given we'll try to use it for comments for any
2740 + # files mentioned in the flist.
2741 + #
2742 + if [[ -z $flist_done ]]; then
2743 + flist_from_git $CWS $real_parent
2744 + flist_done=1
2745 + fi
2746 +
2747 + #
2748 + # If we have a file list now, pull out any variables set
2749 + # therein. We do this now (rather than when we possibly use
2750 + # git-active to find comments) to avoid stomping specifications
2751 + # in the user-specified flist.
2752 + #
2753 + if [[ -n $flist_done ]]; then
2754 + env_from_flist
2755 + fi
2756 +
2757 + #
2758 + # Only call git-active if we don't have a wx formatted file already
2759 + #
2760 + if [[ -x $GIT_ACTIVE && -z $wxfile ]]; then
2761 + print " Comments from: git-active -p $real_parent ...\c"
2762 + git_active_wxfile $CWS $real_parent
2763 + print " Done."
2764 + fi
2765 +
2766 + #
2767 + # At this point we must have a wx flist either from git-active,
2768 + # or in general. Use it to try and find our parent revision,
2769 + # if we don't have one.
2770 + #
2771 + if [[ -z $GIT_PARENT ]]; then
2772 + eval `$SED -e "s/#.*$//" $wxfile | $GREP GIT_PARENT=`
2773 + fi
2774 +
2775 + #
2776 + # If we still don't have a parent, we must have been given a
2777 + # wx-style active list with no GIT_PARENT specification, run
2778 + # git-active and pull an GIT_PARENT out of it, ignore the rest.
2779 + #
2780 + if [[ -z $GIT_PARENT && -x $GIT_ACTIVE ]]; then
2781 + $GIT_ACTIVE -w $codemgr_ws -p $real_parent | \
2782 + eval `$SED -e "s/#.*$//" | $GREP GIT_PARENT=`
2783 + elif [[ -z $GIT_PARENT ]]; then
2784 + print -u2 "Error: Cannot discover parent revision"
2785 + exit 1
2786 + fi
2787 + WDIR=${WDIR:-$CWS/../webrev}
2603 2788 elif [[ $SCM_MODE == "subversion" ]]; then
2604 2789
2605 2790 #
2606 2791 # We only will have a real parent workspace in the case one
2607 2792 # was specified (be it an older webrev, or another checkout).
2608 2793 #
2609 2794 [[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2610 2795
2611 2796 if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2612 2797 flist_from_subversion $CWS $OLDPWD
2613 2798 fi
2614 2799 else
2615 2800 if [[ $SCM_MODE == "unknown" ]]; then
2616 2801 print -u2 " Unknown type of SCM in use"
2617 2802 else
2618 2803 print -u2 " Unsupported SCM in use: $SCM_MODE"
2619 2804 fi
2620 2805
2621 2806 env_from_flist
2622 2807
2623 2808 if [[ -z $CODEMGR_WS ]]; then
2624 2809 print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2625 2810 exit 1
2626 2811 fi
2627 2812
2628 2813 if [[ -z $CODEMGR_PARENT ]]; then
2629 2814 print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2630 2815 exit 1
2631 2816 fi
2632 2817
2633 2818 CWS=$CODEMGR_WS
2634 2819 PWS=$CODEMGR_PARENT
2635 2820 fi
2636 2821
2637 2822 #
2638 2823 # If the user didn't specify a -i option, check to see if there is a
2639 2824 # webrev-info file in the workspace directory.
2640 2825 #
2641 2826 if [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2642 2827 iflag=1
2643 2828 INCLUDE_FILE="$CWS/webrev-info"
2644 2829 fi
2645 2830
2646 2831 if [[ -n $iflag ]]; then
2647 2832 if [[ ! -r $INCLUDE_FILE ]]; then
2648 2833 print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2649 2834 "not readable."
2650 2835 exit 1
2651 2836 else
2652 2837 #
2653 2838 # $INCLUDE_FILE may be a relative path, and the script alters
2654 2839 # PWD, so we just stash a copy in /tmp.
2655 2840 #
2656 2841 cp $INCLUDE_FILE /tmp/$$.include
2657 2842 fi
2658 2843 fi
2659 2844
2660 2845 # DO_EVERYTHING: break point
2661 2846 if [[ -n $Nflag ]]; then
2662 2847 break
2663 2848 fi
2664 2849
2665 2850 typeset -A itsinfo
2666 2851 typeset -r its_sed_script=/tmp/$$.its_sed
2667 2852 valid_prefixes=
2668 2853 if [[ -z $nflag ]]; then
2669 2854 DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
2670 2855 if [[ -n $Iflag ]]; then
2671 2856 REGFILE=$ITSREG
2672 2857 elif [[ -r $HOME/.its.reg ]]; then
2673 2858 REGFILE=$HOME/.its.reg
2674 2859 else
2675 2860 REGFILE=$DEFREGFILE
2676 2861 fi
2677 2862 if [[ ! -r $REGFILE ]]; then
2678 2863 print "ERROR: Unable to read database registry file $REGFILE"
2679 2864 exit 1
2680 2865 elif [[ $REGFILE != $DEFREGFILE ]]; then
2681 2866 print " its.reg from: $REGFILE"
2682 2867 fi
2683 2868
2684 2869 $SED -e '/^#/d' -e '/^[ ]*$/d' $REGFILE | while read LINE; do
2685 2870
2686 2871 name=${LINE%%=*}
2687 2872 value="${LINE#*=}"
2688 2873
2689 2874 if [[ $name == PREFIX ]]; then
2690 2875 p=${value}
2691 2876 valid_prefixes="${p} ${valid_prefixes}"
2692 2877 else
2693 2878 itsinfo["${p}_${name}"]="${value}"
2694 2879 fi
2695 2880 done
2696 2881
2697 2882
2698 2883 DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
2699 2884 CONFFILES=$DEFCONFFILE
2700 2885 if [[ -r $HOME/.its.conf ]]; then
2701 2886 CONFFILES="${CONFFILES} $HOME/.its.conf"
2702 2887 fi
2703 2888 if [[ -n $Cflag ]]; then
2704 2889 CONFFILES="${CONFFILES} ${ITSCONF}"
2705 2890 fi
2706 2891 its_domain=
2707 2892 its_priority=
2708 2893 for cf in ${CONFFILES}; do
2709 2894 if [[ ! -r $cf ]]; then
2710 2895 print "ERROR: Unable to read database configuration file $cf"
2711 2896 exit 1
2712 2897 elif [[ $cf != $DEFCONFFILE ]]; then
2713 2898 print " its.conf: reading $cf"
2714 2899 fi
2715 2900 $SED -e '/^#/d' -e '/^[ ]*$/d' $cf | while read LINE; do
2716 2901 eval "${LINE}"
2717 2902 done
2718 2903 done
2719 2904
2720 2905 #
2721 2906 # If an information tracking system is explicitly identified by prefix,
2722 2907 # we want to disregard the specified priorities and resolve it accordingly.
2723 2908 #
2724 2909 # To that end, we'll build a sed script to do each valid prefix in turn.
2725 2910 #
2726 2911 for p in ${valid_prefixes}; do
2727 2912 #
2728 2913 # When an informational URL was provided, translate it to a
2729 2914 # hyperlink. When omitted, simply use the prefix text.
2730 2915 #
2731 2916 if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
2732 2917 itsinfo["${p}_INFO"]=${p}
2733 2918 else
2734 2919 itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
2735 2920 fi
2736 2921
2737 2922 #
2738 2923 # Assume that, for this invocation of webrev, all references
2739 2924 # to this information tracking system should resolve through
2740 2925 # the same URL.
2741 2926 #
2742 2927 # If the caller specified -O, then always use EXTERNAL_URL.
2743 2928 #
2744 2929 # Otherwise, look in the list of domains for a matching
2745 2930 # INTERNAL_URL.
2746 2931 #
2747 2932 [[ -z $Oflag ]] && for d in ${its_domain}; do
2748 2933 if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
2749 2934 itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
2750 2935 break
2751 2936 fi
2752 2937 done
2753 2938 if [[ -z ${itsinfo["${p}_URL"]} ]]; then
2754 2939 itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
2755 2940 fi
2756 2941
2757 2942 #
2758 2943 # Turn the destination URL into a hyperlink
2759 2944 #
2760 2945 itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
2761 2946
2762 2947 print "/^${p}[ ]/ {
2763 2948 s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
2764 2949 s;^${p};${itsinfo[${p}_INFO]};
2765 2950 }" >> ${its_sed_script}
2766 2951 done
2767 2952
2768 2953 #
2769 2954 # The previous loop took care of explicit specification. Now use
2770 2955 # the configured priorities to attempt implicit translations.
2771 2956 #
2772 2957 for p in ${its_priority}; do
2773 2958 print "/^${itsinfo[${p}_REGEX]}[ ]/ {
2774 2959 s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
2775 2960 }" >> ${its_sed_script}
2776 2961 done
2777 2962 fi
2778 2963
2779 2964 #
2780 2965 # Search for DO_EVERYTHING above for matching "for" statement
2781 2966 # and explanation of this terminator.
2782 2967 #
2783 2968 done
2784 2969
2785 2970 #
2786 2971 # Output directory.
2787 2972 #
2788 2973 WDIR=${WDIR:-$CWS/webrev}
2789 2974
2790 2975 #
2791 2976 # Name of the webrev, derived from the workspace name or output directory;
2792 2977 # in the future this could potentially be an option.
2793 2978 #
2794 2979 if [[ -n $oflag ]]; then
2795 2980 WNAME=${WDIR##*/}
2796 2981 else
2797 2982 WNAME=${CWS##*/}
2798 2983 fi
2799 2984
2800 2985 # Make sure remote target is well formed for remote upload/delete.
2801 2986 if [[ -n $Dflag || -n $Uflag ]]; then
2802 2987 #
2803 2988 # If remote target is not specified, build it from scratch using
2804 2989 # the default values.
2805 2990 #
2806 2991 if [[ -z $tflag ]]; then
2807 2992 remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2808 2993 else
2809 2994 #
2810 2995 # Check upload target prefix first.
2811 2996 #
2812 2997 if [[ "${remote_target}" != ${rsync_prefix}* &&
2813 2998 "${remote_target}" != ${ssh_prefix}* ]]; then
2814 2999 print "ERROR: invalid prefix of upload URI" \
2815 3000 "($remote_target)"
2816 3001 exit 1
2817 3002 fi
2818 3003 #
2819 3004 # If destination specification is not in the form of
2820 3005 # host_spec:remote_dir then assume it is just remote hostname
2821 3006 # and append a colon and destination directory formed from
2822 3007 # local webrev directory name.
2823 3008 #
2824 3009 typeset target_no_prefix=${remote_target##*://}
2825 3010 if [[ ${target_no_prefix} == *:* ]]; then
2826 3011 if [[ "${remote_target}" == *: ]]; then
2827 3012 remote_target=${remote_target}${WNAME}
2828 3013 fi
2829 3014 else
2830 3015 if [[ ${target_no_prefix} == */* ]]; then
2831 3016 print "ERROR: badly formed upload URI" \
2832 3017 "($remote_target)"
2833 3018 exit 1
2834 3019 else
2835 3020 remote_target=${remote_target}:${WNAME}
2836 3021 fi
2837 3022 fi
2838 3023 fi
2839 3024
2840 3025 #
2841 3026 # Strip trailing slash. Each upload method will deal with directory
2842 3027 # specification separately.
2843 3028 #
2844 3029 remote_target=${remote_target%/}
2845 3030 fi
2846 3031
2847 3032 #
2848 3033 # Option -D by itself (option -U not present) implies no webrev generation.
2849 3034 #
2850 3035 if [[ -z $Uflag && -n $Dflag ]]; then
2851 3036 delete_webrev 1 1
2852 3037 exit $?
2853 3038 fi
2854 3039
2855 3040 #
2856 3041 # Do not generate the webrev, just upload it or delete it.
2857 3042 #
2858 3043 if [[ -n $nflag ]]; then
2859 3044 if [[ -n $Dflag ]]; then
2860 3045 delete_webrev 1 1
2861 3046 (( $? == 0 )) || exit $?
2862 3047 fi
2863 3048 if [[ -n $Uflag ]]; then
2864 3049 upload_webrev
2865 3050 exit $?
2866 3051 fi
2867 3052 fi
2868 3053
2869 3054 if [ "${WDIR%%/*}" ]; then
2870 3055 WDIR=$PWD/$WDIR
2871 3056 fi
2872 3057
2873 3058 if [[ ! -d $WDIR ]]; then
2874 3059 mkdir -p $WDIR
2875 3060 (( $? != 0 )) && exit 1
2876 3061 fi
2877 3062
2878 3063 #
2879 3064 # Summarize what we're going to do.
2880 3065 #
2881 3066 if [[ -n $CWS_REV ]]; then
2882 3067 print " Workspace: $CWS (at $CWS_REV)"
2883 3068 else
2884 3069 print " Workspace: $CWS"
2885 3070 fi
2886 3071 if [[ -n $parent_webrev ]]; then
2887 3072 print "Compare against: webrev at $parent_webrev"
2888 3073 else
2889 3074 if [[ -n $HG_PARENT ]]; then
2890 3075 hg_parent_short=`echo $HG_PARENT \
2891 3076 | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2892 3077 print "Compare against: $PWS (at $hg_parent_short)"
2893 3078 else
2894 3079 print "Compare against: $PWS"
2895 3080 fi
2896 3081 fi
2897 3082
2898 3083 [[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE"
2899 3084 print " Output to: $WDIR"
2900 3085
2901 3086 #
2902 3087 # Save the file list in the webrev dir
2903 3088 #
2904 3089 [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
2905 3090
2906 3091 rm -f $WDIR/$WNAME.patch
2907 3092 rm -f $WDIR/$WNAME.ps
2908 3093 rm -f $WDIR/$WNAME.pdf
2909 3094
2910 3095 touch $WDIR/$WNAME.patch
2911 3096
2912 3097 print " Output Files:"
2913 3098
2914 3099 #
2915 3100 # Clean up the file list: Remove comments, blank lines and env variables.
2916 3101 #
2917 3102 $SED -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean
2918 3103 FLIST=/tmp/$$.flist.clean
2919 3104
2920 3105 #
2921 3106 # For Mercurial, create a cache of manifest entries.
2922 3107 #
2923 3108 if [[ $SCM_MODE == "mercurial" ]]; then
2924 3109 #
2925 3110 # Transform the FLIST into a temporary sed script that matches
2926 3111 # relevant entries in the Mercurial manifest as follows:
2927 3112 # 1) The script will be used against the parent revision manifest,
2928 3113 # so for FLIST lines that have two filenames (a renamed file)
2929 3114 # keep only the old name.
2930 3115 # 2) Escape all forward slashes the filename.
2931 3116 # 3) Change the filename into another sed command that matches
2932 3117 # that file in "hg manifest -v" output: start of line, three
2933 3118 # octal digits for file permissions, space, a file type flag
2934 3119 # character, space, the filename, end of line.
2935 3120 #
2936 3121 SEDFILE=/tmp/$$.manifest.sed
2937 3122 $SED '
2938 3123 s#^[^ ]* ##
2939 3124 s#/#\\\/#g
2940 3125 s#^.*$#/^... . &$/p#
2941 3126 ' < $FLIST > $SEDFILE
2942 3127
2943 3128 #
2944 3129 # Apply the generated script to the output of "hg manifest -v"
2945 3130 # to get the relevant subset for this webrev.
2946 3131 #
2947 3132 HG_PARENT_MANIFEST=/tmp/$$.manifest
2948 3133 hg -R $CWS manifest -v -r $HG_PARENT |
2949 3134 $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2950 3135 fi
2951 3136
2952 3137 #
2953 3138 # First pass through the files: generate the per-file webrev HTML-files.
2954 3139 #
2955 3140 cat $FLIST | while read LINE
2956 3141 do
2957 3142 set - $LINE
2958 3143 P=$1
2959 3144
2960 3145 #
2961 3146 # Normally, each line in the file list is just a pathname of a
2962 3147 # file that has been modified or created in the child. A file
2963 3148 # that is renamed in the child workspace has two names on the
2964 3149 # line: new name followed by the old name.
2965 3150 #
2966 3151 oldname=""
2967 3152 oldpath=""
2968 3153 rename=
2969 3154 if [[ $# -eq 2 ]]; then
2970 3155 PP=$2 # old filename
2971 3156 oldname=" (was $PP)"
2972 3157 oldpath="$PP"
2973 3158 rename=1
2974 3159 PDIR=${PP%/*}
2975 3160 if [[ $PDIR == $PP ]]; then
2976 3161 PDIR="." # File at root of workspace
2977 3162 fi
2978 3163
2979 3164 PF=${PP##*/}
2980 3165
2981 3166 DIR=${P%/*}
2982 3167 if [[ $DIR == $P ]]; then
2983 3168 DIR="." # File at root of workspace
2984 3169 fi
2985 3170
2986 3171 F=${P##*/}
2987 3172
2988 3173 else
2989 3174 DIR=${P%/*}
2990 3175 if [[ "$DIR" == "$P" ]]; then
2991 3176 DIR="." # File at root of workspace
2992 3177 fi
2993 3178
2994 3179 F=${P##*/}
2995 3180
2996 3181 PP=$P
2997 3182 PDIR=$DIR
2998 3183 PF=$F
2999 3184 fi
3000 3185
3001 3186 COMM=`getcomments html $P $PP`
3002 3187
3003 3188 print "\t$P$oldname\n\t\t\c"
3004 3189
3005 3190 # Make the webrev mirror directory if necessary
3006 3191 mkdir -p $WDIR/$DIR
3007 3192
3008 3193 #
3009 3194 # If we're in OpenSolaris mode, we enforce a minor policy:
3010 3195 # help to make sure the reviewer doesn't accidentally publish
3011 3196 # source which is in usr/closed/* or deleted_files/usr/closed/*
3012 3197 #
3013 3198 if [[ -n "$Oflag" ]]; then
3014 3199 pclosed=${P##usr/closed/}
3015 3200 pdeleted=${P##deleted_files/usr/closed/}
3016 3201 if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
3017 3202 print "*** Omitting closed source for OpenSolaris" \
3018 3203 "mode review"
3019 3204 continue
3020 3205 fi
3021 3206 fi
3022 3207
3023 3208 #
3024 3209 # We stash old and new files into parallel directories in $WDIR
3025 3210 # and do our diffs there. This makes it possible to generate
3026 3211 # clean looking diffs which don't have absolute paths present.
3027 3212 #
3028 3213
3029 3214 build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
3030 3215 continue
3031 3216
3032 3217 #
3033 3218 # Keep the old PWD around, so we can safely switch back after
3034 3219 # diff generation, such that build_old_new runs in a
3035 3220 # consistent environment.
3036 3221 #
3037 3222 OWD=$PWD
3038 3223 cd $WDIR/raw_files
3039 3224 ofile=old/$PDIR/$PF
3040 3225 nfile=new/$DIR/$F
3041 3226
3042 3227 mv_but_nodiff=
3043 3228 cmp $ofile $nfile > /dev/null 2>&1
3044 3229 if [[ $? == 0 && $rename == 1 ]]; then
3045 3230 mv_but_nodiff=1
3046 3231 fi
3047 3232
3048 3233 #
3049 3234 # If we have old and new versions of the file then run the appropriate
3050 3235 # diffs. This is complicated by a couple of factors:
3051 3236 #
3052 3237 # - renames must be handled specially: we emit a 'remove'
3053 3238 # diff and an 'add' diff
3054 3239 # - new files and deleted files must be handled specially
3055 3240 # - Solaris patch(1m) can't cope with file creation
3056 3241 # (and hence renames) as of this writing.
3057 3242 # - To make matters worse, gnu patch doesn't interpret the
3058 3243 # output of Solaris diff properly when it comes to
3059 3244 # adds and deletes. We need to do some "cleansing"
3060 3245 # transformations:
3061 3246 # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@
3062 3247 # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@
3063 3248 #
3064 3249 cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3065 3250 cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3066 3251
3067 3252 rm -f $WDIR/$DIR/$F.patch
3068 3253 if [[ -z $rename ]]; then
3069 3254 if [ ! -f "$ofile" ]; then
3070 3255 diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3071 3256 > $WDIR/$DIR/$F.patch
3072 3257 elif [ ! -f "$nfile" ]; then
3073 3258 diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3074 3259 > $WDIR/$DIR/$F.patch
3075 3260 else
3076 3261 diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3077 3262 fi
3078 3263 else
3079 3264 diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3080 3265 > $WDIR/$DIR/$F.patch
3081 3266
3082 3267 diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3083 3268 >> $WDIR/$DIR/$F.patch
3084 3269
3085 3270 fi
3086 3271
3087 3272 #
3088 3273 # Tack the patch we just made onto the accumulated patch for the
3089 3274 # whole wad.
3090 3275 #
3091 3276 cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3092 3277
3093 3278 print " patch\c"
3094 3279
3095 3280 if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3096 3281
3097 3282 ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3098 3283 diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3099 3284 > $WDIR/$DIR/$F.cdiff.html
3100 3285 print " cdiffs\c"
3101 3286
3102 3287 ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3103 3288 diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3104 3289 > $WDIR/$DIR/$F.udiff.html
3105 3290
3106 3291 print " udiffs\c"
3107 3292
3108 3293 if [[ -x $WDIFF ]]; then
3109 3294 $WDIFF -c "$COMM" \
3110 3295 -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3111 3296 $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3112 3297 if [[ $? -eq 0 ]]; then
3113 3298 print " wdiffs\c"
3114 3299 else
3115 3300 print " wdiffs[fail]\c"
3116 3301 fi
3117 3302 fi
3118 3303
3119 3304 sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3120 3305 > $WDIR/$DIR/$F.sdiff.html
3121 3306 print " sdiffs\c"
3122 3307
3123 3308 print " frames\c"
3124 3309
3125 3310 rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
3126 3311
3127 3312 difflines $ofile $nfile > $WDIR/$DIR/$F.count
3128 3313
3129 3314 elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3130 3315 # renamed file: may also have differences
3131 3316 difflines $ofile $nfile > $WDIR/$DIR/$F.count
3132 3317 elif [[ -f $nfile ]]; then
3133 3318 # new file: count added lines
3134 3319 difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3135 3320 elif [[ -f $ofile ]]; then
3136 3321 # old file: count deleted lines
3137 3322 difflines $ofile /dev/null > $WDIR/$DIR/$F.count
3138 3323 fi
3139 3324
3140 3325 #
3141 3326 # Now we generate the postscript for this file. We generate diffs
3142 3327 # only in the event that there is delta, or the file is new (it seems
3143 3328 # tree-killing to print out the contents of deleted files).
3144 3329 #
3145 3330 if [[ -f $nfile ]]; then
3146 3331 ocr=$ofile
3147 3332 [[ ! -f $ofile ]] && ocr=/dev/null
3148 3333
3149 3334 if [[ -z $mv_but_nodiff ]]; then
3150 3335 textcomm=`getcomments text $P $PP`
3151 3336 if [[ -x $CODEREVIEW ]]; then
3152 3337 $CODEREVIEW -y "$textcomm" \
3153 3338 -e $ocr $nfile \
3154 3339 > /tmp/$$.psfile 2>/dev/null &&
3155 3340 cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3156 3341 if [[ $? -eq 0 ]]; then
3157 3342 print " ps\c"
3158 3343 else
3159 3344 print " ps[fail]\c"
3160 3345 fi
3161 3346 fi
3162 3347 fi
3163 3348 fi
3164 3349
3165 3350 if [[ -f $ofile ]]; then
3166 3351 source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
3167 3352 print " old\c"
3168 3353 fi
3169 3354
3170 3355 if [[ -f $nfile ]]; then
3171 3356 source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
3172 3357 print " new\c"
3173 3358 fi
3174 3359
3175 3360 cd $OWD
3176 3361
3177 3362 print
3178 3363 done
3179 3364
3180 3365 frame_nav_js > $WDIR/ancnav.js
3181 3366 frame_navigation > $WDIR/ancnav.html
3182 3367
3183 3368 if [[ ! -f $WDIR/$WNAME.ps ]]; then
3184 3369 print " Generating PDF: Skipped: no output available"
3185 3370 elif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
3186 3371 print " Generating PDF: \c"
3187 3372 fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3188 3373 print "Done."
3189 3374 else
3190 3375 print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
3191 3376 fi
3192 3377
3193 3378 # If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3194 3379 # delete it - prevent accidental publishing of closed source
3195 3380
3196 3381 if [[ -n "$Oflag" ]]; then
3197 3382 $FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3198 3383 fi
3199 3384
3200 3385 # Now build the index.html file that contains
3201 3386 # links to the source files and their diffs.
3202 3387
3203 3388 cd $CWS
3204 3389
3205 3390 # Save total changed lines for Code Inspection.
3206 3391 print "$TOTL" > $WDIR/TotalChangedLines
3207 3392
3208 3393 print " index.html: \c"
3209 3394 INDEXFILE=$WDIR/index.html
3210 3395 exec 3<&1 # duplicate stdout to FD3.
3211 3396 exec 1<&- # Close stdout.
3212 3397 exec > $INDEXFILE # Open stdout to index file.
3213 3398
3214 3399 print "$HTML<head>$STDHEAD"
3215 3400 print "<title>$WNAME</title>"
3216 3401 print "</head>"
3217 3402 print "<body id=\"SUNWwebrev\">"
3218 3403 print "<div class=\"summary\">"
3219 3404 print "<h2>Code Review for $WNAME</h2>"
3220 3405
3221 3406 print "<table>"
3222 3407
3223 3408 #
3224 3409 # Get the preparer's name:
3225 3410 #
3226 3411 # If the SCM detected is Mercurial, and the configuration property
3227 3412 # ui.username is available, use that, but be careful to properly escape
3228 3413 # angle brackets (HTML syntax characters) in the email address.
3229 3414 #
3230 3415 # Otherwise, use the current userid in the form "John Doe (jdoe)", but
3231 3416 # to maintain compatibility with passwd(4), we must support '&' substitutions.
3232 3417 #
3233 3418 preparer=
3234 3419 if [[ "$SCM_MODE" == mercurial ]]; then
3235 3420 preparer=`hg showconfig ui.username 2>/dev/null`
3236 3421 if [[ -n "$preparer" ]]; then
3237 3422 preparer="$(echo "$preparer" | html_quote)"
3238 3423 fi
3239 3424 fi
3240 3425 if [[ -z "$preparer" ]]; then
3241 3426 preparer=$(
3242 3427 $PERL -e '
3243 3428 ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3244 3429 if ($login) {
3245 3430 $gcos =~ s/\&/ucfirst($login)/e;
3246 3431 printf "%s (%s)\n", $gcos, $login;
3247 3432 } else {
3248 3433 printf "(unknown)\n";
3249 3434 }
3250 3435 ')
3251 3436 fi
3252 3437
3253 3438 print "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
3254 3439 print "<tr><th>Workspace:</th><td>$CWS"
3255 3440 if [[ -n $CWS_REV ]]; then
3256 3441 print "(at $CWS_REV)"
3257 3442 fi
3258 3443 print "</td></tr>"
3259 3444 print "<tr><th>Compare against:</th><td>"
3260 3445 if [[ -n $parent_webrev ]]; then
3261 3446 print "webrev at $parent_webrev"
3262 3447 else
3263 3448 print "$PWS"
3264 3449 if [[ -n $hg_parent_short ]]; then
3265 3450 print "(at $hg_parent_short)"
3266 3451 fi
3267 3452 fi
3268 3453 print "</td></tr>"
3269 3454 print "<tr><th>Summary of changes:</th><td>"
3270 3455 printCI $TOTL $TINS $TDEL $TMOD $TUNC
3271 3456 print "</td></tr>"
3272 3457
3273 3458 if [[ -f $WDIR/$WNAME.patch ]]; then
3274 3459 wpatch_url="$(print $WNAME.patch | url_encode)"
3275 3460 print "<tr><th>Patch of changes:</th><td>"
3276 3461 print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3277 3462 fi
3278 3463 if [[ -f $WDIR/$WNAME.pdf ]]; then
3279 3464 wpdf_url="$(print $WNAME.pdf | url_encode)"
3280 3465 print "<tr><th>Printable review:</th><td>"
3281 3466 print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3282 3467 fi
3283 3468
3284 3469 if [[ -n "$iflag" ]]; then
3285 3470 print "<tr><th>Author comments:</th><td><div>"
3286 3471 cat /tmp/$$.include
3287 3472 print "</div></td></tr>"
3288 3473 fi
3289 3474 print "</table>"
3290 3475 print "</div>"
3291 3476
3292 3477 #
3293 3478 # Second pass through the files: generate the rest of the index file
3294 3479 #
3295 3480 cat $FLIST | while read LINE
3296 3481 do
3297 3482 set - $LINE
3298 3483 P=$1
3299 3484
3300 3485 if [[ $# == 2 ]]; then
3301 3486 PP=$2
3302 3487 oldname="$PP"
3303 3488 else
3304 3489 PP=$P
3305 3490 oldname=""
3306 3491 fi
3307 3492
3308 3493 mv_but_nodiff=
3309 3494 cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3310 3495 if [[ $? == 0 && -n "$oldname" ]]; then
3311 3496 mv_but_nodiff=1
3312 3497 fi
3313 3498
3314 3499 DIR=${P%/*}
3315 3500 if [[ $DIR == $P ]]; then
3316 3501 DIR="." # File at root of workspace
3317 3502 fi
3318 3503
3319 3504 # Avoid processing the same file twice.
3320 3505 # It's possible for renamed files to
3321 3506 # appear twice in the file list
3322 3507
3323 3508 F=$WDIR/$P
3324 3509
3325 3510 print "<p>"
3326 3511
3327 3512 # If there's a diffs file, make diffs links
3328 3513
3329 3514 if [[ -f $F.cdiff.html ]]; then
3330 3515 cdiff_url="$(print $P.cdiff.html | url_encode)"
3331 3516 udiff_url="$(print $P.udiff.html | url_encode)"
3332 3517 print "<a href=\"$cdiff_url\">Cdiffs</a>"
3333 3518 print "<a href=\"$udiff_url\">Udiffs</a>"
3334 3519
3335 3520 if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3336 3521 wdiff_url="$(print $P.wdiff.html | url_encode)"
3337 3522 print "<a href=\"$wdiff_url\">Wdiffs</a>"
3338 3523 fi
3339 3524
3340 3525 sdiff_url="$(print $P.sdiff.html | url_encode)"
3341 3526 print "<a href=\"$sdiff_url\">Sdiffs</a>"
3342 3527
3343 3528 frames_url="$(print $P.frames.html | url_encode)"
3344 3529 print "<a href=\"$frames_url\">Frames</a>"
3345 3530 else
3346 3531 print " ------ ------ ------"
3347 3532
3348 3533 if [[ -x $WDIFF ]]; then
3349 3534 print " ------"
3350 3535 fi
3351 3536
3352 3537 print " ------"
3353 3538 fi
3354 3539
3355 3540 # If there's an old file, make the link
3356 3541
3357 3542 if [[ -f $F-.html ]]; then
3358 3543 oldfile_url="$(print $P-.html | url_encode)"
3359 3544 print "<a href=\"$oldfile_url\">Old</a>"
3360 3545 else
3361 3546 print " ---"
3362 3547 fi
3363 3548
3364 3549 # If there's an new file, make the link
3365 3550
3366 3551 if [[ -f $F.html ]]; then
3367 3552 newfile_url="$(print $P.html | url_encode)"
3368 3553 print "<a href=\"$newfile_url\">New</a>"
3369 3554 else
3370 3555 print " ---"
3371 3556 fi
3372 3557
3373 3558 if [[ -f $F.patch ]]; then
3374 3559 patch_url="$(print $P.patch | url_encode)"
3375 3560 print "<a href=\"$patch_url\">Patch</a>"
3376 3561 else
3377 3562 print " -----"
3378 3563 fi
3379 3564
3380 3565 if [[ -f $WDIR/raw_files/new/$P ]]; then
3381 3566 rawfiles_url="$(print raw_files/new/$P | url_encode)"
3382 3567 print "<a href=\"$rawfiles_url\">Raw</a>"
3383 3568 else
3384 3569 print " ---"
3385 3570 fi
3386 3571
3387 3572 print "<b>$P</b>"
3388 3573
3389 3574 # For renamed files, clearly state whether or not they are modified
3390 3575 if [[ -n "$oldname" ]]; then
3391 3576 if [[ -n "$mv_but_nodiff" ]]; then
3392 3577 print "<i>(renamed only, was $oldname)</i>"
3393 3578 else
3394 3579 print "<i>(modified and renamed, was $oldname)</i>"
3395 3580 fi
3396 3581 fi
3397 3582
3398 3583 # If there's an old file, but no new file, the file was deleted
3399 3584 if [[ -f $F-.html && ! -f $F.html ]]; then
3400 3585 print " <i>(deleted)</i>"
3401 3586 fi
3402 3587
3403 3588 #
3404 3589 # Check for usr/closed and deleted_files/usr/closed
3405 3590 #
3406 3591 if [ ! -z "$Oflag" ]; then
3407 3592 if [[ $P == usr/closed/* || \
3408 3593 $P == deleted_files/usr/closed/* ]]; then
3409 3594 print " <i>Closed source: omitted from" \
3410 3595 "this review</i>"
3411 3596 fi
3412 3597 fi
3413 3598
3414 3599 print "</p>"
3415 3600 # Insert delta comments
3416 3601
3417 3602 print "<blockquote><pre>"
3418 3603 getcomments html $P $PP
3419 3604 print "</pre>"
3420 3605
3421 3606 # Add additional comments comment
3422 3607
3423 3608 print "<!-- Add comments to explain changes in $P here -->"
3424 3609
3425 3610 # Add count of changes.
3426 3611
3427 3612 if [[ -f $F.count ]]; then
3428 3613 cat $F.count
3429 3614 rm $F.count
3430 3615 fi
3431 3616
3432 3617 if [[ $SCM_MODE == "teamware" ||
3433 3618 $SCM_MODE == "mercurial" ||
3434 3619 $SCM_MODE == "unknown" ]]; then
3435 3620
3436 3621 # Include warnings for important file mode situations:
3437 3622 # 1) New executable files
3438 3623 # 2) Permission changes of any kind
3439 3624 # 3) Existing executable files
3440 3625
3441 3626 old_mode=
3442 3627 if [[ -f $WDIR/raw_files/old/$PP ]]; then
3443 3628 old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3444 3629 fi
3445 3630
3446 3631 new_mode=
3447 3632 if [[ -f $WDIR/raw_files/new/$P ]]; then
3448 3633 new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3449 3634 fi
3450 3635
3451 3636 if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3452 3637 print "<span class=\"chmod\">"
3453 3638 print "<p>new executable file: mode $new_mode</p>"
3454 3639 print "</span>"
3455 3640 elif [[ -n "$old_mode" && -n "$new_mode" &&
3456 3641 "$old_mode" != "$new_mode" ]]; then
3457 3642 print "<span class=\"chmod\">"
3458 3643 print "<p>mode change: $old_mode to $new_mode</p>"
3459 3644 print "</span>"
3460 3645 elif [[ "$new_mode" = *[1357]* ]]; then
3461 3646 print "<span class=\"chmod\">"
3462 3647 print "<p>executable file: mode $new_mode</p>"
3463 3648 print "</span>"
3464 3649 fi
3465 3650 fi
3466 3651
3467 3652 print "</blockquote>"
3468 3653 done
3469 3654
3470 3655 print
3471 3656 print
3472 3657 print "<hr></hr>"
3473 3658 print "<p style=\"font-size: small\">"
3474 3659 print "This code review page was prepared using <b>$0</b>."
3475 3660 print "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3476 3661 print "OpenSolaris</a> project. The latest version may be obtained"
3477 3662 print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3478 3663 print "</body>"
3479 3664 print "</html>"
3480 3665
3481 3666 exec 1<&- # Close FD 1.
3482 3667 exec 1<&3 # dup FD 3 to restore stdout.
3483 3668 exec 3<&- # close FD 3.
3484 3669
3485 3670 print "Done."
3486 3671
3487 3672 #
3488 3673 # If remote deletion was specified and fails do not continue.
3489 3674 #
3490 3675 if [[ -n $Dflag ]]; then
3491 3676 delete_webrev 1 1
3492 3677 (( $? == 0 )) || exit $?
3493 3678 fi
3494 3679
3495 3680 if [[ -n $Uflag ]]; then
3496 3681 upload_webrev
3497 3682 exit $?
3498 3683 fi
|
↓ open down ↓ |
886 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX