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