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