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