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