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