148fe8920SMark J. Nelson#!/usr/bin/ksh93 -p 27c478bd9Sstevel@tonic-gate# 37c478bd9Sstevel@tonic-gate# CDDL HEADER START 47c478bd9Sstevel@tonic-gate# 57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the 6daaffb31Sdp# Common Development and Distribution License (the "License"). 7daaffb31Sdp# You may not use this file except in compliance with the License. 87c478bd9Sstevel@tonic-gate# 97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate# and limitations under the License. 137c478bd9Sstevel@tonic-gate# 147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate# 207c478bd9Sstevel@tonic-gate# CDDL HEADER END 217c478bd9Sstevel@tonic-gate# 229a70fc3bSMark J. Nelson 237c478bd9Sstevel@tonic-gate# 24371d72daSLubomir Sedlacik# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate# Use is subject to license terms. 267c478bd9Sstevel@tonic-gate# 27cdf0c1d5Smjnelson 28cdf0c1d5Smjnelson# 29daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files 30daaffb31Sdp# suitable for doing a code review of source changes via a web page. 31daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just 32daaffb31Sdp# type 'webrev -h'. 337c478bd9Sstevel@tonic-gate# 34daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1) 35daaffb31Sdp# man page. 367c478bd9Sstevel@tonic-gate# 37daaffb31Sdp 387c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown 397c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue 407c478bd9Sstevel@tonic-gateNEW_COLOR=blue 417c478bd9Sstevel@tonic-gate 42daaffb31SdpHTML='<?xml version="1.0"?> 43daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 44daaffb31Sdp "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 45daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' 46daaffb31Sdp 47daaffb31SdpFRAMEHTML='<?xml version="1.0"?> 48daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 49daaffb31Sdp "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> 50daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' 51daaffb31Sdp 52cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta> 53cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta> 54cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta> 55daaffb31Sdp<!-- 56daaffb31Sdp Note to customizers: the body of the webrev is IDed as SUNWwebrev 57daaffb31Sdp to allow easy overriding by users of webrev via the userContent.css 58daaffb31Sdp mechanism available in some browsers. 59daaffb31Sdp 60daaffb31Sdp For example, to have all "removed" information be red instead of 61daaffb31Sdp brown, set a rule in your userContent.css file like: 62daaffb31Sdp 63daaffb31Sdp body#SUNWwebrev span.removed { color: red ! important; } 64daaffb31Sdp--> 65daaffb31Sdp<style type="text/css" media="screen"> 66daaffb31Sdpbody { 67daaffb31Sdp background-color: #eeeeee; 68daaffb31Sdp} 69daaffb31Sdphr { 70daaffb31Sdp border: none 0; 71daaffb31Sdp border-top: 1px solid #aaa; 72daaffb31Sdp height: 1px; 73daaffb31Sdp} 74daaffb31Sdpdiv.summary { 75daaffb31Sdp font-size: .8em; 76daaffb31Sdp border-bottom: 1px solid #aaa; 77daaffb31Sdp padding-left: 1em; 78daaffb31Sdp padding-right: 1em; 79daaffb31Sdp} 80daaffb31Sdpdiv.summary h2 { 81daaffb31Sdp margin-bottom: 0.3em; 82daaffb31Sdp} 83daaffb31Sdpdiv.summary table th { 84daaffb31Sdp text-align: right; 85daaffb31Sdp vertical-align: top; 86daaffb31Sdp white-space: nowrap; 87daaffb31Sdp} 88daaffb31Sdpspan.lineschanged { 89daaffb31Sdp font-size: 0.7em; 90daaffb31Sdp} 91daaffb31Sdpspan.oldmarker { 92daaffb31Sdp color: red; 93daaffb31Sdp font-size: large; 94daaffb31Sdp font-weight: bold; 95daaffb31Sdp} 96daaffb31Sdpspan.newmarker { 97daaffb31Sdp color: green; 98daaffb31Sdp font-size: large; 99daaffb31Sdp font-weight: bold; 100daaffb31Sdp} 101daaffb31Sdpspan.removed { 102daaffb31Sdp color: brown; 103daaffb31Sdp} 104daaffb31Sdpspan.changed { 105daaffb31Sdp color: blue; 106daaffb31Sdp} 107daaffb31Sdpspan.new { 108daaffb31Sdp color: blue; 109daaffb31Sdp font-weight: bold; 110daaffb31Sdp} 111cdf0c1d5Smjnelsonspan.chmod { 112cdf0c1d5Smjnelson font-size: 0.7em; 113cdf0c1d5Smjnelson color: #db7800; 114cdf0c1d5Smjnelson} 115daaffb31Sdpa.print { font-size: x-small; } 116daaffb31Sdpa:hover { background-color: #ffcc99; } 117daaffb31Sdp</style> 118daaffb31Sdp 119daaffb31Sdp<style type="text/css" media="print"> 120daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; } 121daaffb31Sdpspan.removed { color: #444; font-style: italic } 122daaffb31Sdpspan.changed { font-weight: bold; } 123daaffb31Sdpspan.new { font-weight: bold; } 124daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; } 125daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; } 126daaffb31Sdpa.print {display: none} 127daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; } 128daaffb31Sdp</style> 129daaffb31Sdp' 130daaffb31Sdp 131daaffb31Sdp# 132daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't 133daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs). 134daaffb31Sdp# 135daaffb31SdpUDIFFCSS=' 136daaffb31Sdp<style type="text/css" media="screen"> 137daaffb31Sdpspan.new { 138daaffb31Sdp color: blue; 139daaffb31Sdp font-weight: normal; 140daaffb31Sdp} 141daaffb31Sdp</style> 142daaffb31Sdp' 143daaffb31Sdp 144b0088928SVladimir Kotal# 145b0088928SVladimir Kotal# Display remote target with prefix and trailing slash. 146b0088928SVladimir Kotal# 147b0088928SVladimir Kotalfunction print_upload_header 148b0088928SVladimir Kotal{ 149b0088928SVladimir Kotal typeset -r prefix=$1 150b0088928SVladimir Kotal typeset display_target 151b0088928SVladimir Kotal 152b0088928SVladimir Kotal if [[ -z $tflag ]]; then 153b0088928SVladimir Kotal display_target=${prefix}${remote_target} 154b0088928SVladimir Kotal else 155b0088928SVladimir Kotal display_target=${remote_target} 156b0088928SVladimir Kotal fi 157b0088928SVladimir Kotal 158b0088928SVladimir Kotal if [[ ${display_target} != */ ]]; then 159b0088928SVladimir Kotal display_target=${display_target}/ 160b0088928SVladimir Kotal fi 161b0088928SVladimir Kotal 162b0088928SVladimir Kotal print " Upload to: ${display_target}\n" \ 163b0088928SVladimir Kotal " Uploading: \c" 164b0088928SVladimir Kotal} 165b0088928SVladimir Kotal 166b0088928SVladimir Kotal# 16702d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error. 168b0088928SVladimir Kotal# 169ba44d8a2SVladimir Kotalfunction rsync_upload 17002d26c39SVladimir Kotal{ 171b0088928SVladimir Kotal if (( $# != 2 )); then 172b0088928SVladimir Kotal print "\nERROR: rsync_upload: wrong usage ($#)" 173b0088928SVladimir Kotal exit 1 17402d26c39SVladimir Kotal fi 17502d26c39SVladimir Kotal 176b0088928SVladimir Kotal typeset -r dst=$1 177b0088928SVladimir Kotal integer -r print_err_msg=$2 17802d26c39SVladimir Kotal 179b0088928SVladimir Kotal print_upload_header ${rsync_prefix} 180b0088928SVladimir Kotal print "rsync ... \c" 1818a34f8dcSVladimir Kotal typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX ) 182b0088928SVladimir Kotal if [[ -z $err_msg ]]; then 183b0088928SVladimir Kotal print "\nERROR: rsync_upload: cannot create temporary file" 184b0088928SVladimir Kotal return 1 185b0088928SVladimir Kotal fi 186b0088928SVladimir Kotal # 187b0088928SVladimir Kotal # The source directory must end with a slash in order to copy just 188b0088928SVladimir Kotal # directory contents, not the whole directory. 189b0088928SVladimir Kotal # 190b0088928SVladimir Kotal typeset src_dir=$WDIR 191b0088928SVladimir Kotal if [[ ${src_dir} != */ ]]; then 192b0088928SVladimir Kotal src_dir=${src_dir}/ 193b0088928SVladimir Kotal fi 194b0088928SVladimir Kotal $RSYNC -r -q ${src_dir} $dst 2>$err_msg 19502d26c39SVladimir Kotal if (( $? != 0 )); then 196b0088928SVladimir Kotal if (( ${print_err_msg} > 0 )); then 197b0088928SVladimir Kotal print "Failed.\nERROR: rsync failed" 198b0088928SVladimir Kotal print "src dir: '${src_dir}'\ndst dir: '$dst'" 199b0088928SVladimir Kotal print "error messages:" 200b0088928SVladimir Kotal $SED 's/^/> /' $err_msg 201b0088928SVladimir Kotal rm -f $err_msg 202b0088928SVladimir Kotal fi 20302d26c39SVladimir Kotal return 1 20402d26c39SVladimir Kotal fi 20502d26c39SVladimir Kotal 206b0088928SVladimir Kotal rm -f $err_msg 20702d26c39SVladimir Kotal print "Done." 20802d26c39SVladimir Kotal return 0 20902d26c39SVladimir Kotal} 21002d26c39SVladimir Kotal 211b0088928SVladimir Kotal# 212b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success, 213b0088928SVladimir Kotal# 1 on failure. 214b0088928SVladimir Kotal# 215b0088928SVladimir Kotalfunction remote_mkdirs 216b0088928SVladimir Kotal{ 217b0088928SVladimir Kotal typeset -r dir_spec=$1 218b0088928SVladimir Kotal 219b0088928SVladimir Kotal # 220b0088928SVladimir Kotal # If the supplied path is absolute we assume all directories are 221b0088928SVladimir Kotal # created, otherwise try to create all directories in the path 222b0088928SVladimir Kotal # except the last one which will be created by scp. 223b0088928SVladimir Kotal # 224b0088928SVladimir Kotal if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then 225b0088928SVladimir Kotal print "mkdirs \c" 226b0088928SVladimir Kotal # 227b0088928SVladimir Kotal # Remove the last directory from directory specification. 228b0088928SVladimir Kotal # 229b0088928SVladimir Kotal typeset -r dirs_mk=${dir_spec%/*} 2308a34f8dcSVladimir Kotal typeset -r batch_file_mkdir=$( $MKTEMP \ 2318a34f8dcSVladimir Kotal /tmp/webrev_mkdir.XXXXXX ) 232b0088928SVladimir Kotal if [[ -z $batch_file_mkdir ]]; then 233b0088928SVladimir Kotal print "\nERROR: remote_mkdirs:" \ 234b0088928SVladimir Kotal "cannot create temporary file for batch file" 235b0088928SVladimir Kotal return 1 236b0088928SVladimir Kotal fi 237b0088928SVladimir Kotal OLDIFS=$IFS 238b0088928SVladimir Kotal IFS=/ 239b0088928SVladimir Kotal typeset dir 240b0088928SVladimir Kotal for dir in ${dirs_mk}; do 241b0088928SVladimir Kotal # 242b0088928SVladimir Kotal # Use the '-' prefix to ignore mkdir errors in order 243b0088928SVladimir Kotal # to avoid an error in case the directory already 244b0088928SVladimir Kotal # exists. We check the directory with chdir to be sure 245b0088928SVladimir Kotal # there is one. 246b0088928SVladimir Kotal # 247b0088928SVladimir Kotal print -- "-mkdir ${dir}" >> ${batch_file_mkdir} 248b0088928SVladimir Kotal print "chdir ${dir}" >> ${batch_file_mkdir} 249b0088928SVladimir Kotal done 250b0088928SVladimir Kotal IFS=$OLDIFS 2518a34f8dcSVladimir Kotal typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX ) 252b0088928SVladimir Kotal if [[ -z ${sftp_err_msg} ]]; then 253b0088928SVladimir Kotal print "\nERROR: remote_mkdirs:" \ 254b0088928SVladimir Kotal "cannot create temporary file for error messages" 255b0088928SVladimir Kotal return 1 256b0088928SVladimir Kotal fi 257b0088928SVladimir Kotal $SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2 258b0088928SVladimir Kotal if (( $? != 0 )); then 259b0088928SVladimir Kotal print "\nERROR: failed to create remote directories" 260b0088928SVladimir Kotal print "error messages:" 261b0088928SVladimir Kotal $SED 's/^/> /' ${sftp_err_msg} 262b0088928SVladimir Kotal rm -f ${sftp_err_msg} ${batch_file_mkdir} 263b0088928SVladimir Kotal return 1 264b0088928SVladimir Kotal fi 265b0088928SVladimir Kotal rm -f ${sftp_err_msg} ${batch_file_mkdir} 266b0088928SVladimir Kotal fi 267b0088928SVladimir Kotal 268b0088928SVladimir Kotal return 0 269b0088928SVladimir Kotal} 270b0088928SVladimir Kotal 271b0088928SVladimir Kotal# 27202d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error. 273b0088928SVladimir Kotal# 274ba44d8a2SVladimir Kotalfunction ssh_upload 27502d26c39SVladimir Kotal{ 27602d26c39SVladimir Kotal if (( $# != 1 )); then 277b0088928SVladimir Kotal print "\nERROR: ssh_upload: wrong number of arguments" 278b0088928SVladimir Kotal exit 1 27902d26c39SVladimir Kotal fi 28002d26c39SVladimir Kotal 28102d26c39SVladimir Kotal typeset dst=$1 28202d26c39SVladimir Kotal typeset -r host_spec=${dst%%:*} 283ba44d8a2SVladimir Kotal typeset -r dir_spec=${dst#*:} 28402d26c39SVladimir Kotal 285b0088928SVladimir Kotal # 286b0088928SVladimir Kotal # Display the upload information before calling delete_webrev 287b0088928SVladimir Kotal # because it will also print its progress. 288b0088928SVladimir Kotal # 289b0088928SVladimir Kotal print_upload_header ${ssh_prefix} 290b0088928SVladimir Kotal 291b0088928SVladimir Kotal # 292b0088928SVladimir Kotal # If the deletion was explicitly requested there is no need 293b0088928SVladimir Kotal # to perform it again. 294b0088928SVladimir Kotal # 295ba44d8a2SVladimir Kotal if [[ -z $Dflag ]]; then 296b0088928SVladimir Kotal # 297b0088928SVladimir Kotal # We do not care about return value because this might be 298b0088928SVladimir Kotal # the first time this directory is uploaded. 299b0088928SVladimir Kotal # 300ba44d8a2SVladimir Kotal delete_webrev 0 30102d26c39SVladimir Kotal fi 30202d26c39SVladimir Kotal 303b0088928SVladimir Kotal # 304b0088928SVladimir Kotal # Create remote directories. Any error reporting will be done 305b0088928SVladimir Kotal # in remote_mkdirs function. 306b0088928SVladimir Kotal # 307b0088928SVladimir Kotal remote_mkdirs ${dir_spec} 30802d26c39SVladimir Kotal if (( $? != 0 )); then 30902d26c39SVladimir Kotal return 1 31002d26c39SVladimir Kotal fi 31102d26c39SVladimir Kotal 312b0088928SVladimir Kotal print "upload ... \c" 3138a34f8dcSVladimir Kotal typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX ) 314b0088928SVladimir Kotal if [[ -z ${scp_err_msg} ]]; then 315b0088928SVladimir Kotal print "\nERROR: ssh_upload:" \ 316b0088928SVladimir Kotal "cannot create temporary file for error messages" 317b0088928SVladimir Kotal return 1 318b0088928SVladimir Kotal fi 31902d26c39SVladimir Kotal $SCP -q -C -B -o PreferredAuthentications=publickey -r \ 320b0088928SVladimir Kotal $WDIR $dst 2>${scp_err_msg} 32102d26c39SVladimir Kotal if (( $? != 0 )); then 322b0088928SVladimir Kotal print "Failed.\nERROR: scp failed" 323b0088928SVladimir Kotal print "src dir: '$WDIR'\ndst dir: '$dst'" 324b0088928SVladimir Kotal print "error messages:" 325b0088928SVladimir Kotal $SED 's/^/> /' ${scp_err_msg} 326b0088928SVladimir Kotal rm -f ${scp_err_msg} 32702d26c39SVladimir Kotal return 1 32802d26c39SVladimir Kotal fi 32902d26c39SVladimir Kotal 330b0088928SVladimir Kotal rm -f ${scp_err_msg} 33102d26c39SVladimir Kotal print "Done." 33202d26c39SVladimir Kotal return 0 33302d26c39SVladimir Kotal} 33402d26c39SVladimir Kotal 33502d26c39SVladimir Kotal# 336ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp 337b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return 338b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run 339b0088928SVladimir Kotal# only performs deletion. 340ba44d8a2SVladimir Kotal# 341ba44d8a2SVladimir Kotalfunction delete_webrev 342ba44d8a2SVladimir Kotal{ 343b0088928SVladimir Kotal if (( $# < 1 )); then 344b0088928SVladimir Kotal print "delete_webrev: wrong number of arguments" 345b0088928SVladimir Kotal exit 1 346ba44d8a2SVladimir Kotal fi 347ba44d8a2SVladimir Kotal 348b0088928SVladimir Kotal integer -r check=$1 349b0088928SVladimir Kotal integer delete_only=0 350b0088928SVladimir Kotal if (( $# == 2 )); then 351b0088928SVladimir Kotal delete_only=1 352b0088928SVladimir Kotal fi 353b0088928SVladimir Kotal 354b0088928SVladimir Kotal # 355ba44d8a2SVladimir Kotal # Strip the transport specification part of remote target first. 356b0088928SVladimir Kotal # 357ba44d8a2SVladimir Kotal typeset -r stripped_target=${remote_target##*://} 358ba44d8a2SVladimir Kotal typeset -r host_spec=${stripped_target%%:*} 359ba44d8a2SVladimir Kotal typeset -r dir_spec=${stripped_target#*:} 360ba44d8a2SVladimir Kotal typeset dir_rm 361ba44d8a2SVladimir Kotal 362b0088928SVladimir Kotal # 363ba44d8a2SVladimir Kotal # Do not accept an absolute path. 364b0088928SVladimir Kotal # 365ba44d8a2SVladimir Kotal if [[ ${dir_spec} == /* ]]; then 366ba44d8a2SVladimir Kotal return 1 367ba44d8a2SVladimir Kotal fi 368ba44d8a2SVladimir Kotal 369b0088928SVladimir Kotal # 370ba44d8a2SVladimir Kotal # Strip the ending slash. 371b0088928SVladimir Kotal # 372ba44d8a2SVladimir Kotal if [[ ${dir_spec} == */ ]]; then 373ba44d8a2SVladimir Kotal dir_rm=${dir_spec%%/} 374ba44d8a2SVladimir Kotal else 375ba44d8a2SVladimir Kotal dir_rm=${dir_spec} 376ba44d8a2SVladimir Kotal fi 377ba44d8a2SVladimir Kotal 378b0088928SVladimir Kotal if (( ${delete_only} > 0 )); then 379b0088928SVladimir Kotal print " Removing: \c" 380b0088928SVladimir Kotal else 381b0088928SVladimir Kotal print "rmdir \c" 382b0088928SVladimir Kotal fi 383ba44d8a2SVladimir Kotal if [[ -z "$dir_rm" ]]; then 384b0088928SVladimir Kotal print "\nERROR: empty directory for removal" 385ba44d8a2SVladimir Kotal return 1 386ba44d8a2SVladimir Kotal fi 387ba44d8a2SVladimir Kotal 388b0088928SVladimir Kotal # 389ba44d8a2SVladimir Kotal # Prepare batch file. 390b0088928SVladimir Kotal # 3918a34f8dcSVladimir Kotal typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX ) 392ba44d8a2SVladimir Kotal if [[ -z $batch_file_rm ]]; then 393b0088928SVladimir Kotal print "\nERROR: delete_webrev: cannot create temporary file" 394ba44d8a2SVladimir Kotal return 1 395ba44d8a2SVladimir Kotal fi 396ba44d8a2SVladimir Kotal print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm 397ba44d8a2SVladimir Kotal 398b0088928SVladimir Kotal # 399ba44d8a2SVladimir Kotal # Perform remote deletion and remove the batch file. 400b0088928SVladimir Kotal # 4018a34f8dcSVladimir Kotal typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX ) 402b0088928SVladimir Kotal if [[ -z ${sftp_err_msg} ]]; then 403b0088928SVladimir Kotal print "\nERROR: delete_webrev:" \ 404b0088928SVladimir Kotal "cannot create temporary file for error messages" 405b0088928SVladimir Kotal return 1 406b0088928SVladimir Kotal fi 407b0088928SVladimir Kotal $SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2 408ba44d8a2SVladimir Kotal integer -r ret=$? 409ba44d8a2SVladimir Kotal rm -f $batch_file_rm 410ba44d8a2SVladimir Kotal if (( $ret != 0 && $check > 0 )); then 411b0088928SVladimir Kotal print "Failed.\nERROR: failed to remove remote directories" 412b0088928SVladimir Kotal print "error messages:" 413b0088928SVladimir Kotal $SED 's/^/> /' ${sftp_err_msg} 414b0088928SVladimir Kotal rm -f ${sftp_err_msg} 415ba44d8a2SVladimir Kotal return $ret 416ba44d8a2SVladimir Kotal fi 417b0088928SVladimir Kotal rm -f ${sftp_err_msg} 418b0088928SVladimir Kotal if (( ${delete_only} > 0 )); then 419ba44d8a2SVladimir Kotal print "Done." 420b0088928SVladimir Kotal fi 421ba44d8a2SVladimir Kotal 422ba44d8a2SVladimir Kotal return 0 423ba44d8a2SVladimir Kotal} 424ba44d8a2SVladimir Kotal 425ba44d8a2SVladimir Kotal# 42602d26c39SVladimir Kotal# Upload webrev to remote site 42702d26c39SVladimir Kotal# 428ba44d8a2SVladimir Kotalfunction upload_webrev 42902d26c39SVladimir Kotal{ 430b0088928SVladimir Kotal integer ret 43102d26c39SVladimir Kotal 43202d26c39SVladimir Kotal if [[ ! -d "$WDIR" ]]; then 433b0088928SVladimir Kotal print "\nERROR: webrev directory '$WDIR' does not exist" 43402d26c39SVladimir Kotal return 1 43502d26c39SVladimir Kotal fi 43602d26c39SVladimir Kotal 437b0088928SVladimir Kotal # 43802d26c39SVladimir Kotal # Perform a late check to make sure we do not upload closed source 43902d26c39SVladimir Kotal # to remote target when -n is used. If the user used custom remote 44002d26c39SVladimir Kotal # target he probably knows what he is doing. 441b0088928SVladimir Kotal # 44202d26c39SVladimir Kotal if [[ -n $nflag && -z $tflag ]]; then 443ba44d8a2SVladimir Kotal $FIND $WDIR -type d -name closed \ 44402d26c39SVladimir Kotal | $GREP closed >/dev/null 44502d26c39SVladimir Kotal if (( $? == 0 )); then 446b0088928SVladimir Kotal print "\nERROR: directory '$WDIR' contains" \ 447b0088928SVladimir Kotal "\"closed\" directory" 44802d26c39SVladimir Kotal return 1 44902d26c39SVladimir Kotal fi 45002d26c39SVladimir Kotal fi 45102d26c39SVladimir Kotal 452b0088928SVladimir Kotal 453b0088928SVladimir Kotal # 454b0088928SVladimir Kotal # We have the URI for remote destination now so let's start the upload. 455b0088928SVladimir Kotal # 45602d26c39SVladimir Kotal if [[ -n $tflag ]]; then 45702d26c39SVladimir Kotal if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then 458b0088928SVladimir Kotal rsync_upload ${remote_target##$rsync_prefix} 1 459b0088928SVladimir Kotal ret=$? 460b0088928SVladimir Kotal return $ret 46102d26c39SVladimir Kotal elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then 46202d26c39SVladimir Kotal ssh_upload ${remote_target##$ssh_prefix} 463b0088928SVladimir Kotal ret=$? 464b0088928SVladimir Kotal return $ret 46502d26c39SVladimir Kotal fi 46602d26c39SVladimir Kotal else 467b0088928SVladimir Kotal # 468b0088928SVladimir Kotal # Try rsync first and fallback to SSH in case it fails. 469b0088928SVladimir Kotal # 470b0088928SVladimir Kotal rsync_upload ${remote_target} 0 471b0088928SVladimir Kotal ret=$? 472b0088928SVladimir Kotal if (( $ret != 0 )); then 473b0088928SVladimir Kotal print "Failed. (falling back to SSH)" 474ba44d8a2SVladimir Kotal ssh_upload ${remote_target} 475b0088928SVladimir Kotal ret=$? 47602d26c39SVladimir Kotal fi 477b0088928SVladimir Kotal return $ret 47802d26c39SVladimir Kotal fi 47902d26c39SVladimir Kotal} 48002d26c39SVladimir Kotal 481daaffb31Sdp# 482371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd 483371d72daSLubomir Sedlacik# 484371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986. 485371d72daSLubomir Sedlacik# 486371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;= 487371d72daSLubomir Sedlacik# 488371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition 489371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is 490371d72daSLubomir Sedlacik# a path delimiter. 491371d72daSLubomir Sedlacik# 49225cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make 49325cc4e45SVladimir Kotal# the substitution work with GNU sed. 49425cc4e45SVladimir Kotal# 495371d72daSLubomir Sedlacikfunction url_encode 496371d72daSLubomir Sedlacik{ 497b0088928SVladimir Kotal $SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \ 498371d72daSLubomir Sedlacik -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \ 499371d72daSLubomir Sedlacik -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \ 500371d72daSLubomir Sedlacik -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \ 50125cc4e45SVladimir Kotal -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \ 502371d72daSLubomir Sedlacik -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g" 503371d72daSLubomir Sedlacik} 504371d72daSLubomir Sedlacik 505371d72daSLubomir Sedlacik# 506daaffb31Sdp# input_cmd | html_quote | output_cmd 507daaffb31Sdp# or 508daaffb31Sdp# html_quote filename | output_cmd 5097c478bd9Sstevel@tonic-gate# 5107c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block. 5117c478bd9Sstevel@tonic-gate# 5127c478bd9Sstevel@tonic-gatehtml_quote() 5137c478bd9Sstevel@tonic-gate{ 514b0088928SVladimir Kotal $SED -e "s/&/\&/g" -e "s/</\</g" -e "s/>/\>/g" "$@" | expand 5157c478bd9Sstevel@tonic-gate} 5167c478bd9Sstevel@tonic-gate 517daaffb31Sdp# 5180fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd 519daaffb31Sdp# 5200fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the 5210fd2682eSMark J. Nelson# relevant databases. 522daaffb31Sdp# 5230fd2682eSMark J. Nelsonits2url() 5247c478bd9Sstevel@tonic-gate{ 5250fd2682eSMark J. Nelson $SED -f ${its_sed_script} 526daaffb31Sdp} 527daaffb31Sdp 5287c478bd9Sstevel@tonic-gate# 529daaffb31Sdp# strip_unchanged <infile> | output_cmd 5307c478bd9Sstevel@tonic-gate# 531daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it 532daaffb31Sdp# easier for a code reviewer to find the bits that have changed. 5337c478bd9Sstevel@tonic-gate# 534daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some 535daaffb31Sdp# identical lines are retained before and after the changed lines to 536daaffb31Sdp# provide some context. The number of these lines is controlled by the 537cdf0c1d5Smjnelson# variable C in the $AWK script below. 538daaffb31Sdp# 539daaffb31Sdp# The script detects changed lines as any line that has a "<span class=" 540daaffb31Sdp# string embedded (unchanged lines have no particular class and are not 541daaffb31Sdp# part of a <span>). Blank lines (without a sequence number) are also 542daaffb31Sdp# detected since they flag lines that have been inserted or deleted. 543daaffb31Sdp# 544daaffb31Sdpstrip_unchanged() 545daaffb31Sdp{ 546cdf0c1d5Smjnelson $AWK ' 547daaffb31Sdp BEGIN { C = c = 20 } 548cdf0c1d5Smjnelson NF == 0 || /<span class="/ { 549daaffb31Sdp if (c > C) { 550daaffb31Sdp c -= C 551daaffb31Sdp inx = 0 552daaffb31Sdp if (c > C) { 553cac38512Smjnelson print "\n</pre><hr></hr><pre>" 554daaffb31Sdp inx = c % C 555daaffb31Sdp c = C 556daaffb31Sdp } 557daaffb31Sdp 558daaffb31Sdp for (i = 0; i < c; i++) 559daaffb31Sdp print ln[(inx + i) % C] 560daaffb31Sdp } 561daaffb31Sdp c = 0; 562daaffb31Sdp print 563daaffb31Sdp next 564daaffb31Sdp } 565daaffb31Sdp { if (c >= C) { 566daaffb31Sdp ln[c % C] = $0 567daaffb31Sdp c++; 568daaffb31Sdp next; 569daaffb31Sdp } 570daaffb31Sdp c++; 571daaffb31Sdp print 572daaffb31Sdp } 573cac38512Smjnelson END { if (c > (C * 2)) print "\n</pre><hr></hr>" } 574daaffb31Sdp 575daaffb31Sdp ' $1 576daaffb31Sdp} 577daaffb31Sdp 578daaffb31Sdp# 579daaffb31Sdp# sdiff_to_html 580daaffb31Sdp# 581daaffb31Sdp# This function takes two files as arguments, obtains their diff, and 582daaffb31Sdp# processes the diff output to present the files as an HTML document with 583daaffb31Sdp# the files displayed side-by-side, differences shown in color. It also 584daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third 585daaffb31Sdp# argument. The function takes two files as arguments, then the name of 586daaffb31Sdp# file, the path, and the comment. The HTML will be delivered on stdout, 587daaffb31Sdp# e.g. 588daaffb31Sdp# 589daaffb31Sdp# $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \ 590daaffb31Sdp# new/usr/src/tools/scripts/webrev.sh \ 591daaffb31Sdp# webrev.sh usr/src/tools/scripts \ 592daaffb31Sdp# '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567"> 593daaffb31Sdp# 1234567</a> my bugid' > <file>.html 594daaffb31Sdp# 595daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html 596daaffb31Sdp# in the webrev tree. 597daaffb31Sdp# 598daaffb31Sdp# FYI: This function is rather unusual in its use of awk. The initial 599daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed 600daaffb31Sdp# with editing codes. The changed lines are ignored - we're interested in 601daaffb31Sdp# the editing codes, e.g. 6027c478bd9Sstevel@tonic-gate# 6037c478bd9Sstevel@tonic-gate# 8c8 6047c478bd9Sstevel@tonic-gate# 57a61 6057c478bd9Sstevel@tonic-gate# 63c66,76 6067c478bd9Sstevel@tonic-gate# 68,93d80 6077c478bd9Sstevel@tonic-gate# 106d90 6087c478bd9Sstevel@tonic-gate# 108,110d91 6097c478bd9Sstevel@tonic-gate# 610daaffb31Sdp# These editing codes are parsed by the awk script and used to generate 611daaffb31Sdp# another awk script that generates HTML, e.g the above lines would turn 612daaffb31Sdp# into something like this: 6137c478bd9Sstevel@tonic-gate# 6147c478bd9Sstevel@tonic-gate# BEGIN { printf "<pre>\n" } 6157c478bd9Sstevel@tonic-gate# function sp(n) {for (i=0;i<n;i++)printf "\n"} 616daaffb31Sdp# function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0} 6177c478bd9Sstevel@tonic-gate# NR==8 {wl("#7A7ADD");next} 6187c478bd9Sstevel@tonic-gate# NR==54 {wl("#7A7ADD");sp(3);next} 6197c478bd9Sstevel@tonic-gate# NR==56 {wl("#7A7ADD");next} 6207c478bd9Sstevel@tonic-gate# NR==57 {wl("black");printf "\n"; next} 6217c478bd9Sstevel@tonic-gate# : : 6227c478bd9Sstevel@tonic-gate# 623daaffb31Sdp# This script is then run on the original source file to generate the 624daaffb31Sdp# HTML that corresponds to the source file. 6257c478bd9Sstevel@tonic-gate# 626daaffb31Sdp# The two HTML files are then combined into a single piece of HTML that 627daaffb31Sdp# uses an HTML table construct to present the files side by side. You'll 628daaffb31Sdp# notice that the changes are color-coded: 6297c478bd9Sstevel@tonic-gate# 6307c478bd9Sstevel@tonic-gate# black - unchanged lines 6317c478bd9Sstevel@tonic-gate# blue - changed lines 6327c478bd9Sstevel@tonic-gate# bold blue - new lines 6337c478bd9Sstevel@tonic-gate# brown - deleted lines 6347c478bd9Sstevel@tonic-gate# 635daaffb31Sdp# Blank lines are inserted in each file to keep unchanged lines in sync 636daaffb31Sdp# (side-by-side). This format is familiar to users of sdiff(1) or 637daaffb31Sdp# Teamware's filemerge tool. 638daaffb31Sdp# 639daaffb31Sdpsdiff_to_html() 640daaffb31Sdp{ 6417c478bd9Sstevel@tonic-gate diff -b $1 $2 > /tmp/$$.diffs 6427c478bd9Sstevel@tonic-gate 643daaffb31Sdp TNAME=$3 644daaffb31Sdp TPATH=$4 645daaffb31Sdp COMMENT=$5 646daaffb31Sdp 6477c478bd9Sstevel@tonic-gate # 6487c478bd9Sstevel@tonic-gate # Now we have the diffs, generate the HTML for the old file. 6497c478bd9Sstevel@tonic-gate # 650cdf0c1d5Smjnelson $AWK ' 6517c478bd9Sstevel@tonic-gate BEGIN { 6527c478bd9Sstevel@tonic-gate printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n" 653daaffb31Sdp printf "function removed() " 654daaffb31Sdp printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 655daaffb31Sdp printf "function changed() " 656daaffb31Sdp printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 657daaffb31Sdp printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n" 6587c478bd9Sstevel@tonic-gate} 6597c478bd9Sstevel@tonic-gate /^</ {next} 6607c478bd9Sstevel@tonic-gate /^>/ {next} 6617c478bd9Sstevel@tonic-gate /^---/ {next} 662daaffb31Sdp 6637c478bd9Sstevel@tonic-gate { 6647c478bd9Sstevel@tonic-gate split($1, a, /[cad]/) ; 6657c478bd9Sstevel@tonic-gate if (index($1, "a")) { 6667c478bd9Sstevel@tonic-gate if (a[1] == 0) { 6677c478bd9Sstevel@tonic-gate n = split(a[2], r, /,/); 6687c478bd9Sstevel@tonic-gate if (n == 1) 6697c478bd9Sstevel@tonic-gate printf "BEGIN\t\t{sp(1)}\n" 6707c478bd9Sstevel@tonic-gate else 6717c478bd9Sstevel@tonic-gate printf "BEGIN\t\t{sp(%d)}\n",\ 6727c478bd9Sstevel@tonic-gate (r[2] - r[1]) + 1 6737c478bd9Sstevel@tonic-gate next 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate printf "NR==%s\t\t{", a[1] 6777c478bd9Sstevel@tonic-gate n = split(a[2], r, /,/); 6787c478bd9Sstevel@tonic-gate s = r[1]; 6797c478bd9Sstevel@tonic-gate if (n == 1) 6807c478bd9Sstevel@tonic-gate printf "bl();printf \"\\n\"; next}\n" 6817c478bd9Sstevel@tonic-gate else { 6827c478bd9Sstevel@tonic-gate n = r[2] - r[1] 6837c478bd9Sstevel@tonic-gate printf "bl();sp(%d);next}\n",\ 6847c478bd9Sstevel@tonic-gate (r[2] - r[1]) + 1 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate next 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate if (index($1, "d")) { 6897c478bd9Sstevel@tonic-gate n = split(a[1], r, /,/); 6907c478bd9Sstevel@tonic-gate n1 = r[1] 6917c478bd9Sstevel@tonic-gate n2 = r[2] 6927c478bd9Sstevel@tonic-gate if (n == 1) 693daaffb31Sdp printf "NR==%s\t\t{removed(); next}\n" , n1 6947c478bd9Sstevel@tonic-gate else 695daaffb31Sdp printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2 6967c478bd9Sstevel@tonic-gate next 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate if (index($1, "c")) { 6997c478bd9Sstevel@tonic-gate n = split(a[1], r, /,/); 7007c478bd9Sstevel@tonic-gate n1 = r[1] 7017c478bd9Sstevel@tonic-gate n2 = r[2] 7027c478bd9Sstevel@tonic-gate final = n2 7037c478bd9Sstevel@tonic-gate d1 = 0 7047c478bd9Sstevel@tonic-gate if (n == 1) 705daaffb31Sdp printf "NR==%s\t\t{changed();" , n1 7067c478bd9Sstevel@tonic-gate else { 7077c478bd9Sstevel@tonic-gate d1 = n2 - n1 708daaffb31Sdp printf "NR==%s,NR==%s\t{changed();" , n1, n2 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate m = split(a[2], r, /,/); 7117c478bd9Sstevel@tonic-gate n1 = r[1] 7127c478bd9Sstevel@tonic-gate n2 = r[2] 7137c478bd9Sstevel@tonic-gate if (m > 1) { 7147c478bd9Sstevel@tonic-gate d2 = n2 - n1 7157c478bd9Sstevel@tonic-gate if (d2 > d1) { 7167c478bd9Sstevel@tonic-gate if (n > 1) printf "if (NR==%d)", final 7177c478bd9Sstevel@tonic-gate printf "sp(%d);", d2 - d1 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate printf "next}\n" ; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate next 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 726daaffb31Sdp END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" } 727daaffb31Sdp ' /tmp/$$.diffs > /tmp/$$.file1 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate # 7307c478bd9Sstevel@tonic-gate # Now generate the HTML for the new file 7317c478bd9Sstevel@tonic-gate # 732cdf0c1d5Smjnelson $AWK ' 7337c478bd9Sstevel@tonic-gate BEGIN { 7347c478bd9Sstevel@tonic-gate printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n" 735daaffb31Sdp printf "function new() " 736daaffb31Sdp printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n" 737daaffb31Sdp printf "function changed() " 738daaffb31Sdp printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n" 739daaffb31Sdp printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n" 7407c478bd9Sstevel@tonic-gate } 741daaffb31Sdp 7427c478bd9Sstevel@tonic-gate /^</ {next} 7437c478bd9Sstevel@tonic-gate /^>/ {next} 7447c478bd9Sstevel@tonic-gate /^---/ {next} 745daaffb31Sdp 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate split($1, a, /[cad]/) ; 7487c478bd9Sstevel@tonic-gate if (index($1, "d")) { 7497c478bd9Sstevel@tonic-gate if (a[2] == 0) { 7507c478bd9Sstevel@tonic-gate n = split(a[1], r, /,/); 7517c478bd9Sstevel@tonic-gate if (n == 1) 7527c478bd9Sstevel@tonic-gate printf "BEGIN\t\t{sp(1)}\n" 7537c478bd9Sstevel@tonic-gate else 7547c478bd9Sstevel@tonic-gate printf "BEGIN\t\t{sp(%d)}\n",\ 7557c478bd9Sstevel@tonic-gate (r[2] - r[1]) + 1 7567c478bd9Sstevel@tonic-gate next 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate printf "NR==%s\t\t{", a[2] 7607c478bd9Sstevel@tonic-gate n = split(a[1], r, /,/); 7617c478bd9Sstevel@tonic-gate s = r[1]; 7627c478bd9Sstevel@tonic-gate if (n == 1) 7637c478bd9Sstevel@tonic-gate printf "bl();printf \"\\n\"; next}\n" 7647c478bd9Sstevel@tonic-gate else { 7657c478bd9Sstevel@tonic-gate n = r[2] - r[1] 7667c478bd9Sstevel@tonic-gate printf "bl();sp(%d);next}\n",\ 7677c478bd9Sstevel@tonic-gate (r[2] - r[1]) + 1 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate next 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate if (index($1, "a")) { 7727c478bd9Sstevel@tonic-gate n = split(a[2], r, /,/); 7737c478bd9Sstevel@tonic-gate n1 = r[1] 7747c478bd9Sstevel@tonic-gate n2 = r[2] 7757c478bd9Sstevel@tonic-gate if (n == 1) 776daaffb31Sdp printf "NR==%s\t\t{new() ; next}\n" , n1 7777c478bd9Sstevel@tonic-gate else 778daaffb31Sdp printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2 7797c478bd9Sstevel@tonic-gate next 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate if (index($1, "c")) { 7827c478bd9Sstevel@tonic-gate n = split(a[2], r, /,/); 7837c478bd9Sstevel@tonic-gate n1 = r[1] 7847c478bd9Sstevel@tonic-gate n2 = r[2] 7857c478bd9Sstevel@tonic-gate final = n2 7867c478bd9Sstevel@tonic-gate d2 = 0; 7877c478bd9Sstevel@tonic-gate if (n == 1) { 7887c478bd9Sstevel@tonic-gate final = n1 789daaffb31Sdp printf "NR==%s\t\t{changed();" , n1 7907c478bd9Sstevel@tonic-gate } else { 7917c478bd9Sstevel@tonic-gate d2 = n2 - n1 792daaffb31Sdp printf "NR==%s,NR==%s\t{changed();" , n1, n2 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate m = split(a[1], r, /,/); 7957c478bd9Sstevel@tonic-gate n1 = r[1] 7967c478bd9Sstevel@tonic-gate n2 = r[2] 7977c478bd9Sstevel@tonic-gate if (m > 1) { 7987c478bd9Sstevel@tonic-gate d1 = n2 - n1 7997c478bd9Sstevel@tonic-gate if (d1 > d2) { 8007c478bd9Sstevel@tonic-gate if (n > 1) printf "if (NR==%d)", final 8017c478bd9Sstevel@tonic-gate printf "sp(%d);", d1 - d2 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate printf "next}\n" ; 8057c478bd9Sstevel@tonic-gate next 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate } 808daaffb31Sdp END { printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" } 8097c478bd9Sstevel@tonic-gate ' /tmp/$$.diffs > /tmp/$$.file2 8107c478bd9Sstevel@tonic-gate 811daaffb31Sdp # 812cdf0c1d5Smjnelson # Post-process the HTML files by running them back through $AWK 813daaffb31Sdp # 814cdf0c1d5Smjnelson html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html 8157c478bd9Sstevel@tonic-gate 816cdf0c1d5Smjnelson html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html 8177c478bd9Sstevel@tonic-gate 818daaffb31Sdp # 819daaffb31Sdp # Now combine into a valid HTML file and side-by-side into a table 820daaffb31Sdp # 821daaffb31Sdp print "$HTML<head>$STDHEAD" 822cdf0c1d5Smjnelson print "<title>$WNAME Sdiff $TPATH/$TNAME</title>" 823daaffb31Sdp print "</head><body id=\"SUNWwebrev\">" 824daaffb31Sdp print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>" 825daaffb31Sdp print "<pre>$COMMENT</pre>\n" 826daaffb31Sdp print "<table><tr valign=\"top\">" 827daaffb31Sdp print "<td><pre>" 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate strip_unchanged /tmp/$$.file1.html 8307c478bd9Sstevel@tonic-gate 831daaffb31Sdp print "</pre></td><td><pre>" 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate strip_unchanged /tmp/$$.file2.html 8347c478bd9Sstevel@tonic-gate 835daaffb31Sdp print "</pre></td>" 836daaffb31Sdp print "</tr></table>" 837daaffb31Sdp print "</body></html>" 8387c478bd9Sstevel@tonic-gate 839daaffb31Sdp framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \ 840daaffb31Sdp "$COMMENT" 8417c478bd9Sstevel@tonic-gate} 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate 844daaffb31Sdp# 845daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment> 846daaffb31Sdp# 847daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html. 848daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors, 849daaffb31Sdp# and then emit the main frame. Content is placed into: 850daaffb31Sdp# 851daaffb31Sdp# $WDIR/DIR/$TNAME.lhs.html 852daaffb31Sdp# $WDIR/DIR/$TNAME.rhs.html 853daaffb31Sdp# $WDIR/DIR/$TNAME.frames.html 854daaffb31Sdp# 855daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR. 856daaffb31Sdp# 8577c478bd9Sstevel@tonic-gatefunction framed_sdiff 8587c478bd9Sstevel@tonic-gate{ 8597c478bd9Sstevel@tonic-gate typeset TNAME=$1 860daaffb31Sdp typeset TPATH=$2 861daaffb31Sdp typeset lhsfile=$3 862daaffb31Sdp typeset rhsfile=$4 863daaffb31Sdp typeset comments=$5 8647c478bd9Sstevel@tonic-gate typeset RTOP 865daaffb31Sdp 8667c478bd9Sstevel@tonic-gate # Enable html files to access WDIR via a relative path. 867daaffb31Sdp RTOP=$(relative_dir $TPATH $WDIR) 868daaffb31Sdp 869daaffb31Sdp # Make the rhs/lhs files and output the frameset file. 870daaffb31Sdp print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html 871daaffb31Sdp 872daaffb31Sdp cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF 8738b3b7b16SMark J. Nelson <script type="text/javascript" src="${RTOP}ancnav.js"></script> 8747c478bd9Sstevel@tonic-gate </head> 875daaffb31Sdp <body id="SUNWwebrev" onkeypress="keypress(event);"> 876cac38512Smjnelson <a name="0"></a> 877cac38512Smjnelson <pre>$comments</pre><hr></hr> 878daaffb31Sdp EOF 879daaffb31Sdp 880daaffb31Sdp cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html 881daaffb31Sdp 882daaffb31Sdp insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html 883daaffb31Sdp insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html 884daaffb31Sdp 885daaffb31Sdp close='</body></html>' 886daaffb31Sdp 887daaffb31Sdp print $close >> $WDIR/$DIR/$TNAME.lhs.html 888daaffb31Sdp print $close >> $WDIR/$DIR/$TNAME.rhs.html 889daaffb31Sdp 890daaffb31Sdp print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html 891daaffb31Sdp print "<title>$WNAME Framed-Sdiff " \ 892daaffb31Sdp "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html 893daaffb31Sdp cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF 894daaffb31Sdp <frameset rows="*,60"> 895daaffb31Sdp <frameset cols="50%,50%"> 896cac38512Smjnelson <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame> 897cac38512Smjnelson <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame> 898daaffb31Sdp </frameset> 8998b3b7b16SMark J. Nelson <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0" 900cac38512Smjnelson marginheight="0" name="nav"></frame> 901daaffb31Sdp <noframes> 902daaffb31Sdp <body id="SUNWwebrev"> 903daaffb31Sdp Alas 'frames' webrev requires that your browser supports frames 9047c478bd9Sstevel@tonic-gate and has the feature enabled. 905daaffb31Sdp </body> 906daaffb31Sdp </noframes> 907daaffb31Sdp </frameset> 9087c478bd9Sstevel@tonic-gate </html> 9097c478bd9Sstevel@tonic-gate EOF 9107c478bd9Sstevel@tonic-gate} 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate 913daaffb31Sdp# 914daaffb31Sdp# fix_postscript 915daaffb31Sdp# 916daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by: 917daaffb31Sdp# - removing all extraneous headers/trailers 918daaffb31Sdp# - making the page numbers right 919daaffb31Sdp# - removing pages devoid of contents which confuse some 920daaffb31Sdp# postscript readers. 921daaffb31Sdp# 922daaffb31Sdp# From Casper. 923daaffb31Sdp# 924daaffb31Sdpfunction fix_postscript 9257c478bd9Sstevel@tonic-gate{ 926daaffb31Sdp infile=$1 9277c478bd9Sstevel@tonic-gate 928daaffb31Sdp cat > /tmp/$$.crmerge.pl << \EOF 9297c478bd9Sstevel@tonic-gate 930daaffb31Sdp print scalar(<>); # %!PS-Adobe--- 931daaffb31Sdp print "%%Orientation: Landscape\n"; 9327c478bd9Sstevel@tonic-gate 933daaffb31Sdp $pno = 0; 934daaffb31Sdp $doprint = 1; 935daaffb31Sdp 936daaffb31Sdp $page = ""; 937daaffb31Sdp 938daaffb31Sdp while (<>) { 939daaffb31Sdp next if (/^%%Pages:\s*\d+/); 940daaffb31Sdp 941daaffb31Sdp if (/^%%Page:/) { 942daaffb31Sdp if ($pno == 0 || $page =~ /\)S/) { 943daaffb31Sdp # Header or single page containing text 944daaffb31Sdp print "%%Page: ? $pno\n" if ($pno > 0); 945daaffb31Sdp print $page; 946daaffb31Sdp $pno++; 947daaffb31Sdp } else { 948daaffb31Sdp # Empty page, skip it. 9497c478bd9Sstevel@tonic-gate } 950daaffb31Sdp $page = ""; 951daaffb31Sdp $doprint = 1; 9527c478bd9Sstevel@tonic-gate next; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 955daaffb31Sdp # Skip from %%Trailer of one document to Endprolog 956daaffb31Sdp # %%Page of the next 957daaffb31Sdp $doprint = 0 if (/^%%Trailer/); 958daaffb31Sdp $page .= $_ if ($doprint); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 961daaffb31Sdp if ($page =~ /\)S/) { 962daaffb31Sdp print "%%Page: ? $pno\n"; 963daaffb31Sdp print $page; 964daaffb31Sdp } else { 965daaffb31Sdp $pno--; 966daaffb31Sdp } 967daaffb31Sdp print "%%Trailer\n%%Pages: $pno\n"; 968daaffb31SdpEOF 969daaffb31Sdp 97014983201Sdp $PERL /tmp/$$.crmerge.pl < $infile 971daaffb31Sdp} 972daaffb31Sdp 973daaffb31Sdp 974daaffb31Sdp# 975daaffb31Sdp# input_cmd | insert_anchors | output_cmd 976daaffb31Sdp# 9777c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible 978daaffb31Sdp# anchors. These are used to drive the frames version of the 9797c478bd9Sstevel@tonic-gate# sdiffs output. 9807c478bd9Sstevel@tonic-gate# 9817c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes, 9827c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom. 9837c478bd9Sstevel@tonic-gate# 984daaffb31Sdp# The script detects changed lines as any line that has a "<span 985daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are 986daaffb31Sdp# not part of a <span>. Blank lines (without a sequence number) 9877c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or 9887c478bd9Sstevel@tonic-gate# deleted. 9897c478bd9Sstevel@tonic-gate# 990daaffb31Sdpfunction insert_anchors 991daaffb31Sdp{ 992cdf0c1d5Smjnelson $AWK ' 9937c478bd9Sstevel@tonic-gate function ia() { 994daaffb31Sdp printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++; 9957c478bd9Sstevel@tonic-gate } 996daaffb31Sdp 9977c478bd9Sstevel@tonic-gate BEGIN { 998daaffb31Sdp anc=1; 9997c478bd9Sstevel@tonic-gate inblock=1; 1000daaffb31Sdp printf "<pre>\n"; 10017c478bd9Sstevel@tonic-gate } 1002daaffb31Sdp NF == 0 || /^<span class=/ { 10037c478bd9Sstevel@tonic-gate if (inblock == 0) { 10047c478bd9Sstevel@tonic-gate ia(); 10057c478bd9Sstevel@tonic-gate inblock=1; 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate print; 10087c478bd9Sstevel@tonic-gate next; 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate { 10117c478bd9Sstevel@tonic-gate inblock=0; 10127c478bd9Sstevel@tonic-gate print; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate END { 10157c478bd9Sstevel@tonic-gate ia(); 1016daaffb31Sdp 1017daaffb31Sdp printf "<b style=\"font-size: large; color: red\">"; 1018daaffb31Sdp printf "--- EOF ---</b>" 10197c478bd9Sstevel@tonic-gate for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n"; 1020daaffb31Sdp printf "</pre>" 1021daaffb31Sdp printf "<form name=\"eof\">"; 1022cac38512Smjnelson printf "<input name=\"value\" value=\"%d\" " \ 1023cac38512Smjnelson "type=\"hidden\"></input>", anc - 1; 1024daaffb31Sdp printf "</form>"; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate ' $1 10277c478bd9Sstevel@tonic-gate} 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate 1030daaffb31Sdp# 1031daaffb31Sdp# relative_dir 1032daaffb31Sdp# 1033daaffb31Sdp# Print a relative return path from $1 to $2. For example if 1034daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview, 1035daaffb31Sdp# this function would print "../../../../". 1036daaffb31Sdp# 1037daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr, 1038daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev 1039daaffb31Sdp# is not relocatable. 1040daaffb31Sdp# 1041daaffb31Sdpfunction relative_dir 10427c478bd9Sstevel@tonic-gate{ 1043daaffb31Sdp typeset cur="${1##$2?(/)}" 10448b3b7b16SMark J. Nelson 10458b3b7b16SMark J. Nelson # 10468b3b7b16SMark J. Nelson # If the first path was specified absolutely, and it does 10478b3b7b16SMark J. Nelson # not start with the second path, it's an error. 10488b3b7b16SMark J. Nelson # 10490fd2682eSMark J. Nelson if [[ "$cur" = "/${1#/}" ]]; then 1050daaffb31Sdp # Should never happen. 105114983201Sdp print -u2 "\nWARNING: relative_dir: \"$1\" not relative " 1052daaffb31Sdp print -u2 "to \"$2\". Check input paths. Framed webrev " 1053daaffb31Sdp print -u2 "will not be relocatable!" 1054daaffb31Sdp print $2 1055daaffb31Sdp return 1056daaffb31Sdp fi 1057daaffb31Sdp 10588b3b7b16SMark J. Nelson # 10598b3b7b16SMark J. Nelson # This is kind of ugly. The sed script will do the following: 10608b3b7b16SMark J. Nelson # 10618b3b7b16SMark J. Nelson # 1. Strip off a leading "." or "./": this is important to get 10628b3b7b16SMark J. Nelson # the correct arcnav links for files in $WDIR. 10638b3b7b16SMark J. Nelson # 2. Strip off a trailing "/": this is not strictly necessary, 10648b3b7b16SMark J. Nelson # but is kind of nice, since it doesn't end up in "//" at 10658b3b7b16SMark J. Nelson # the end of a relative path. 10668b3b7b16SMark J. Nelson # 3. Replace all remaining sequences of non-"/" with "..": the 10678b3b7b16SMark J. Nelson # assumption here is that each dirname represents another 10688b3b7b16SMark J. Nelson # level of relative separation. 10698b3b7b16SMark J. Nelson # 4. Append a trailing "/" only for non-empty paths: this way 10708b3b7b16SMark J. Nelson # the caller doesn't need to duplicate this logic, and does 10718b3b7b16SMark J. Nelson # not end up using $RTOP/file for files in $WDIR. 10728b3b7b16SMark J. Nelson # 10730fd2682eSMark J. Nelson print $cur | $SED -e '{ 10748b3b7b16SMark J. Nelson s:^\./*:: 10758b3b7b16SMark J. Nelson s:/$:: 10768b3b7b16SMark J. Nelson s:[^/][^/]*:..:g 10770fd2682eSMark J. Nelson s:^\(..*\)$:\1/: 10780fd2682eSMark J. Nelson }' 10797c478bd9Sstevel@tonic-gate} 10807c478bd9Sstevel@tonic-gate 1081daaffb31Sdp# 1082daaffb31Sdp# frame_nav_js 1083daaffb31Sdp# 1084daaffb31Sdp# Emit javascript for frame navigation 1085daaffb31Sdp# 1086daaffb31Sdpfunction frame_nav_js 10877c478bd9Sstevel@tonic-gate{ 10887c478bd9Sstevel@tonic-gatecat << \EOF 10897c478bd9Sstevel@tonic-gatevar myInt; 10907c478bd9Sstevel@tonic-gatevar scrolling=0; 1091daaffb31Sdpvar sfactor = 3; 10927c478bd9Sstevel@tonic-gatevar scount=10; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gatefunction scrollByPix() { 10957c478bd9Sstevel@tonic-gate if (scount<=0) { 10967c478bd9Sstevel@tonic-gate sfactor*=1.2; 10977c478bd9Sstevel@tonic-gate scount=10; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate parent.lhs.scrollBy(0,sfactor); 11007c478bd9Sstevel@tonic-gate parent.rhs.scrollBy(0,sfactor); 11017c478bd9Sstevel@tonic-gate scount--; 11027c478bd9Sstevel@tonic-gate} 11037c478bd9Sstevel@tonic-gate 1104daaffb31Sdpfunction scrollToAnc(num) { 1105daaffb31Sdp 1106daaffb31Sdp // Update the value of the anchor in the form which we use as 1107daaffb31Sdp // storage for this value. setAncValue() will take care of 1108daaffb31Sdp // correcting for overflow and underflow of the value and return 1109daaffb31Sdp // us the new value. 1110daaffb31Sdp num = setAncValue(num); 1111daaffb31Sdp 1112daaffb31Sdp // Set location and scroll back a little to expose previous 1113daaffb31Sdp // lines. 1114daaffb31Sdp // 1115daaffb31Sdp // Note that this could be improved: it is possible although 1116daaffb31Sdp // complex to compute the x and y position of an anchor, and to 1117daaffb31Sdp // scroll to that location directly. 1118daaffb31Sdp // 11197c478bd9Sstevel@tonic-gate parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num); 11207c478bd9Sstevel@tonic-gate parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num); 1121daaffb31Sdp 11227c478bd9Sstevel@tonic-gate parent.lhs.scrollBy(0,-30); 11237c478bd9Sstevel@tonic-gate parent.rhs.scrollBy(0,-30); 11247c478bd9Sstevel@tonic-gate} 11257c478bd9Sstevel@tonic-gate 1126daaffb31Sdpfunction getAncValue() 1127daaffb31Sdp{ 1128daaffb31Sdp return (parseInt(parent.nav.document.diff.real.value)); 1129daaffb31Sdp} 1130daaffb31Sdp 1131daaffb31Sdpfunction setAncValue(val) 1132daaffb31Sdp{ 1133daaffb31Sdp if (val <= 0) { 1134daaffb31Sdp val = 0; 1135daaffb31Sdp parent.nav.document.diff.real.value = val; 1136daaffb31Sdp parent.nav.document.diff.display.value = "BOF"; 1137daaffb31Sdp return (val); 1138daaffb31Sdp } 1139daaffb31Sdp 1140daaffb31Sdp // 1141daaffb31Sdp // The way we compute the max anchor value is to stash it 1142daaffb31Sdp // inline in the left and right hand side pages-- it's the same 1143daaffb31Sdp // on each side, so we pluck from the left. 1144daaffb31Sdp // 1145daaffb31Sdp maxval = parent.lhs.document.eof.value.value; 1146daaffb31Sdp if (val < maxval) { 1147daaffb31Sdp parent.nav.document.diff.real.value = val; 1148daaffb31Sdp parent.nav.document.diff.display.value = val.toString(); 1149daaffb31Sdp return (val); 1150daaffb31Sdp } 1151daaffb31Sdp 1152daaffb31Sdp // this must be: val >= maxval 1153daaffb31Sdp val = maxval; 1154daaffb31Sdp parent.nav.document.diff.real.value = val; 1155daaffb31Sdp parent.nav.document.diff.display.value = "EOF"; 1156daaffb31Sdp return (val); 1157daaffb31Sdp} 1158daaffb31Sdp 11597c478bd9Sstevel@tonic-gatefunction stopScroll() { 11607c478bd9Sstevel@tonic-gate if (scrolling==1) { 11617c478bd9Sstevel@tonic-gate clearInterval(myInt); 11627c478bd9Sstevel@tonic-gate scrolling=0; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate} 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gatefunction startScroll() { 11677c478bd9Sstevel@tonic-gate stopScroll(); 11687c478bd9Sstevel@tonic-gate scrolling=1; 11697c478bd9Sstevel@tonic-gate myInt=setInterval("scrollByPix()",10); 11707c478bd9Sstevel@tonic-gate} 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gatefunction handlePress(b) { 1173daaffb31Sdp 11747c478bd9Sstevel@tonic-gate switch (b) { 11757c478bd9Sstevel@tonic-gate case 1 : 1176daaffb31Sdp scrollToAnc(-1); 11777c478bd9Sstevel@tonic-gate break; 11787c478bd9Sstevel@tonic-gate case 2 : 1179daaffb31Sdp scrollToAnc(getAncValue() - 1); 11807c478bd9Sstevel@tonic-gate break; 11817c478bd9Sstevel@tonic-gate case 3 : 11827c478bd9Sstevel@tonic-gate sfactor=-3; 11837c478bd9Sstevel@tonic-gate startScroll(); 11847c478bd9Sstevel@tonic-gate break; 11857c478bd9Sstevel@tonic-gate case 4 : 11867c478bd9Sstevel@tonic-gate sfactor=3; 11877c478bd9Sstevel@tonic-gate startScroll(); 11887c478bd9Sstevel@tonic-gate break; 11897c478bd9Sstevel@tonic-gate case 5 : 1190daaffb31Sdp scrollToAnc(getAncValue() + 1); 11917c478bd9Sstevel@tonic-gate break; 11927c478bd9Sstevel@tonic-gate case 6 : 1193daaffb31Sdp scrollToAnc(999999); 11947c478bd9Sstevel@tonic-gate break; 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate} 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gatefunction handleRelease(b) { 11997c478bd9Sstevel@tonic-gate stopScroll(); 12007c478bd9Sstevel@tonic-gate} 12017c478bd9Sstevel@tonic-gate 1202daaffb31Sdpfunction keypress(ev) { 1203daaffb31Sdp var keynum; 1204daaffb31Sdp var keychar; 1205daaffb31Sdp 1206daaffb31Sdp if (window.event) { // IE 1207daaffb31Sdp keynum = ev.keyCode; 1208daaffb31Sdp } else if (ev.which) { // non-IE 1209daaffb31Sdp keynum = ev.which; 1210daaffb31Sdp } 1211daaffb31Sdp 1212daaffb31Sdp keychar = String.fromCharCode(keynum); 1213daaffb31Sdp 1214daaffb31Sdp if (keychar == "k") { 1215daaffb31Sdp handlePress(2); 1216daaffb31Sdp return (0); 1217daaffb31Sdp } else if (keychar == "j" || keychar == " ") { 1218daaffb31Sdp handlePress(5); 1219daaffb31Sdp return (0); 1220daaffb31Sdp } 1221daaffb31Sdp return (1); 1222daaffb31Sdp} 1223daaffb31Sdp 12247c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){ 1225daaffb31Sdp val = parent.nav.document.diff.display.value; 1226daaffb31Sdp if (val == "EOF") { 1227daaffb31Sdp scrollToAnc(999999); 1228daaffb31Sdp return; 1229daaffb31Sdp } 1230daaffb31Sdp 1231daaffb31Sdp if (val == "BOF") { 1232daaffb31Sdp scrollToAnc(0); 1233daaffb31Sdp return; 1234daaffb31Sdp } 1235daaffb31Sdp 1236daaffb31Sdp i=parseInt(val); 12377c478bd9Sstevel@tonic-gate if (isNaN(i)) { 1238daaffb31Sdp parent.nav.document.diff.display.value = getAncValue(); 12397c478bd9Sstevel@tonic-gate } else { 1240daaffb31Sdp scrollToAnc(i); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate return false; 12437c478bd9Sstevel@tonic-gate} 12447c478bd9Sstevel@tonic-gate 1245daaffb31SdpEOF 1246daaffb31Sdp} 1247daaffb31Sdp 1248daaffb31Sdp# 1249daaffb31Sdp# frame_navigation 1250daaffb31Sdp# 1251daaffb31Sdp# Output anchor navigation file for framed sdiffs. 1252daaffb31Sdp# 1253daaffb31Sdpfunction frame_navigation 1254daaffb31Sdp{ 1255daaffb31Sdp print "$HTML<head>$STDHEAD" 1256daaffb31Sdp 1257daaffb31Sdp cat << \EOF 1258daaffb31Sdp<title>Anchor Navigation</title> 1259daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript"> 1260daaffb31Sdp<meta http-equiv="Content-Type" content="text/html"> 1261daaffb31Sdp 1262daaffb31Sdp<style type="text/css"> 1263daaffb31Sdp div.button td { padding-left: 5px; padding-right: 5px; 1264daaffb31Sdp background-color: #eee; text-align: center; 1265daaffb31Sdp border: 1px #444 outset; cursor: pointer; } 1266daaffb31Sdp div.button a { font-weight: bold; color: black } 1267daaffb31Sdp div.button td:hover { background: #ffcc99; } 1268daaffb31Sdp</style> 1269daaffb31SdpEOF 1270daaffb31Sdp 1271cac38512Smjnelson print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>" 1272daaffb31Sdp 1273daaffb31Sdp cat << \EOF 12747c478bd9Sstevel@tonic-gate</head> 1275daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();" 1276daaffb31Sdp onkeypress="keypress(event);"> 12777c478bd9Sstevel@tonic-gate <noscript lang="javascript"> 12787c478bd9Sstevel@tonic-gate <center> 1279cac38512Smjnelson <p><big>Framed Navigation controls require Javascript</big><br></br> 12807c478bd9Sstevel@tonic-gate Either this browser is incompatable or javascript is not enabled</p> 12817c478bd9Sstevel@tonic-gate </center> 12827c478bd9Sstevel@tonic-gate </noscript> 12837c478bd9Sstevel@tonic-gate <table width="100%" border="0" align="center"> 1284daaffb31Sdp <tr> 1285daaffb31Sdp <td valign="middle" width="25%">Diff navigation: 1286daaffb31Sdp Use 'j' and 'k' for next and previous diffs; or use buttons 1287daaffb31Sdp at right</td> 1288daaffb31Sdp <td align="center" valign="top" width="50%"> 12897c478bd9Sstevel@tonic-gate <div class="button"> 1290daaffb31Sdp <table border="0" align="center"> 1291daaffb31Sdp <tr> 1292daaffb31Sdp <td> 12937c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(1);return true;" 12947c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(1);return true;" 12957c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(1);return true;" 12967c478bd9Sstevel@tonic-gate onClick="return false;" 12977c478bd9Sstevel@tonic-gate title="Go to Beginning Of file">BOF</a></td> 1298daaffb31Sdp <td> 12997c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(3);return true;" 13007c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(3);return true;" 13017c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(3);return true;" 13027c478bd9Sstevel@tonic-gate title="Scroll Up: Press and Hold to accelerate" 1303daaffb31Sdp onClick="return false;">Scroll Up</a></td> 1304daaffb31Sdp <td> 13057c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(2);return true;" 13067c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(2);return true;" 13077c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(2);return true;" 13087c478bd9Sstevel@tonic-gate title="Go to previous Diff" 13097c478bd9Sstevel@tonic-gate onClick="return false;">Prev Diff</a> 13107c478bd9Sstevel@tonic-gate </td></tr> 1311daaffb31Sdp 13127c478bd9Sstevel@tonic-gate <tr> 1313daaffb31Sdp <td> 13147c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(6);return true;" 13157c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(6);return true;" 13167c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(6);return true;" 13177c478bd9Sstevel@tonic-gate onClick="return false;" 13187c478bd9Sstevel@tonic-gate title="Go to End Of File">EOF</a></td> 1319daaffb31Sdp <td> 13207c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(4);return true;" 13217c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(4);return true;" 13227c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(4);return true;" 13237c478bd9Sstevel@tonic-gate title="Scroll Down: Press and Hold to accelerate" 1324daaffb31Sdp onClick="return false;">Scroll Down</a></td> 1325daaffb31Sdp <td> 13267c478bd9Sstevel@tonic-gate <a onMouseDown="handlePress(5);return true;" 13277c478bd9Sstevel@tonic-gate onMouseUp="handleRelease(5);return true;" 13287c478bd9Sstevel@tonic-gate onMouseOut="handleRelease(5);return true;" 13297c478bd9Sstevel@tonic-gate title="Go to next Diff" 13307c478bd9Sstevel@tonic-gate onClick="return false;">Next Diff</a></td> 1331daaffb31Sdp </tr> 1332daaffb31Sdp </table> 1333daaffb31Sdp </div> 1334daaffb31Sdp </td> 13357c478bd9Sstevel@tonic-gate <th valign="middle" width="25%"> 1336daaffb31Sdp <form action="" name="diff" onsubmit="return ValidateDiffNum();"> 1337cac38512Smjnelson <input name="display" value="BOF" size="8" type="text"></input> 1338cac38512Smjnelson <input name="real" value="0" size="8" type="hidden"></input> 13397c478bd9Sstevel@tonic-gate </form> 13407c478bd9Sstevel@tonic-gate </th> 1341daaffb31Sdp </tr> 13427c478bd9Sstevel@tonic-gate </table> 13437c478bd9Sstevel@tonic-gate </body> 13447c478bd9Sstevel@tonic-gate</html> 13457c478bd9Sstevel@tonic-gateEOF 13467c478bd9Sstevel@tonic-gate} 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate 1349daaffb31Sdp 1350daaffb31Sdp# 1351daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment> 1352daaffb31Sdp# 1353daaffb31Sdp# Processes the output of diff to produce an HTML file representing either 1354daaffb31Sdp# context or unified diffs. 1355daaffb31Sdp# 13567c478bd9Sstevel@tonic-gatediff_to_html() 13577c478bd9Sstevel@tonic-gate{ 13587c478bd9Sstevel@tonic-gate TNAME=$1 1359daaffb31Sdp TPATH=$2 1360daaffb31Sdp DIFFTYPE=$3 1361daaffb31Sdp COMMENT=$4 1362daaffb31Sdp 1363daaffb31Sdp print "$HTML<head>$STDHEAD" 1364daaffb31Sdp print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>" 1365daaffb31Sdp 1366daaffb31Sdp if [[ $DIFFTYPE == "U" ]]; then 1367daaffb31Sdp print "$UDIFFCSS" 1368daaffb31Sdp fi 1369daaffb31Sdp 1370daaffb31Sdp cat <<-EOF 1371daaffb31Sdp </head> 1372daaffb31Sdp <body id="SUNWwebrev"> 1373daaffb31Sdp <a class="print" href="javascript:print()">Print this page</a> 1374daaffb31Sdp <pre>$COMMENT</pre> 1375daaffb31Sdp <pre> 1376daaffb31Sdp EOF 13777c478bd9Sstevel@tonic-gate 1378cdf0c1d5Smjnelson html_quote | $AWK ' 1379daaffb31Sdp /^--- new/ { next } 1380daaffb31Sdp /^\+\+\+ new/ { next } 1381daaffb31Sdp /^--- old/ { next } 1382daaffb31Sdp /^\*\*\* old/ { next } 1383daaffb31Sdp /^\*\*\*\*/ { next } 13847c478bd9Sstevel@tonic-gate /^-------/ { printf "<center><h1>%s</h1></center>\n", $0; next } 1385cac38512Smjnelson /^\@\@.*\@\@$/ { printf "</pre><hr></hr><pre>\n"; 1386daaffb31Sdp printf "<span class=\"newmarker\">%s</span>\n", $0; 1387daaffb31Sdp next} 1388daaffb31Sdp 1389cac38512Smjnelson /^\*\*\*/ { printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0; 1390daaffb31Sdp next} 1391daaffb31Sdp /^---/ { printf "<span class=\"newmarker\">%s</span>\n", $0; 1392daaffb31Sdp next} 1393daaffb31Sdp /^\+/ {printf "<span class=\"new\">%s</span>\n", $0; next} 1394daaffb31Sdp /^!/ {printf "<span class=\"changed\">%s</span>\n", $0; next} 1395daaffb31Sdp /^-/ {printf "<span class=\"removed\">%s</span>\n", $0; next} 1396daaffb31Sdp {printf "%s\n", $0; next} 13977c478bd9Sstevel@tonic-gate ' 1398daaffb31Sdp 1399daaffb31Sdp print "</pre></body></html>\n" 14007c478bd9Sstevel@tonic-gate} 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate 1403daaffb31Sdp# 1404daaffb31Sdp# source_to_html { new | old } <filename> 1405daaffb31Sdp# 1406daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file. 1407daaffb31Sdp# 14087c478bd9Sstevel@tonic-gatesource_to_html() 14097c478bd9Sstevel@tonic-gate{ 14107c478bd9Sstevel@tonic-gate WHICH=$1 14117c478bd9Sstevel@tonic-gate TNAME=$2 14127c478bd9Sstevel@tonic-gate 1413daaffb31Sdp print "$HTML<head>$STDHEAD" 1414cdf0c1d5Smjnelson print "<title>$WNAME $WHICH $TNAME</title>" 1415daaffb31Sdp print "<body id=\"SUNWwebrev\">" 1416daaffb31Sdp print "<pre>" 1417cdf0c1d5Smjnelson html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }' 1418daaffb31Sdp print "</pre></body></html>" 14197c478bd9Sstevel@tonic-gate} 14207c478bd9Sstevel@tonic-gate 1421daaffb31Sdp# 1422cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file 1423daaffb31Sdp# 1424daaffb31Sdp# Find the first delta in the child that's not in the parent. Get the 1425daaffb31Sdp# newest delta from the parent, get all deltas from the child starting 1426daaffb31Sdp# with that delta, and then get all info starting with the second oldest 1427daaffb31Sdp# delta in that list (the first delta unique to the child). 14287c478bd9Sstevel@tonic-gate# 14297c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script 1430daaffb31Sdp# 1431daaffb31Sdpcomments_from_teamware() 14327c478bd9Sstevel@tonic-gate{ 1433daaffb31Sdp fmt=$1 1434daaffb31Sdp pfile=$PWS/$2 1435daaffb31Sdp cfile=$CWS/$3 14367c478bd9Sstevel@tonic-gate 1437cdf0c1d5Smjnelson if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then 1438cdf0c1d5Smjnelson pfile=$RWS/$2 1439cdf0c1d5Smjnelson fi 1440cdf0c1d5Smjnelson 1441daaffb31Sdp if [[ -f $pfile ]]; then 1442cdf0c1d5Smjnelson psid=$($SCCS prs -d:I: $pfile 2>/dev/null) 14437c478bd9Sstevel@tonic-gate else 14447c478bd9Sstevel@tonic-gate psid=1.1 14457c478bd9Sstevel@tonic-gate fi 14467c478bd9Sstevel@tonic-gate 1447cdf0c1d5Smjnelson set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null) 14487c478bd9Sstevel@tonic-gate N=${#sids[@]} 14497c478bd9Sstevel@tonic-gate 1450daaffb31Sdp nawkprg=' 1451daaffb31Sdp /^COMMENTS:/ {p=1; continue} 1452daaffb31Sdp /^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; } 1453daaffb31Sdp NF == 0u { continue } 1454daaffb31Sdp {if (p==0) continue; print $0 }' 1455daaffb31Sdp 14567c478bd9Sstevel@tonic-gate if [[ $N -ge 2 ]]; then 14577c478bd9Sstevel@tonic-gate sid1=${sids[$((N-2))]} # Gets 2nd to last sid 14587c478bd9Sstevel@tonic-gate 1459daaffb31Sdp if [[ $fmt == "text" ]]; then 1460cdf0c1d5Smjnelson $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \ 1461cdf0c1d5Smjnelson $AWK "$nawkprg" 1462daaffb31Sdp return 1463daaffb31Sdp fi 1464daaffb31Sdp 1465cdf0c1d5Smjnelson $SCCS prs -l -r$sid1 $cfile 2>/dev/null | \ 14660fd2682eSMark J. Nelson html_quote | its2url | $AWK "$nawkprg" 14677c478bd9Sstevel@tonic-gate fi 14687c478bd9Sstevel@tonic-gate} 14697c478bd9Sstevel@tonic-gate 1470daaffb31Sdp# 1471cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath 1472daaffb31Sdp# 1473cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active 1474cdf0c1d5Smjnelson# file list and print the following comment. Output is either text or 1475cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits) 1476cdf0c1d5Smjnelson# are turned into URLs. 1477cdf0c1d5Smjnelson# 1478cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active. 1479daaffb31Sdp# 1480daaffb31Sdpcomments_from_wx() 14817c478bd9Sstevel@tonic-gate{ 1482daaffb31Sdp typeset fmt=$1 1483daaffb31Sdp typeset p=$2 14847c478bd9Sstevel@tonic-gate 1485cdf0c1d5Smjnelson comm=`$AWK ' 1486daaffb31Sdp $1 == "'$p'" { 14877c478bd9Sstevel@tonic-gate do getline ; while (NF > 0) 14887c478bd9Sstevel@tonic-gate getline 14897c478bd9Sstevel@tonic-gate while (NF > 0) { print ; getline } 14907c478bd9Sstevel@tonic-gate exit 1491daaffb31Sdp }' < $wxfile` 1492daaffb31Sdp 1493cdf0c1d5Smjnelson if [[ -z $comm ]]; then 1494cdf0c1d5Smjnelson comm="*** NO COMMENTS ***" 1495cdf0c1d5Smjnelson fi 1496cdf0c1d5Smjnelson 1497daaffb31Sdp if [[ $fmt == "text" ]]; then 1498cdf0c1d5Smjnelson print -- "$comm" 1499daaffb31Sdp return 1500daaffb31Sdp fi 1501daaffb31Sdp 15020fd2682eSMark J. Nelson print -- "$comm" | html_quote | its2url 1503cdf0c1d5Smjnelson 15047c478bd9Sstevel@tonic-gate} 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate# 1507daaffb31Sdp# getcomments {text|html} filepath parentpath 1508daaffb31Sdp# 1509daaffb31Sdp# Fetch the comments depending on what SCM mode we're in. 1510daaffb31Sdp# 1511daaffb31Sdpgetcomments() 1512daaffb31Sdp{ 1513daaffb31Sdp typeset fmt=$1 1514daaffb31Sdp typeset p=$2 1515daaffb31Sdp typeset pp=$3 15167c478bd9Sstevel@tonic-gate 15173df69ef3SDarren Moffat if [[ -n $Nflag ]]; then 15183df69ef3SDarren Moffat return 15193df69ef3SDarren Moffat fi 1520cdf0c1d5Smjnelson # 1521cdf0c1d5Smjnelson # Mercurial support uses a file list in wx format, so this 1522cdf0c1d5Smjnelson # will be used there, too 1523cdf0c1d5Smjnelson # 1524daaffb31Sdp if [[ -n $wxfile ]]; then 1525daaffb31Sdp comments_from_wx $fmt $p 1526daaffb31Sdp else 1527daaffb31Sdp if [[ $SCM_MODE == "teamware" ]]; then 1528daaffb31Sdp comments_from_teamware $fmt $pp $p 1529daaffb31Sdp fi 1530daaffb31Sdp fi 1531daaffb31Sdp} 1532daaffb31Sdp 1533daaffb31Sdp# 1534daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged> 1535daaffb31Sdp# 1536daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format. 1537daaffb31Sdp# 1538daaffb31Sdpfunction printCI 1539daaffb31Sdp{ 1540daaffb31Sdp integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5 1541daaffb31Sdp typeset str 1542daaffb31Sdp if (( tot == 1 )); then 1543daaffb31Sdp str="line" 1544daaffb31Sdp else 1545daaffb31Sdp str="lines" 1546daaffb31Sdp fi 1547daaffb31Sdp printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \ 1548daaffb31Sdp $tot $str $ins $del $mod $unc 1549daaffb31Sdp} 1550daaffb31Sdp 1551daaffb31Sdp 1552daaffb31Sdp# 1553daaffb31Sdp# difflines <oldfile> <newfile> 1554daaffb31Sdp# 1555daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines, 1556daaffb31Sdp# and total lines changed, the sum of added + removed + modified. 1557daaffb31Sdp# 15587c478bd9Sstevel@tonic-gatefunction difflines 15597c478bd9Sstevel@tonic-gate{ 1560daaffb31Sdp integer tot mod del ins unc err 15617c478bd9Sstevel@tonic-gate typeset filename 15627c478bd9Sstevel@tonic-gate 1563cdf0c1d5Smjnelson eval $( diff -e $1 $2 | $AWK ' 1564daaffb31Sdp # Change range of lines: N,Nc 15657c478bd9Sstevel@tonic-gate /^[0-9]*,[0-9]*c$/ { 15667c478bd9Sstevel@tonic-gate n=split(substr($1,1,length($1)-1), counts, ","); 15677c478bd9Sstevel@tonic-gate if (n != 2) { 15687c478bd9Sstevel@tonic-gate error=2 15697c478bd9Sstevel@tonic-gate exit; 15707c478bd9Sstevel@tonic-gate } 1571daaffb31Sdp # 1572daaffb31Sdp # 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines. 1573daaffb31Sdp # following would be 5 - 3 = 2! Hence +1 for correction. 1574daaffb31Sdp # 15757c478bd9Sstevel@tonic-gate r=(counts[2]-counts[1])+1; 1576daaffb31Sdp 1577daaffb31Sdp # 1578daaffb31Sdp # Now count replacement lines: each represents a change instead 1579daaffb31Sdp # of a delete, so increment c and decrement r. 1580daaffb31Sdp # 15817c478bd9Sstevel@tonic-gate while (getline != /^\.$/) { 15827c478bd9Sstevel@tonic-gate c++; 15837c478bd9Sstevel@tonic-gate r--; 15847c478bd9Sstevel@tonic-gate } 1585daaffb31Sdp # 1586daaffb31Sdp # If there were more replacement lines than original lines, 1587daaffb31Sdp # then r will be negative; in this case there are no deletions, 1588daaffb31Sdp # but there are r changes that should be counted as adds, and 1589daaffb31Sdp # since r is negative, subtract it from a and add it to c. 1590daaffb31Sdp # 15917c478bd9Sstevel@tonic-gate if (r < 0) { 15927c478bd9Sstevel@tonic-gate a-=r; 15937c478bd9Sstevel@tonic-gate c+=r; 15947c478bd9Sstevel@tonic-gate } 1595daaffb31Sdp 1596daaffb31Sdp # 1597daaffb31Sdp # If there were more original lines than replacement lines, then 1598daaffb31Sdp # r will be positive; in this case, increment d by that much. 1599daaffb31Sdp # 16007c478bd9Sstevel@tonic-gate if (r > 0) { 16017c478bd9Sstevel@tonic-gate d+=r; 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate next; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 1606daaffb31Sdp # Change lines: Nc 16077c478bd9Sstevel@tonic-gate /^[0-9].*c$/ { 1608daaffb31Sdp # The first line is a replacement; any more are additions. 16097c478bd9Sstevel@tonic-gate if (getline != /^\.$/) { 16107c478bd9Sstevel@tonic-gate c++; 16117c478bd9Sstevel@tonic-gate while (getline != /^\.$/) a++; 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate next; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 1616daaffb31Sdp # Add lines: both Na and N,Na 16177c478bd9Sstevel@tonic-gate /^[0-9].*a$/ { 16187c478bd9Sstevel@tonic-gate while (getline != /^\.$/) a++; 16197c478bd9Sstevel@tonic-gate next; 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate 1622daaffb31Sdp # Delete range of lines: N,Nd 16237c478bd9Sstevel@tonic-gate /^[0-9]*,[0-9]*d$/ { 16247c478bd9Sstevel@tonic-gate n=split(substr($1,1,length($1)-1), counts, ","); 16257c478bd9Sstevel@tonic-gate if (n != 2) { 16267c478bd9Sstevel@tonic-gate error=2 16277c478bd9Sstevel@tonic-gate exit; 16287c478bd9Sstevel@tonic-gate } 1629daaffb31Sdp # 1630daaffb31Sdp # 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines. 1631daaffb31Sdp # following would be 5 - 3 = 2! Hence +1 for correction. 1632daaffb31Sdp # 16337c478bd9Sstevel@tonic-gate r=(counts[2]-counts[1])+1; 16347c478bd9Sstevel@tonic-gate d+=r; 16357c478bd9Sstevel@tonic-gate next; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 1638daaffb31Sdp # Delete line: Nd. For example 10d says line 10 is deleted. 16397c478bd9Sstevel@tonic-gate /^[0-9]*d$/ {d++; next} 16407c478bd9Sstevel@tonic-gate 1641daaffb31Sdp # Should not get here! 16427c478bd9Sstevel@tonic-gate { 16437c478bd9Sstevel@tonic-gate error=1; 16447c478bd9Sstevel@tonic-gate exit; 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 1647daaffb31Sdp # Finish off - print results 16487c478bd9Sstevel@tonic-gate END { 1649daaffb31Sdp printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n", 16507c478bd9Sstevel@tonic-gate (c+d+a), c, d, a, error); 16517c478bd9Sstevel@tonic-gate }' ) 16527c478bd9Sstevel@tonic-gate 1653cdf0c1d5Smjnelson # End of $AWK, Check to see if any trouble occurred. 16547c478bd9Sstevel@tonic-gate if (( $? > 0 || err > 0 )); then 1655daaffb31Sdp print "Unexpected Error occurred reading" \ 1656daaffb31Sdp "\`diff -e $1 $2\`: \$?=$?, err=" $err 1657daaffb31Sdp return 1658daaffb31Sdp fi 1659daaffb31Sdp 16607c478bd9Sstevel@tonic-gate # Accumulate totals 16617c478bd9Sstevel@tonic-gate (( TOTL += tot )) 1662daaffb31Sdp (( TMOD += mod )) 16637c478bd9Sstevel@tonic-gate (( TDEL += del )) 16647c478bd9Sstevel@tonic-gate (( TINS += ins )) 16657c478bd9Sstevel@tonic-gate # Calculate unchanged lines 1666cdf0c1d5Smjnelson unc=`wc -l < $1` 16677c478bd9Sstevel@tonic-gate if (( unc > 0 )); then 1668daaffb31Sdp (( unc -= del + mod )) 16697c478bd9Sstevel@tonic-gate (( TUNC += unc )) 16707c478bd9Sstevel@tonic-gate fi 16717c478bd9Sstevel@tonic-gate # print summary 1672daaffb31Sdp print "<span class=\"lineschanged\">" 1673daaffb31Sdp printCI $tot $ins $del $mod $unc 1674daaffb31Sdp print "</span>" 16757c478bd9Sstevel@tonic-gate} 16767c478bd9Sstevel@tonic-gate 1677daaffb31Sdp 16787c478bd9Sstevel@tonic-gate# 1679daaffb31Sdp# flist_from_wx 1680daaffb31Sdp# 1681daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file. 1682daaffb31Sdp# Sets the global 'wxfile' variable. 1683daaffb31Sdp# 1684daaffb31Sdpfunction flist_from_wx 16857c478bd9Sstevel@tonic-gate{ 1686daaffb31Sdp typeset argfile=$1 1687daaffb31Sdp if [[ -n ${argfile%%/*} ]]; then 1688daaffb31Sdp # 1689daaffb31Sdp # If the wx file pathname is relative then make it absolute 1690daaffb31Sdp # because the webrev does a "cd" later on. 1691daaffb31Sdp # 1692daaffb31Sdp wxfile=$PWD/$argfile 16937c478bd9Sstevel@tonic-gate else 1694daaffb31Sdp wxfile=$argfile 16957c478bd9Sstevel@tonic-gate fi 16967c478bd9Sstevel@tonic-gate 1697cdf0c1d5Smjnelson $AWK '{ c = 1; print; 16987c478bd9Sstevel@tonic-gate while (getline) { 16997c478bd9Sstevel@tonic-gate if (NF == 0) { c = -c; continue } 17007c478bd9Sstevel@tonic-gate if (c > 0) print 17017c478bd9Sstevel@tonic-gate } 1702daaffb31Sdp }' $wxfile > $FLIST 17037c478bd9Sstevel@tonic-gate 1704daaffb31Sdp print " Done." 1705daaffb31Sdp} 17067c478bd9Sstevel@tonic-gate 1707daaffb31Sdp# 1708daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ] 1709daaffb31Sdp# 1710daaffb31Sdp# Generate the file list by extracting file names from a putback -n. Some 1711daaffb31Sdp# names may come from the "update/create" messages and others from the 1712daaffb31Sdp# "currently checked out" warning. Renames are detected here too. Extract 1713daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback 1714daaffb31Sdp# -n as well, but remove them if they are already defined. 1715daaffb31Sdp# 1716daaffb31Sdpfunction flist_from_teamware 1717daaffb31Sdp{ 1718cdf0c1d5Smjnelson if [[ -n $codemgr_parent && -z $parent_webrev ]]; then 1719daaffb31Sdp if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then 1720daaffb31Sdp print -u2 "parent $codemgr_parent doesn't look like a" \ 1721daaffb31Sdp "valid teamware workspace" 17227c478bd9Sstevel@tonic-gate exit 1 17237c478bd9Sstevel@tonic-gate fi 1724daaffb31Sdp parent_args="-p $codemgr_parent" 17257c478bd9Sstevel@tonic-gate fi 17267c478bd9Sstevel@tonic-gate 1727daaffb31Sdp print " File list from: 'putback -n $parent_args $*' ... \c" 17287c478bd9Sstevel@tonic-gate 1729daaffb31Sdp putback -n $parent_args $* 2>&1 | 1730cdf0c1d5Smjnelson $AWK ' 1731daaffb31Sdp /^update:|^create:/ {print $2} 1732daaffb31Sdp /^Parent workspace:/ {printf("CODEMGR_PARENT=%s\n",$3)} 1733daaffb31Sdp /^Child workspace:/ {printf("CODEMGR_WS=%s\n",$3)} 1734daaffb31Sdp /^The following files are currently checked out/ {p = 1; continue} 1735daaffb31Sdp NF == 0 {p=0 ; continue} 1736daaffb31Sdp /^rename/ {old=$3} 1737daaffb31Sdp $1 == "to:" {print $2, old} 1738daaffb31Sdp /^"/ {continue} 1739daaffb31Sdp p == 1 {print $1}' | 1740daaffb31Sdp sort -r -k 1,1 -u | sort > $FLIST 17417c478bd9Sstevel@tonic-gate 1742daaffb31Sdp print " Done." 1743daaffb31Sdp} 1744daaffb31Sdp 1745cdf0c1d5Smjnelson# 1746cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format 1747cdf0c1d5Smjnelson# 1748cdf0c1d5Smjnelsonfunction hg_active_wxfile 1749cdf0c1d5Smjnelson{ 1750cdf0c1d5Smjnelson typeset child=$1 1751cdf0c1d5Smjnelson typeset parent=$2 1752cdf0c1d5Smjnelson 1753cdf0c1d5Smjnelson TMPFLIST=/tmp/$$.active 17549a70fc3bSMark J. Nelson $HG_ACTIVE -w $child -p $parent -o $TMPFLIST 1755cdf0c1d5Smjnelson wxfile=$TMPFLIST 1756cdf0c1d5Smjnelson} 1757cdf0c1d5Smjnelson 1758cdf0c1d5Smjnelson# 1759cdf0c1d5Smjnelson# flist_from_mercurial 1760cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to 1761cdf0c1d5Smjnelson# flist_from_wx 1762cdf0c1d5Smjnelson# 1763cdf0c1d5Smjnelsonfunction flist_from_mercurial 1764cdf0c1d5Smjnelson{ 1765cdf0c1d5Smjnelson typeset child=$1 1766cdf0c1d5Smjnelson typeset parent=$2 1767cdf0c1d5Smjnelson 1768cdf0c1d5Smjnelson print " File list from: hg-active -p $parent ...\c" 1769cdf0c1d5Smjnelson 1770cdf0c1d5Smjnelson if [[ ! -x $HG_ACTIVE ]]; then 1771cdf0c1d5Smjnelson print # Blank line for the \c above 1772cdf0c1d5Smjnelson print -u2 "Error: hg-active tool not found. Exiting" 1773cdf0c1d5Smjnelson exit 1 1774cdf0c1d5Smjnelson fi 1775cdf0c1d5Smjnelson hg_active_wxfile $child $parent 1776cdf0c1d5Smjnelson 1777cdf0c1d5Smjnelson # flist_from_wx prints the Done, so we don't have to. 1778cdf0c1d5Smjnelson flist_from_wx $TMPFLIST 1779cdf0c1d5Smjnelson} 1780cdf0c1d5Smjnelson 1781cdf0c1d5Smjnelson# 1782cdf0c1d5Smjnelson# flist_from_subversion 1783cdf0c1d5Smjnelson# 1784cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status. 1785cdf0c1d5Smjnelson# 1786cdf0c1d5Smjnelsonfunction flist_from_subversion 1787cdf0c1d5Smjnelson{ 1788cdf0c1d5Smjnelson CWS=$1 1789cdf0c1d5Smjnelson OLDPWD=$2 1790cdf0c1d5Smjnelson 1791cdf0c1d5Smjnelson cd $CWS 1792cdf0c1d5Smjnelson print -u2 " File list from: svn status ... \c" 1793cdf0c1d5Smjnelson svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST 1794cdf0c1d5Smjnelson print -u2 " Done." 1795cdf0c1d5Smjnelson cd $OLDPWD 1796cdf0c1d5Smjnelson} 1797cdf0c1d5Smjnelson 1798daaffb31Sdpfunction env_from_flist 1799daaffb31Sdp{ 1800daaffb31Sdp [[ -r $FLIST ]] || return 1801daaffb31Sdp 1802daaffb31Sdp # 1803daaffb31Sdp # Use "eval" to set env variables that are listed in the file 1804daaffb31Sdp # list. Then copy those into our local versions of those 1805daaffb31Sdp # variables if they have not been set already. 1806daaffb31Sdp # 1807b0088928SVladimir Kotal eval `$SED -e "s/#.*$//" $FLIST | $GREP = ` 18087c478bd9Sstevel@tonic-gate 1809cdf0c1d5Smjnelson if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then 1810cdf0c1d5Smjnelson codemgr_ws=$CODEMGR_WS 1811cdf0c1d5Smjnelson export CODEMGR_WS 1812cdf0c1d5Smjnelson fi 18137c478bd9Sstevel@tonic-gate 1814daaffb31Sdp # 1815daaffb31Sdp # Check to see if CODEMGR_PARENT is set in the flist file. 1816daaffb31Sdp # 1817cdf0c1d5Smjnelson if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then 1818daaffb31Sdp codemgr_parent=$CODEMGR_PARENT 1819cdf0c1d5Smjnelson export CODEMGR_PARENT 1820daaffb31Sdp fi 1821daaffb31Sdp} 1822daaffb31Sdp 182314983201Sdpfunction look_for_prog 182414983201Sdp{ 182514983201Sdp typeset path 182614983201Sdp typeset ppath 182714983201Sdp typeset progname=$1 182814983201Sdp 182914983201Sdp ppath=$PATH 183014983201Sdp ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin 183114983201Sdp ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin 1832cdf0c1d5Smjnelson ppath=$ppath:/opt/onbld/bin/`uname -p` 183314983201Sdp 183414983201Sdp PATH=$ppath prog=`whence $progname` 183514983201Sdp if [[ -n $prog ]]; then 183614983201Sdp print $prog 183714983201Sdp fi 183814983201Sdp} 183914983201Sdp 1840cdf0c1d5Smjnelsonfunction get_file_mode 1841cdf0c1d5Smjnelson{ 1842cdf0c1d5Smjnelson $PERL -e ' 1843cdf0c1d5Smjnelson if (@stat = stat($ARGV[0])) { 1844cdf0c1d5Smjnelson $mode = $stat[2] & 0777; 1845cdf0c1d5Smjnelson printf "%03o\n", $mode; 1846cdf0c1d5Smjnelson exit 0; 1847cdf0c1d5Smjnelson } else { 1848cdf0c1d5Smjnelson exit 1; 1849cdf0c1d5Smjnelson } 1850cdf0c1d5Smjnelson ' $1 1851cdf0c1d5Smjnelson} 1852cdf0c1d5Smjnelson 1853cdf0c1d5Smjnelsonfunction build_old_new_teamware 1854cdf0c1d5Smjnelson{ 1855cdf0c1d5Smjnelson typeset olddir="$1" 1856cdf0c1d5Smjnelson typeset newdir="$2" 1857cdf0c1d5Smjnelson 1858cdf0c1d5Smjnelson # If the child's version doesn't exist then 1859cdf0c1d5Smjnelson # get a readonly copy. 1860cdf0c1d5Smjnelson 1861cdf0c1d5Smjnelson if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then 1862cdf0c1d5Smjnelson $SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F 1863cdf0c1d5Smjnelson fi 1864cdf0c1d5Smjnelson 1865cdf0c1d5Smjnelson # The following two sections propagate file permissions the 1866cdf0c1d5Smjnelson # same way SCCS does. If the file is already under version 1867cdf0c1d5Smjnelson # control, always use permissions from the SCCS/s.file. If 1868cdf0c1d5Smjnelson # the file is not under SCCS control, use permissions from the 1869cdf0c1d5Smjnelson # working copy. In all cases, the file copied to the webrev 1870cdf0c1d5Smjnelson # is set to read only, and group/other permissions are set to 1871cdf0c1d5Smjnelson # match those of the file owner. This way, even if the file 1872cdf0c1d5Smjnelson # is currently checked out, the webrev will display the final 1873cdf0c1d5Smjnelson # permissions that would result after check in. 1874cdf0c1d5Smjnelson 1875cdf0c1d5Smjnelson # 1876cdf0c1d5Smjnelson # Snag new version of file. 1877cdf0c1d5Smjnelson # 1878cdf0c1d5Smjnelson rm -f $newdir/$DIR/$F 1879cdf0c1d5Smjnelson cp $CWS/$DIR/$F $newdir/$DIR/$F 1880cdf0c1d5Smjnelson if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then 1881cdf0c1d5Smjnelson chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \ 1882cdf0c1d5Smjnelson $newdir/$DIR/$F 1883cdf0c1d5Smjnelson fi 1884cdf0c1d5Smjnelson chmod u-w,go=u $newdir/$DIR/$F 1885cdf0c1d5Smjnelson 1886cdf0c1d5Smjnelson # 1887cdf0c1d5Smjnelson # Get the parent's version of the file. First see whether the 1888cdf0c1d5Smjnelson # child's version is checked out and get the parent's version 1889cdf0c1d5Smjnelson # with keywords expanded or unexpanded as appropriate. 1890cdf0c1d5Smjnelson # 1891cdf0c1d5Smjnelson if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \ 1892cdf0c1d5Smjnelson ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then 1893cdf0c1d5Smjnelson # Parent is not a real workspace, but just a raw 1894cdf0c1d5Smjnelson # directory tree - use the file that's there as 1895cdf0c1d5Smjnelson # the old file. 1896cdf0c1d5Smjnelson 1897cdf0c1d5Smjnelson rm -f $olddir/$PDIR/$PF 1898cdf0c1d5Smjnelson cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF 1899cdf0c1d5Smjnelson else 1900cdf0c1d5Smjnelson if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then 1901cdf0c1d5Smjnelson real_parent=$PWS 1902cdf0c1d5Smjnelson else 1903cdf0c1d5Smjnelson real_parent=$RWS 1904cdf0c1d5Smjnelson fi 1905cdf0c1d5Smjnelson 1906cdf0c1d5Smjnelson rm -f $olddir/$PDIR/$PF 1907cdf0c1d5Smjnelson 1908cdf0c1d5Smjnelson if [[ -f $real_parent/$PDIR/$PF ]]; then 1909cdf0c1d5Smjnelson if [ -f $CWS/$DIR/SCCS/p.$F ]; then 1910cdf0c1d5Smjnelson $SCCS get -s -p -k $real_parent/$PDIR/$PF > \ 1911cdf0c1d5Smjnelson $olddir/$PDIR/$PF 1912cdf0c1d5Smjnelson else 1913cdf0c1d5Smjnelson $SCCS get -s -p $real_parent/$PDIR/$PF > \ 1914cdf0c1d5Smjnelson $olddir/$PDIR/$PF 1915cdf0c1d5Smjnelson fi 1916cdf0c1d5Smjnelson chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \ 1917cdf0c1d5Smjnelson $olddir/$PDIR/$PF 1918cdf0c1d5Smjnelson fi 1919cdf0c1d5Smjnelson fi 1920cdf0c1d5Smjnelson if [[ -f $olddir/$PDIR/$PF ]]; then 1921cdf0c1d5Smjnelson chmod u-w,go=u $olddir/$PDIR/$PF 1922cdf0c1d5Smjnelson fi 1923cdf0c1d5Smjnelson} 1924cdf0c1d5Smjnelson 1925cdf0c1d5Smjnelsonfunction build_old_new_mercurial 1926cdf0c1d5Smjnelson{ 1927cdf0c1d5Smjnelson typeset olddir="$1" 1928cdf0c1d5Smjnelson typeset newdir="$2" 1929cdf0c1d5Smjnelson typeset old_mode= 1930cdf0c1d5Smjnelson typeset new_mode= 1931cdf0c1d5Smjnelson typeset file 1932cdf0c1d5Smjnelson 1933cdf0c1d5Smjnelson # 1934cdf0c1d5Smjnelson # Get old file mode, from the parent revision manifest entry. 1935cdf0c1d5Smjnelson # Mercurial only stores a "file is executable" flag, but the 1936cdf0c1d5Smjnelson # manifest will display an octal mode "644" or "755". 1937cdf0c1d5Smjnelson # 1938cdf0c1d5Smjnelson if [[ "$PDIR" == "." ]]; then 1939cdf0c1d5Smjnelson file="$PF" 1940cdf0c1d5Smjnelson else 1941cdf0c1d5Smjnelson file="$PDIR/$PF" 1942cdf0c1d5Smjnelson fi 1943b0088928SVladimir Kotal file=`echo $file | $SED 's#/#\\\/#g'` 1944cdf0c1d5Smjnelson # match the exact filename, and return only the permission digits 1945b0088928SVladimir Kotal old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \ 1946cdf0c1d5Smjnelson < $HG_PARENT_MANIFEST` 1947cdf0c1d5Smjnelson 1948cdf0c1d5Smjnelson # 1949cdf0c1d5Smjnelson # Get new file mode, directly from the filesystem. 1950cdf0c1d5Smjnelson # Normalize the mode to match Mercurial's behavior. 1951cdf0c1d5Smjnelson # 1952cdf0c1d5Smjnelson new_mode=`get_file_mode $CWS/$DIR/$F` 1953cdf0c1d5Smjnelson if [[ -n "$new_mode" ]]; then 1954cdf0c1d5Smjnelson if [[ "$new_mode" = *[1357]* ]]; then 1955cdf0c1d5Smjnelson new_mode=755 1956cdf0c1d5Smjnelson else 1957cdf0c1d5Smjnelson new_mode=644 1958cdf0c1d5Smjnelson fi 1959cdf0c1d5Smjnelson fi 1960cdf0c1d5Smjnelson 1961cdf0c1d5Smjnelson # 1962cdf0c1d5Smjnelson # new version of the file. 1963cdf0c1d5Smjnelson # 1964cdf0c1d5Smjnelson rm -rf $newdir/$DIR/$F 1965cdf0c1d5Smjnelson if [[ -e $CWS/$DIR/$F ]]; then 1966cdf0c1d5Smjnelson cp $CWS/$DIR/$F $newdir/$DIR/$F 1967cdf0c1d5Smjnelson if [[ -n $new_mode ]]; then 1968cdf0c1d5Smjnelson chmod $new_mode $newdir/$DIR/$F 1969cdf0c1d5Smjnelson else 1970cdf0c1d5Smjnelson # should never happen 1971cdf0c1d5Smjnelson print -u2 "ERROR: set mode of $newdir/$DIR/$F" 1972cdf0c1d5Smjnelson fi 1973cdf0c1d5Smjnelson fi 1974cdf0c1d5Smjnelson 1975cdf0c1d5Smjnelson # 1976cdf0c1d5Smjnelson # parent's version of the file 1977cdf0c1d5Smjnelson # 1978cdf0c1d5Smjnelson # Note that we get this from the last version common to both 1979cdf0c1d5Smjnelson # ourselves and the parent. References are via $CWS since we have no 1980cdf0c1d5Smjnelson # guarantee that the parent workspace is reachable via the filesystem. 1981cdf0c1d5Smjnelson # 1982cdf0c1d5Smjnelson if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then 1983cdf0c1d5Smjnelson cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF 1984cdf0c1d5Smjnelson elif [[ -n $HG_PARENT ]]; then 1985cdf0c1d5Smjnelson hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \ 1986cdf0c1d5Smjnelson $olddir/$PDIR/$PF 2>/dev/null 1987cdf0c1d5Smjnelson 198802d26c39SVladimir Kotal if (( $? != 0 )); then 1989cdf0c1d5Smjnelson rm -f $olddir/$PDIR/$PF 1990cdf0c1d5Smjnelson else 1991cdf0c1d5Smjnelson if [[ -n $old_mode ]]; then 1992cdf0c1d5Smjnelson chmod $old_mode $olddir/$PDIR/$PF 1993cdf0c1d5Smjnelson else 1994cdf0c1d5Smjnelson # should never happen 1995cdf0c1d5Smjnelson print -u2 "ERROR: set mode of $olddir/$PDIR/$PF" 1996cdf0c1d5Smjnelson fi 1997cdf0c1d5Smjnelson fi 1998cdf0c1d5Smjnelson fi 1999cdf0c1d5Smjnelson} 2000cdf0c1d5Smjnelson 2001cdf0c1d5Smjnelsonfunction build_old_new_subversion 2002cdf0c1d5Smjnelson{ 2003cdf0c1d5Smjnelson typeset olddir="$1" 2004cdf0c1d5Smjnelson typeset newdir="$2" 2005cdf0c1d5Smjnelson 2006cdf0c1d5Smjnelson # Snag new version of file. 2007cdf0c1d5Smjnelson rm -f $newdir/$DIR/$F 2008cdf0c1d5Smjnelson [[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F 2009cdf0c1d5Smjnelson 2010cdf0c1d5Smjnelson if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then 2011cdf0c1d5Smjnelson cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF 2012cdf0c1d5Smjnelson else 2013cdf0c1d5Smjnelson # Get the parent's version of the file. 2014cdf0c1d5Smjnelson svn status $CWS/$DIR/$F | read stat file 2015cdf0c1d5Smjnelson if [[ $stat != "A" ]]; then 2016cdf0c1d5Smjnelson svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF 2017cdf0c1d5Smjnelson fi 2018cdf0c1d5Smjnelson fi 2019cdf0c1d5Smjnelson} 2020cdf0c1d5Smjnelson 2021cdf0c1d5Smjnelsonfunction build_old_new_unknown 2022cdf0c1d5Smjnelson{ 2023cdf0c1d5Smjnelson typeset olddir="$1" 2024cdf0c1d5Smjnelson typeset newdir="$2" 2025cdf0c1d5Smjnelson 2026cdf0c1d5Smjnelson # 2027cdf0c1d5Smjnelson # Snag new version of file. 2028cdf0c1d5Smjnelson # 2029cdf0c1d5Smjnelson rm -f $newdir/$DIR/$F 2030cdf0c1d5Smjnelson [[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F 2031cdf0c1d5Smjnelson 2032cdf0c1d5Smjnelson # 2033cdf0c1d5Smjnelson # Snag the parent's version of the file. 2034cdf0c1d5Smjnelson # 2035cdf0c1d5Smjnelson if [[ -f $PWS/$PDIR/$PF ]]; then 2036cdf0c1d5Smjnelson rm -f $olddir/$PDIR/$PF 2037cdf0c1d5Smjnelson cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF 2038cdf0c1d5Smjnelson fi 2039cdf0c1d5Smjnelson} 2040cdf0c1d5Smjnelson 2041cdf0c1d5Smjnelsonfunction build_old_new 2042cdf0c1d5Smjnelson{ 2043cdf0c1d5Smjnelson typeset WDIR=$1 2044cdf0c1d5Smjnelson typeset PWS=$2 2045cdf0c1d5Smjnelson typeset PDIR=$3 2046cdf0c1d5Smjnelson typeset PF=$4 2047cdf0c1d5Smjnelson typeset CWS=$5 2048cdf0c1d5Smjnelson typeset DIR=$6 2049cdf0c1d5Smjnelson typeset F=$7 2050cdf0c1d5Smjnelson 2051cdf0c1d5Smjnelson typeset olddir="$WDIR/raw_files/old" 2052cdf0c1d5Smjnelson typeset newdir="$WDIR/raw_files/new" 2053cdf0c1d5Smjnelson 2054cdf0c1d5Smjnelson mkdir -p $olddir/$PDIR 2055cdf0c1d5Smjnelson mkdir -p $newdir/$DIR 2056cdf0c1d5Smjnelson 2057cdf0c1d5Smjnelson if [[ $SCM_MODE == "teamware" ]]; then 2058cdf0c1d5Smjnelson build_old_new_teamware "$olddir" "$newdir" 2059cdf0c1d5Smjnelson elif [[ $SCM_MODE == "mercurial" ]]; then 2060cdf0c1d5Smjnelson build_old_new_mercurial "$olddir" "$newdir" 2061cdf0c1d5Smjnelson elif [[ $SCM_MODE == "subversion" ]]; then 2062cdf0c1d5Smjnelson build_old_new_subversion "$olddir" "$newdir" 2063cdf0c1d5Smjnelson elif [[ $SCM_MODE == "unknown" ]]; then 2064cdf0c1d5Smjnelson build_old_new_unknown "$olddir" "$newdir" 2065cdf0c1d5Smjnelson fi 2066cdf0c1d5Smjnelson 2067cdf0c1d5Smjnelson if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then 2068cdf0c1d5Smjnelson print "*** Error: file not in parent or child" 2069cdf0c1d5Smjnelson return 1 2070cdf0c1d5Smjnelson fi 2071cdf0c1d5Smjnelson return 0 2072cdf0c1d5Smjnelson} 2073cdf0c1d5Smjnelson 2074cdf0c1d5Smjnelson 2075daaffb31Sdp# 2076daaffb31Sdp# Usage message. 2077daaffb31Sdp# 2078daaffb31Sdpfunction usage 2079daaffb31Sdp{ 2080daaffb31Sdp print 'Usage:\twebrev [common-options] 2081daaffb31Sdp webrev [common-options] ( <file> | - ) 2082daaffb31Sdp webrev [common-options] -w <wx file> 2083daaffb31Sdp 2084daaffb31SdpOptions: 20850fd2682eSMark J. Nelson -C <filename>: Use <filename> for the information tracking configuration. 2086ba44d8a2SVladimir Kotal -D: delete remote webrev 2087daaffb31Sdp -i <filename>: Include <filename> in the index.html file. 20880fd2682eSMark J. Nelson -I <filename>: Use <filename> for the information tracking registry. 2089ba44d8a2SVladimir Kotal -n: do not generate the webrev (useful with -U) 2090ba44d8a2SVladimir Kotal -O: Print bugids/arc cases suitable for OpenSolaris. 2091daaffb31Sdp -o <outdir>: Output webrev to specified directory. 2092daaffb31Sdp -p <compare-against>: Use specified parent wkspc or basis for comparison 209302d26c39SVladimir Kotal -t <remote_target>: Specify remote destination for webrev upload 209402d26c39SVladimir Kotal -U: upload the webrev to remote destination 2095daaffb31Sdp -w <wxfile>: Use specified wx active file. 2096daaffb31Sdp 2097daaffb31SdpEnvironment: 2098daaffb31Sdp WDIR: Control the output directory. 2099ba44d8a2SVladimir Kotal WEBREV_TRASH_DIR: Set directory for webrev delete. 2100daaffb31Sdp 2101cdf0c1d5SmjnelsonSCM Specific Options: 2102cdf0c1d5Smjnelson TeamWare: webrev [common-options] -l [arguments to 'putback'] 2103cdf0c1d5Smjnelson 2104daaffb31SdpSCM Environment: 2105cdf0c1d5Smjnelson CODEMGR_WS: Workspace location. 2106cdf0c1d5Smjnelson CODEMGR_PARENT: Parent workspace location. 2107daaffb31Sdp' 2108daaffb31Sdp 2109daaffb31Sdp exit 2 2110daaffb31Sdp} 2111daaffb31Sdp 2112daaffb31Sdp# 2113daaffb31Sdp# 2114daaffb31Sdp# Main program starts here 2115daaffb31Sdp# 2116daaffb31Sdp# 2117daaffb31Sdp 2118daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15 2119daaffb31Sdp 2120daaffb31Sdpset +o noclobber 2121daaffb31Sdp 2122cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH 2123cdf0c1d5Smjnelson 212414983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff` 212514983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx` 2126cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active` 2127cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm` 212814983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview` 212914983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf` 213014983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl` 213102d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync` 2132cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs` 2133cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk` 2134cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk` 2135cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk` 213602d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp` 2137b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed` 213802d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp` 2139*e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort` 214002d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp` 214102d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep` 2142ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find` 2143cdf0c1d5Smjnelson 2144ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion 2145ba44d8a2SVladimir KotalTRASH_DIR=".trash" 2146ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR 214714983201Sdp 214814983201Sdpif [[ ! -x $PERL ]]; then 214914983201Sdp print -u2 "Error: No perl interpreter found. Exiting." 215014983201Sdp exit 1 2151daaffb31Sdpfi 215214983201Sdp 2153cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then 2154cdf0c1d5Smjnelson print -u2 "Error: Could not find which_scm. Exiting." 2155cdf0c1d5Smjnelson exit 1 2156cdf0c1d5Smjnelsonfi 2157cdf0c1d5Smjnelson 215814983201Sdp# 215914983201Sdp# These aren't fatal, but we want to note them to the user. 216014983201Sdp# We don't warn on the absence of 'wx' until later when we've 216114983201Sdp# determined that we actually need to try to invoke it. 216214983201Sdp# 216314983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found." 216414983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found." 216514983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found." 2166daaffb31Sdp 2167daaffb31Sdp# Declare global total counters. 2168daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC 2169daaffb31Sdp 2170ba44d8a2SVladimir Kotal# default remote host for upload/delete 2171ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org" 2172b0088928SVladimir Kotal# prefixes for upload targets 2173b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://" 2174b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://" 2175ba44d8a2SVladimir Kotal 21760fd2682eSMark J. NelsonCflag= 2177ba44d8a2SVladimir KotalDflag= 217814983201Sdpflist_mode= 217914983201Sdpflist_file= 2180daaffb31Sdpiflag= 21810fd2682eSMark J. NelsonIflag= 218202d26c39SVladimir Kotallflag= 218302d26c39SVladimir KotalNflag= 218402d26c39SVladimir Kotalnflag= 218502d26c39SVladimir KotalOflag= 2186daaffb31Sdpoflag= 2187daaffb31Sdppflag= 218802d26c39SVladimir Kotaltflag= 218902d26c39SVladimir Kotaluflag= 219002d26c39SVladimir KotalUflag= 2191daaffb31Sdpwflag= 219202d26c39SVladimir Kotalremote_target= 2193ba44d8a2SVladimir Kotal 2194ba44d8a2SVladimir Kotal# 2195ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list 2196ba44d8a2SVladimir Kotal# with usr/src/tools/onbld/hgext/cdm.py 2197ba44d8a2SVladimir Kotal# 219825cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt 2199daaffb31Sdpdo 2200daaffb31Sdp case $opt in 22010fd2682eSMark J. Nelson C) Cflag=1 22020fd2682eSMark J. Nelson ITSCONF=$OPTARG;; 22030fd2682eSMark J. Nelson 2204ba44d8a2SVladimir Kotal D) Dflag=1;; 2205ba44d8a2SVladimir Kotal 2206daaffb31Sdp i) iflag=1 2207daaffb31Sdp INCLUDE_FILE=$OPTARG;; 2208daaffb31Sdp 22090fd2682eSMark J. Nelson I) Iflag=1 22100fd2682eSMark J. Nelson ITSREG=$OPTARG;; 22110fd2682eSMark J. Nelson 2212daaffb31Sdp # 2213daaffb31Sdp # If -l has been specified, we need to abort further options 2214daaffb31Sdp # processing, because subsequent arguments are going to be 2215daaffb31Sdp # arguments to 'putback -n'. 2216daaffb31Sdp # 2217daaffb31Sdp l) lflag=1 2218daaffb31Sdp break;; 2219daaffb31Sdp 222002d26c39SVladimir Kotal N) Nflag=1;; 222102d26c39SVladimir Kotal 222202d26c39SVladimir Kotal n) nflag=1;; 2223daaffb31Sdp 2224daaffb31Sdp O) Oflag=1;; 2225daaffb31Sdp 222602d26c39SVladimir Kotal o) oflag=1 222702d26c39SVladimir Kotal WDIR=$OPTARG;; 222802d26c39SVladimir Kotal 222902d26c39SVladimir Kotal p) pflag=1 223002d26c39SVladimir Kotal codemgr_parent=$OPTARG;; 223102d26c39SVladimir Kotal 223202d26c39SVladimir Kotal t) tflag=1 223302d26c39SVladimir Kotal remote_target=$OPTARG;; 223402d26c39SVladimir Kotal 223502d26c39SVladimir Kotal U) Uflag=1;; 223602d26c39SVladimir Kotal 223702d26c39SVladimir Kotal w) wflag=1;; 22383df69ef3SDarren Moffat 2239daaffb31Sdp ?) usage;; 2240daaffb31Sdp esac 2241daaffb31Sdpdone 2242daaffb31Sdp 2243daaffb31SdpFLIST=/tmp/$$.flist 2244daaffb31Sdp 2245daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then 2246daaffb31Sdp usage 2247daaffb31Sdpfi 2248daaffb31Sdp 224902d26c39SVladimir Kotal# more sanity checking 225002d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then 2251ba44d8a2SVladimir Kotal print "it does not make sense to skip webrev generation" \ 2252ba44d8a2SVladimir Kotal "without -U" 225302d26c39SVladimir Kotal exit 1 225402d26c39SVladimir Kotalfi 225502d26c39SVladimir Kotal 2256ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then 2257ba44d8a2SVladimir Kotal echo "remote target has to be used only for upload or delete" 225802d26c39SVladimir Kotal exit 1 225902d26c39SVladimir Kotalfi 226002d26c39SVladimir Kotal 2261daaffb31Sdp# 22622d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume 22632d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name 22642d9224a3SMark J. Nelson# $(basename ${CWS}). So we need to get CWS set before we skip any remaining 22652d9224a3SMark J. Nelson# logic. 22662d9224a3SMark J. Nelson# 22672d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1 22682d9224a3SMark J. Nelsonif [[ $SCM_MODE == "teamware" ]]; then 22692d9224a3SMark J. Nelson # 22702d9224a3SMark J. Nelson # Teamware priorities: 22712d9224a3SMark J. Nelson # 1. CODEMGR_WS from the environment 22722d9224a3SMark J. Nelson # 2. workspace name 22732d9224a3SMark J. Nelson # 22742d9224a3SMark J. Nelson [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS 22752d9224a3SMark J. Nelson if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then 22762d9224a3SMark J. Nelson print -u2 "$codemgr_ws: no such workspace" 22772d9224a3SMark J. Nelson exit 1 22782d9224a3SMark J. Nelson fi 22792d9224a3SMark J. Nelson [[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name) 22802d9224a3SMark J. Nelson codemgr_ws=$(cd $codemgr_ws;print $PWD) 22812d9224a3SMark J. Nelson CODEMGR_WS=$codemgr_ws 22822d9224a3SMark J. Nelson CWS=$codemgr_ws 22832d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "mercurial" ]]; then 22842d9224a3SMark J. Nelson # 22852d9224a3SMark J. Nelson # Mercurial priorities: 22862d9224a3SMark J. Nelson # 1. hg root from CODEMGR_WS environment variable 22872d9224a3SMark J. Nelson # 2. hg root from directory of invocation 22882d9224a3SMark J. Nelson # 22892d9224a3SMark J. Nelson [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \ 22902d9224a3SMark J. Nelson codemgr_ws=$(hg root -R $CODEMGR_WS 2>/dev/null) 22912d9224a3SMark J. Nelson [[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null) 22922d9224a3SMark J. Nelson CWS=$codemgr_ws 22932d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then 22942d9224a3SMark J. Nelson # 22952d9224a3SMark J. Nelson # Subversion priorities: 22962d9224a3SMark J. Nelson # 1. CODEMGR_WS from environment 22972d9224a3SMark J. Nelson # 2. Relative path from current directory to SVN repository root 22982d9224a3SMark J. Nelson # 22992d9224a3SMark J. Nelson if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then 23002d9224a3SMark J. Nelson CWS=$CODEMGR_WS 23012d9224a3SMark J. Nelson else 23022d9224a3SMark J. Nelson svn info | while read line; do 23032d9224a3SMark J. Nelson if [[ $line == "URL: "* ]]; then 23042d9224a3SMark J. Nelson url=${line#URL: } 23052d9224a3SMark J. Nelson elif [[ $line == "Repository Root: "* ]]; then 23062d9224a3SMark J. Nelson repo=${line#Repository Root: } 23072d9224a3SMark J. Nelson fi 23082d9224a3SMark J. Nelson done 23092d9224a3SMark J. Nelson 23102d9224a3SMark J. Nelson rel=${url#$repo} 23112d9224a3SMark J. Nelson CWS=${PWD%$rel} 23122d9224a3SMark J. Nelson fi 23132d9224a3SMark J. Nelsonfi 23142d9224a3SMark J. Nelson 23152d9224a3SMark J. Nelson# 23162d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting 23172d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set. 23182d9224a3SMark J. Nelson# 23192d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then 23202d9224a3SMark J. Nelson CWS=${CODEMGR_WS:-.} 23212d9224a3SMark J. Nelsonfi 23222d9224a3SMark J. Nelson 23232d9224a3SMark J. Nelson 23242d9224a3SMark J. Nelson 23252d9224a3SMark J. Nelson# 23260fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either 23270fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole 23280fd2682eSMark J. Nelson# ton of logic we can skip. 23290fd2682eSMark J. Nelson# 23300fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop 23310fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within. 23320fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure. 23330fd2682eSMark J. Nelson# 23340fd2682eSMark J. Nelsonfor do_everything in 1; do 23350fd2682eSMark J. Nelson 23360fd2682eSMark J. Nelson# DO_EVERYTHING: break point 23370fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then 23380fd2682eSMark J. Nelson break 23390fd2682eSMark J. Nelsonfi 23400fd2682eSMark J. Nelson 23410fd2682eSMark J. Nelson# 2342daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev, 2343daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory. 2344daaffb31Sdp# 2345daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then 2346daaffb31Sdp parent_webrev="$codemgr_parent" 2347daaffb31Sdp codemgr_parent="$codemgr_parent/raw_files/new" 2348daaffb31Sdpfi 2349daaffb31Sdp 2350daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then 2351daaffb31Sdp shift $(($OPTIND - 1)) 2352daaffb31Sdp 2353daaffb31Sdp if [[ $1 == "-" ]]; then 2354daaffb31Sdp cat > $FLIST 235514983201Sdp flist_mode="stdin" 235614983201Sdp flist_done=1 235714983201Sdp shift 2358daaffb31Sdp elif [[ -n $1 ]]; then 235914983201Sdp if [[ ! -r $1 ]]; then 2360daaffb31Sdp print -u2 "$1: no such file or not readable" 2361daaffb31Sdp usage 2362daaffb31Sdp fi 2363daaffb31Sdp cat $1 > $FLIST 236414983201Sdp flist_mode="file" 236514983201Sdp flist_file=$1 236614983201Sdp flist_done=1 236714983201Sdp shift 2368daaffb31Sdp else 236914983201Sdp flist_mode="auto" 2370daaffb31Sdp fi 2371daaffb31Sdpfi 2372daaffb31Sdp 2373daaffb31Sdp# 2374daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think 2375daaffb31Sdp# is in use. 2376daaffb31Sdp# 2377cdf0c1d5Smjnelsoncase "$SCM_MODE" in 2378cdf0c1d5Smjnelsonteamware|mercurial|subversion) 2379cdf0c1d5Smjnelson ;; 2380cdf0c1d5Smjnelsonunknown) 2381cdf0c1d5Smjnelson if [[ $flist_mode == "auto" ]]; then 2382cdf0c1d5Smjnelson print -u2 "Unable to determine SCM in use and file list not specified" 2383cdf0c1d5Smjnelson print -u2 "See which_scm(1) for SCM detection information." 23847c478bd9Sstevel@tonic-gate exit 1 23857c478bd9Sstevel@tonic-gate fi 2386cdf0c1d5Smjnelson ;; 2387cdf0c1d5Smjnelson*) 2388cdf0c1d5Smjnelson if [[ $flist_mode == "auto" ]]; then 2389cdf0c1d5Smjnelson print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified" 2390cdf0c1d5Smjnelson exit 1 2391cdf0c1d5Smjnelson fi 2392cdf0c1d5Smjnelson ;; 2393cdf0c1d5Smjnelsonesac 23947c478bd9Sstevel@tonic-gate 2395daaffb31Sdpprint -u2 " SCM detected: $SCM_MODE" 2396daaffb31Sdp 2397daaffb31Sdpif [[ -n $lflag ]]; then 2398daaffb31Sdp # 2399daaffb31Sdp # If the -l flag is given instead of the name of a file list, 2400daaffb31Sdp # then generate the file list by extracting file names from a 2401daaffb31Sdp # putback -n. 2402daaffb31Sdp # 2403daaffb31Sdp shift $(($OPTIND - 1)) 2404cdf0c1d5Smjnelson if [[ $SCM_MODE == "teamware" ]]; then 2405daaffb31Sdp flist_from_teamware "$*" 2406cdf0c1d5Smjnelson else 2407cdf0c1d5Smjnelson print -u2 -- "Error: -l option only applies to TeamWare" 2408cdf0c1d5Smjnelson exit 1 2409cdf0c1d5Smjnelson fi 2410daaffb31Sdp flist_done=1 2411daaffb31Sdp shift $# 2412daaffb31Sdpelif [[ -n $wflag ]]; then 2413daaffb31Sdp # 2414daaffb31Sdp # If the -w is given then assume the file list is in Bonwick's "wx" 2415daaffb31Sdp # command format, i.e. pathname lines alternating with SCCS comment 2416daaffb31Sdp # lines with blank lines as separators. Use the SCCS comments later 2417daaffb31Sdp # in building the index.html file. 2418daaffb31Sdp # 2419daaffb31Sdp shift $(($OPTIND - 1)) 2420daaffb31Sdp wxfile=$1 2421daaffb31Sdp if [[ -z $wxfile && -n $CODEMGR_WS ]]; then 2422daaffb31Sdp if [[ -r $CODEMGR_WS/wx/active ]]; then 2423daaffb31Sdp wxfile=$CODEMGR_WS/wx/active 2424daaffb31Sdp fi 2425daaffb31Sdp fi 2426daaffb31Sdp 2427daaffb31Sdp [[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \ 2428daaffb31Sdp "be auto-detected (check \$CODEMGR_WS)" && exit 1 2429daaffb31Sdp 2430cdf0c1d5Smjnelson if [[ ! -r $wxfile ]]; then 2431cdf0c1d5Smjnelson print -u2 "$wxfile: no such file or not readable" 2432cdf0c1d5Smjnelson usage 2433cdf0c1d5Smjnelson fi 2434cdf0c1d5Smjnelson 2435daaffb31Sdp print -u2 " File list from: wx 'active' file '$wxfile' ... \c" 2436daaffb31Sdp flist_from_wx $wxfile 2437daaffb31Sdp flist_done=1 2438daaffb31Sdp if [[ -n "$*" ]]; then 2439daaffb31Sdp shift 2440daaffb31Sdp fi 244114983201Sdpelif [[ $flist_mode == "stdin" ]]; then 244214983201Sdp print -u2 " File list from: standard input" 244314983201Sdpelif [[ $flist_mode == "file" ]]; then 244414983201Sdp print -u2 " File list from: $flist_file" 2445daaffb31Sdpfi 2446daaffb31Sdp 2447daaffb31Sdpif [[ $# -gt 0 ]]; then 244814983201Sdp print -u2 "WARNING: unused arguments: $*" 2449daaffb31Sdpfi 2450daaffb31Sdp 24512d9224a3SMark J. Nelson# 24522d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS 24532d9224a3SMark J. Nelson# and CODEMGR_WS as needed. Here, we set the parent workspace. 24542d9224a3SMark J. Nelson# 24552d9224a3SMark J. Nelson 2456daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then 24572d9224a3SMark J. Nelson 2458daaffb31Sdp # 24592d9224a3SMark J. Nelson # Teamware priorities: 2460daaffb31Sdp # 24612d9224a3SMark J. Nelson # 1) via -p command line option 2462daaffb31Sdp # 2) in the user environment 2463daaffb31Sdp # 3) in the flist 24642d9224a3SMark J. Nelson # 4) automatically based on the workspace 2465daaffb31Sdp # 2466daaffb31Sdp 2467daaffb31Sdp # 24682d9224a3SMark J. Nelson # For 1, codemgr_parent will already be set. Here's 2: 2469daaffb31Sdp # 2470daaffb31Sdp [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \ 2471daaffb31Sdp codemgr_parent=$CODEMGR_PARENT 2472daaffb31Sdp if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then 2473daaffb31Sdp print -u2 "$codemgr_parent: no such directory" 24747c478bd9Sstevel@tonic-gate exit 1 24757c478bd9Sstevel@tonic-gate fi 24767c478bd9Sstevel@tonic-gate 2477daaffb31Sdp # 2478daaffb31Sdp # If we're in auto-detect mode and we haven't already gotten the file 2479daaffb31Sdp # list, then see if we can get it by probing for wx. 2480daaffb31Sdp # 248114983201Sdp if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then 248214983201Sdp if [[ ! -x $WX ]]; then 248314983201Sdp print -u2 "WARNING: wx not found!" 2484daaffb31Sdp fi 24857c478bd9Sstevel@tonic-gate 2486daaffb31Sdp # 2487daaffb31Sdp # We need to use wx list -w so that we get renamed files, etc. 2488daaffb31Sdp # but only if a wx active file exists-- otherwise wx will 2489daaffb31Sdp # hang asking us to initialize our wx information. 2490daaffb31Sdp # 249114983201Sdp if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then 2492daaffb31Sdp print -u2 " File list from: 'wx list -w' ... \c" 2493daaffb31Sdp $WX list -w > $FLIST 2494daaffb31Sdp $WX comments > /tmp/$$.wx_comments 2495daaffb31Sdp wxfile=/tmp/$$.wx_comments 2496daaffb31Sdp print -u2 "done" 2497daaffb31Sdp flist_done=1 2498daaffb31Sdp fi 2499daaffb31Sdp fi 2500daaffb31Sdp 2501daaffb31Sdp # 2502daaffb31Sdp # If by hook or by crook we've gotten a file list by now (perhaps 2503daaffb31Sdp # from the command line), eval it to extract environment variables from 25042d9224a3SMark J. Nelson # it: This is method 3 for finding the parent. 2505daaffb31Sdp # 2506daaffb31Sdp if [[ -z $flist_done ]]; then 2507daaffb31Sdp flist_from_teamware 2508daaffb31Sdp fi 25092d9224a3SMark J. Nelson env_from_flist 2510daaffb31Sdp 2511daaffb31Sdp # 2512daaffb31Sdp # (4) If we still don't have a value for codemgr_parent, get it 2513daaffb31Sdp # from workspace. 2514daaffb31Sdp # 2515daaffb31Sdp [[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent` 2516daaffb31Sdp if [[ ! -d $codemgr_parent ]]; then 2517daaffb31Sdp print -u2 "$CODEMGR_PARENT: no such parent workspace" 2518daaffb31Sdp exit 1 2519daaffb31Sdp fi 2520daaffb31Sdp 2521daaffb31Sdp PWS=$codemgr_parent 2522cdf0c1d5Smjnelson 2523cdf0c1d5Smjnelson [[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS) 2524cdf0c1d5Smjnelson 2525cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then 2526cdf0c1d5Smjnelson # 2527cdf0c1d5Smjnelson # Parent can either be specified with -p 2528cdf0c1d5Smjnelson # Specified with CODEMGR_PARENT in the environment 2529cdf0c1d5Smjnelson # or taken from hg's default path. 2530cdf0c1d5Smjnelson # 2531cdf0c1d5Smjnelson 2532cdf0c1d5Smjnelson if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then 2533cdf0c1d5Smjnelson codemgr_parent=$CODEMGR_PARENT 2534cdf0c1d5Smjnelson fi 2535cdf0c1d5Smjnelson 2536cdf0c1d5Smjnelson if [[ -z $codemgr_parent ]]; then 2537cdf0c1d5Smjnelson codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null` 2538cdf0c1d5Smjnelson fi 2539cdf0c1d5Smjnelson 2540cdf0c1d5Smjnelson CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null` 2541cdf0c1d5Smjnelson PWS=$codemgr_parent 2542cdf0c1d5Smjnelson 2543cdf0c1d5Smjnelson # 2544cdf0c1d5Smjnelson # If the parent is a webrev, we want to do some things against 2545cdf0c1d5Smjnelson # the natural workspace parent (file list, comments, etc) 2546cdf0c1d5Smjnelson # 2547cdf0c1d5Smjnelson if [[ -n $parent_webrev ]]; then 2548cdf0c1d5Smjnelson real_parent=$(hg path -R $codemgr_ws default 2>/dev/null) 2549cdf0c1d5Smjnelson else 2550cdf0c1d5Smjnelson real_parent=$PWS 2551cdf0c1d5Smjnelson fi 2552cdf0c1d5Smjnelson 2553cdf0c1d5Smjnelson # 2554cdf0c1d5Smjnelson # If hg-active exists, then we run it. In the case of no explicit 2555cdf0c1d5Smjnelson # flist given, we'll use it for our comments. In the case of an 2556cdf0c1d5Smjnelson # explicit flist given we'll try to use it for comments for any 2557cdf0c1d5Smjnelson # files mentioned in the flist. 2558cdf0c1d5Smjnelson # 2559cdf0c1d5Smjnelson if [[ -z $flist_done ]]; then 2560cdf0c1d5Smjnelson flist_from_mercurial $CWS $real_parent 2561cdf0c1d5Smjnelson flist_done=1 2562cdf0c1d5Smjnelson fi 2563cdf0c1d5Smjnelson 2564cdf0c1d5Smjnelson # 2565cdf0c1d5Smjnelson # If we have a file list now, pull out any variables set 2566cdf0c1d5Smjnelson # therein. We do this now (rather than when we possibly use 2567cdf0c1d5Smjnelson # hg-active to find comments) to avoid stomping specifications 2568cdf0c1d5Smjnelson # in the user-specified flist. 2569cdf0c1d5Smjnelson # 2570cdf0c1d5Smjnelson if [[ -n $flist_done ]]; then 2571cdf0c1d5Smjnelson env_from_flist 2572cdf0c1d5Smjnelson fi 2573cdf0c1d5Smjnelson 2574cdf0c1d5Smjnelson # 2575cdf0c1d5Smjnelson # Only call hg-active if we don't have a wx formatted file already 2576cdf0c1d5Smjnelson # 2577cdf0c1d5Smjnelson if [[ -x $HG_ACTIVE && -z $wxfile ]]; then 2578cdf0c1d5Smjnelson print " Comments from: hg-active -p $real_parent ...\c" 2579cdf0c1d5Smjnelson hg_active_wxfile $CWS $real_parent 2580cdf0c1d5Smjnelson print " Done." 2581cdf0c1d5Smjnelson fi 2582cdf0c1d5Smjnelson 2583cdf0c1d5Smjnelson # 2584cdf0c1d5Smjnelson # At this point we must have a wx flist either from hg-active, 2585cdf0c1d5Smjnelson # or in general. Use it to try and find our parent revision, 2586cdf0c1d5Smjnelson # if we don't have one. 2587cdf0c1d5Smjnelson # 2588cdf0c1d5Smjnelson if [[ -z $HG_PARENT ]]; then 2589b0088928SVladimir Kotal eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=` 2590cdf0c1d5Smjnelson fi 2591cdf0c1d5Smjnelson 2592cdf0c1d5Smjnelson # 2593cdf0c1d5Smjnelson # If we still don't have a parent, we must have been given a 2594cdf0c1d5Smjnelson # wx-style active list with no HG_PARENT specification, run 2595cdf0c1d5Smjnelson # hg-active and pull an HG_PARENT out of it, ignore the rest. 2596cdf0c1d5Smjnelson # 2597cdf0c1d5Smjnelson if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then 2598cdf0c1d5Smjnelson $HG_ACTIVE -w $codemgr_ws -p $real_parent | \ 2599b0088928SVladimir Kotal eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=` 2600cdf0c1d5Smjnelson elif [[ -z $HG_PARENT ]]; then 2601cdf0c1d5Smjnelson print -u2 "Error: Cannot discover parent revision" 2602cdf0c1d5Smjnelson exit 1 2603cdf0c1d5Smjnelson fi 2604cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then 2605cdf0c1d5Smjnelson 2606cdf0c1d5Smjnelson # 2607cdf0c1d5Smjnelson # We only will have a real parent workspace in the case one 2608cdf0c1d5Smjnelson # was specified (be it an older webrev, or another checkout). 2609cdf0c1d5Smjnelson # 2610cdf0c1d5Smjnelson [[ -n $codemgr_parent ]] && PWS=$codemgr_parent 2611cdf0c1d5Smjnelson 2612cdf0c1d5Smjnelson if [[ -z $flist_done && $flist_mode == "auto" ]]; then 2613cdf0c1d5Smjnelson flist_from_subversion $CWS $OLDPWD 2614cdf0c1d5Smjnelson fi 2615cdf0c1d5Smjnelsonelse 2616cdf0c1d5Smjnelson if [[ $SCM_MODE == "unknown" ]]; then 2617cdf0c1d5Smjnelson print -u2 " Unknown type of SCM in use" 2618cdf0c1d5Smjnelson else 2619cdf0c1d5Smjnelson print -u2 " Unsupported SCM in use: $SCM_MODE" 2620cdf0c1d5Smjnelson fi 2621cdf0c1d5Smjnelson 2622cdf0c1d5Smjnelson env_from_flist 2623cdf0c1d5Smjnelson 2624cdf0c1d5Smjnelson if [[ -z $CODEMGR_WS ]]; then 2625cdf0c1d5Smjnelson print -u2 "SCM not detected/supported and CODEMGR_WS not specified" 2626cdf0c1d5Smjnelson exit 1 2627cdf0c1d5Smjnelson fi 2628cdf0c1d5Smjnelson 2629cdf0c1d5Smjnelson if [[ -z $CODEMGR_PARENT ]]; then 2630cdf0c1d5Smjnelson print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified" 2631cdf0c1d5Smjnelson exit 1 2632cdf0c1d5Smjnelson fi 2633cdf0c1d5Smjnelson 2634cdf0c1d5Smjnelson CWS=$CODEMGR_WS 2635cdf0c1d5Smjnelson PWS=$CODEMGR_PARENT 2636daaffb31Sdpfi 2637daaffb31Sdp 2638daaffb31Sdp# 2639daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a 2640daaffb31Sdp# webrev-info file in the workspace directory. 2641daaffb31Sdp# 2642daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then 2643daaffb31Sdp iflag=1 2644daaffb31Sdp INCLUDE_FILE="$CWS/webrev-info" 2645daaffb31Sdpfi 2646daaffb31Sdp 2647daaffb31Sdpif [[ -n $iflag ]]; then 2648daaffb31Sdp if [[ ! -r $INCLUDE_FILE ]]; then 2649daaffb31Sdp print -u2 "include file '$INCLUDE_FILE' does not exist or is" \ 2650daaffb31Sdp "not readable." 2651daaffb31Sdp exit 1 2652daaffb31Sdp else 2653daaffb31Sdp # 2654daaffb31Sdp # $INCLUDE_FILE may be a relative path, and the script alters 2655daaffb31Sdp # PWD, so we just stash a copy in /tmp. 2656daaffb31Sdp # 2657daaffb31Sdp cp $INCLUDE_FILE /tmp/$$.include 2658daaffb31Sdp fi 2659daaffb31Sdpfi 2660daaffb31Sdp 26610fd2682eSMark J. Nelson# DO_EVERYTHING: break point 26620fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then 26630fd2682eSMark J. Nelson break 26640fd2682eSMark J. Nelsonfi 26650fd2682eSMark J. Nelson 26660fd2682eSMark J. Nelsontypeset -A itsinfo 26670fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed 26680fd2682eSMark J. Nelsonvalid_prefixes= 26690fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then 26700fd2682eSMark J. Nelson DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg" 26710fd2682eSMark J. Nelson if [[ -n $Iflag ]]; then 26720fd2682eSMark J. Nelson REGFILE=$ITSREG 26730fd2682eSMark J. Nelson elif [[ -r $HOME/.its.reg ]]; then 26740fd2682eSMark J. Nelson REGFILE=$HOME/.its.reg 26750fd2682eSMark J. Nelson else 26760fd2682eSMark J. Nelson REGFILE=$DEFREGFILE 26770fd2682eSMark J. Nelson fi 26780fd2682eSMark J. Nelson if [[ ! -r $REGFILE ]]; then 26790fd2682eSMark J. Nelson print "ERROR: Unable to read database registry file $REGFILE" 26800fd2682eSMark J. Nelson exit 1 26810fd2682eSMark J. Nelson elif [[ $REGFILE != $DEFREGFILE ]]; then 26820fd2682eSMark J. Nelson print " its.reg from: $REGFILE" 26830fd2682eSMark J. Nelson fi 26840fd2682eSMark J. Nelson 26850fd2682eSMark J. Nelson $SED -e '/^#/d' -e '/^[ ]*$/d' $REGFILE | while read LINE; do 26860fd2682eSMark J. Nelson 26870fd2682eSMark J. Nelson name=${LINE%%=*} 26880fd2682eSMark J. Nelson value="${LINE#*=}" 26890fd2682eSMark J. Nelson 26900fd2682eSMark J. Nelson if [[ $name == PREFIX ]]; then 26910fd2682eSMark J. Nelson p=${value} 26920fd2682eSMark J. Nelson valid_prefixes="${p} ${valid_prefixes}" 26930fd2682eSMark J. Nelson else 26940fd2682eSMark J. Nelson itsinfo["${p}_${name}"]="${value}" 26950fd2682eSMark J. Nelson fi 26960fd2682eSMark J. Nelson done 26970fd2682eSMark J. Nelson 26980fd2682eSMark J. Nelson 26990fd2682eSMark J. Nelson DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf" 27000fd2682eSMark J. Nelson CONFFILES=$DEFCONFFILE 27010fd2682eSMark J. Nelson if [[ -r $HOME/.its.conf ]]; then 27020fd2682eSMark J. Nelson CONFFILES="${CONFFILES} $HOME/.its.conf" 27030fd2682eSMark J. Nelson fi 27040fd2682eSMark J. Nelson if [[ -n $Cflag ]]; then 27050fd2682eSMark J. Nelson CONFFILES="${CONFFILES} ${ITSCONF}" 27060fd2682eSMark J. Nelson fi 27070fd2682eSMark J. Nelson its_domain= 27080fd2682eSMark J. Nelson its_priority= 27090fd2682eSMark J. Nelson for cf in ${CONFFILES}; do 27100fd2682eSMark J. Nelson if [[ ! -r $cf ]]; then 27110fd2682eSMark J. Nelson print "ERROR: Unable to read database configuration file $cf" 27120fd2682eSMark J. Nelson exit 1 27130fd2682eSMark J. Nelson elif [[ $cf != $DEFCONFFILE ]]; then 27140fd2682eSMark J. Nelson print " its.conf: reading $cf" 27150fd2682eSMark J. Nelson fi 27160fd2682eSMark J. Nelson $SED -e '/^#/d' -e '/^[ ]*$/d' $cf | while read LINE; do 27170fd2682eSMark J. Nelson eval "${LINE}" 27180fd2682eSMark J. Nelson done 27190fd2682eSMark J. Nelson done 27200fd2682eSMark J. Nelson 27210fd2682eSMark J. Nelson # 27220fd2682eSMark J. Nelson # If an information tracking system is explicitly identified by prefix, 27230fd2682eSMark J. Nelson # we want to disregard the specified priorities and resolve it accordingly. 27240fd2682eSMark J. Nelson # 27250fd2682eSMark J. Nelson # To that end, we'll build a sed script to do each valid prefix in turn. 27260fd2682eSMark J. Nelson # 27270fd2682eSMark J. Nelson for p in ${valid_prefixes}; do 27280fd2682eSMark J. Nelson # 27290fd2682eSMark J. Nelson # When an informational URL was provided, translate it to a 27300fd2682eSMark J. Nelson # hyperlink. When omitted, simply use the prefix text. 27310fd2682eSMark J. Nelson # 27320fd2682eSMark J. Nelson if [[ -z ${itsinfo["${p}_INFO"]} ]]; then 27330fd2682eSMark J. Nelson itsinfo["${p}_INFO"]=${p} 27340fd2682eSMark J. Nelson else 27350fd2682eSMark J. Nelson itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>" 27360fd2682eSMark J. Nelson fi 27370fd2682eSMark J. Nelson 27380fd2682eSMark J. Nelson # 27390fd2682eSMark J. Nelson # Assume that, for this invocation of webrev, all references 27400fd2682eSMark J. Nelson # to this information tracking system should resolve through 27410fd2682eSMark J. Nelson # the same URL. 27420fd2682eSMark J. Nelson # 27430fd2682eSMark J. Nelson # If the caller specified -O, then always use EXTERNAL_URL. 27440fd2682eSMark J. Nelson # 27450fd2682eSMark J. Nelson # Otherwise, look in the list of domains for a matching 27460fd2682eSMark J. Nelson # INTERNAL_URL. 27470fd2682eSMark J. Nelson # 27480fd2682eSMark J. Nelson [[ -z $Oflag ]] && for d in ${its_domain}; do 27490fd2682eSMark J. Nelson if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then 27500fd2682eSMark J. Nelson itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}" 27510fd2682eSMark J. Nelson break 27520fd2682eSMark J. Nelson fi 27530fd2682eSMark J. Nelson done 27540fd2682eSMark J. Nelson if [[ -z ${itsinfo["${p}_URL"]} ]]; then 27550fd2682eSMark J. Nelson itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}" 27560fd2682eSMark J. Nelson fi 27570fd2682eSMark J. Nelson 27580fd2682eSMark J. Nelson # 27590fd2682eSMark J. Nelson # Turn the destination URL into a hyperlink 27600fd2682eSMark J. Nelson # 27610fd2682eSMark J. Nelson itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>" 27620fd2682eSMark J. Nelson 27630fd2682eSMark J. Nelson print "/^${p}[ ]/ { 27640fd2682eSMark J. Nelson s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g 27650fd2682eSMark J. Nelson s;^${p};${itsinfo[${p}_INFO]}; 27660fd2682eSMark J. Nelson }" >> ${its_sed_script} 27670fd2682eSMark J. Nelson done 27680fd2682eSMark J. Nelson 27690fd2682eSMark J. Nelson # 27700fd2682eSMark J. Nelson # The previous loop took care of explicit specification. Now use 27710fd2682eSMark J. Nelson # the configured priorities to attempt implicit translations. 27720fd2682eSMark J. Nelson # 27730fd2682eSMark J. Nelson for p in ${its_priority}; do 27740fd2682eSMark J. Nelson print "/^${itsinfo[${p}_REGEX]}[ ]/ { 27750fd2682eSMark J. Nelson s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g 27760fd2682eSMark J. Nelson }" >> ${its_sed_script} 27770fd2682eSMark J. Nelson done 27780fd2682eSMark J. Nelsonfi 27790fd2682eSMark J. Nelson 27800fd2682eSMark J. Nelson# 27810fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement 27820fd2682eSMark J. Nelson# and explanation of this terminator. 27830fd2682eSMark J. Nelson# 27840fd2682eSMark J. Nelsondone 27850fd2682eSMark J. Nelson 2786daaffb31Sdp# 2787daaffb31Sdp# Output directory. 2788daaffb31Sdp# 2789daaffb31SdpWDIR=${WDIR:-$CWS/webrev} 2790daaffb31Sdp 2791daaffb31Sdp# 279202d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory; 279302d26c39SVladimir Kotal# in the future this could potentially be an option. 2794daaffb31Sdp# 279502d26c39SVladimir Kotalif [[ -n $oflag ]]; then 279602d26c39SVladimir Kotal WNAME=${WDIR##*/} 279702d26c39SVladimir Kotalelse 2798daaffb31Sdp WNAME=${CWS##*/} 279902d26c39SVladimir Kotalfi 280002d26c39SVladimir Kotal 2801ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete. 2802ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then 2803b0088928SVladimir Kotal # 2804ba44d8a2SVladimir Kotal # If remote target is not specified, build it from scratch using 2805ba44d8a2SVladimir Kotal # the default values. 2806b0088928SVladimir Kotal # 2807ba44d8a2SVladimir Kotal if [[ -z $tflag ]]; then 2808ba44d8a2SVladimir Kotal remote_target=${DEFAULT_REMOTE_HOST}:${WNAME} 2809ba44d8a2SVladimir Kotal else 2810b0088928SVladimir Kotal # 2811b0088928SVladimir Kotal # Check upload target prefix first. 2812b0088928SVladimir Kotal # 2813b0088928SVladimir Kotal if [[ "${remote_target}" != ${rsync_prefix}* && 2814b0088928SVladimir Kotal "${remote_target}" != ${ssh_prefix}* ]]; then 2815b0088928SVladimir Kotal print "ERROR: invalid prefix of upload URI" \ 2816b0088928SVladimir Kotal "($remote_target)" 2817b0088928SVladimir Kotal exit 1 2818b0088928SVladimir Kotal fi 2819b0088928SVladimir Kotal # 2820ba44d8a2SVladimir Kotal # If destination specification is not in the form of 2821ba44d8a2SVladimir Kotal # host_spec:remote_dir then assume it is just remote hostname 2822ba44d8a2SVladimir Kotal # and append a colon and destination directory formed from 2823ba44d8a2SVladimir Kotal # local webrev directory name. 2824b0088928SVladimir Kotal # 2825b0088928SVladimir Kotal typeset target_no_prefix=${remote_target##*://} 2826b0088928SVladimir Kotal if [[ ${target_no_prefix} == *:* ]]; then 2827ba44d8a2SVladimir Kotal if [[ "${remote_target}" == *: ]]; then 2828b0088928SVladimir Kotal remote_target=${remote_target}${WNAME} 2829ba44d8a2SVladimir Kotal fi 2830b0088928SVladimir Kotal else 2831b0088928SVladimir Kotal if [[ ${target_no_prefix} == */* ]]; then 2832b0088928SVladimir Kotal print "ERROR: badly formed upload URI" \ 2833b0088928SVladimir Kotal "($remote_target)" 2834b0088928SVladimir Kotal exit 1 2835b0088928SVladimir Kotal else 2836b0088928SVladimir Kotal remote_target=${remote_target}:${WNAME} 2837ba44d8a2SVladimir Kotal fi 2838ba44d8a2SVladimir Kotal fi 2839ba44d8a2SVladimir Kotal fi 2840ba44d8a2SVladimir Kotal 2841b0088928SVladimir Kotal # 2842b0088928SVladimir Kotal # Strip trailing slash. Each upload method will deal with directory 2843b0088928SVladimir Kotal # specification separately. 2844b0088928SVladimir Kotal # 2845b0088928SVladimir Kotal remote_target=${remote_target%/} 2846b0088928SVladimir Kotalfi 2847b0088928SVladimir Kotal 2848b0088928SVladimir Kotal# 2849ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation. 2850b0088928SVladimir Kotal# 2851ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then 2852b0088928SVladimir Kotal delete_webrev 1 1 2853ba44d8a2SVladimir Kotal exit $? 2854ba44d8a2SVladimir Kotalfi 2855ba44d8a2SVladimir Kotal 2856b0088928SVladimir Kotal# 2857ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it. 2858b0088928SVladimir Kotal# 2859ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then 2860ba44d8a2SVladimir Kotal if [[ -n $Dflag ]]; then 2861b0088928SVladimir Kotal delete_webrev 1 1 2862ba44d8a2SVladimir Kotal (( $? == 0 )) || exit $? 2863ba44d8a2SVladimir Kotal fi 2864ba44d8a2SVladimir Kotal if [[ -n $Uflag ]]; then 286502d26c39SVladimir Kotal upload_webrev 286602d26c39SVladimir Kotal exit $? 286702d26c39SVladimir Kotal fi 2868ba44d8a2SVladimir Kotalfi 2869daaffb31Sdp 2870e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then 28717c478bd9Sstevel@tonic-gate WDIR=$PWD/$WDIR 28727c478bd9Sstevel@tonic-gatefi 2873daaffb31Sdp 2874daaffb31Sdpif [[ ! -d $WDIR ]]; then 2875daaffb31Sdp mkdir -p $WDIR 2876ba44d8a2SVladimir Kotal (( $? != 0 )) && exit 1 28777c478bd9Sstevel@tonic-gatefi 28787c478bd9Sstevel@tonic-gate 2879daaffb31Sdp# 2880daaffb31Sdp# Summarize what we're going to do. 2881daaffb31Sdp# 2882cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then 2883cdf0c1d5Smjnelson print " Workspace: $CWS (at $CWS_REV)" 2884cdf0c1d5Smjnelsonelse 2885daaffb31Sdp print " Workspace: $CWS" 2886cdf0c1d5Smjnelsonfi 2887daaffb31Sdpif [[ -n $parent_webrev ]]; then 2888daaffb31Sdp print "Compare against: webrev at $parent_webrev" 2889daaffb31Sdpelse 2890cdf0c1d5Smjnelson if [[ -n $HG_PARENT ]]; then 2891cdf0c1d5Smjnelson hg_parent_short=`echo $HG_PARENT \ 2892b0088928SVladimir Kotal | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'` 2893cdf0c1d5Smjnelson print "Compare against: $PWS (at $hg_parent_short)" 2894cdf0c1d5Smjnelson else 2895daaffb31Sdp print "Compare against: $PWS" 2896daaffb31Sdp fi 2897cdf0c1d5Smjnelsonfi 2898daaffb31Sdp 2899daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE" 2900daaffb31Sdpprint " Output to: $WDIR" 2901daaffb31Sdp 2902daaffb31Sdp# 29037c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir 2904daaffb31Sdp# 2905daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list 29067c478bd9Sstevel@tonic-gate 2907daaffb31Sdprm -f $WDIR/$WNAME.patch 2908daaffb31Sdprm -f $WDIR/$WNAME.ps 2909daaffb31Sdprm -f $WDIR/$WNAME.pdf 29107c478bd9Sstevel@tonic-gate 2911daaffb31Sdptouch $WDIR/$WNAME.patch 29127c478bd9Sstevel@tonic-gate 2913daaffb31Sdpprint " Output Files:" 2914daaffb31Sdp 2915daaffb31Sdp# 2916daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables. 2917daaffb31Sdp# 2918b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean 2919daaffb31SdpFLIST=/tmp/$$.flist.clean 2920daaffb31Sdp 2921daaffb31Sdp# 2922cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries. 2923cdf0c1d5Smjnelson# 2924cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then 2925cdf0c1d5Smjnelson # 2926cdf0c1d5Smjnelson # Transform the FLIST into a temporary sed script that matches 2927cdf0c1d5Smjnelson # relevant entries in the Mercurial manifest as follows: 2928cdf0c1d5Smjnelson # 1) The script will be used against the parent revision manifest, 2929cdf0c1d5Smjnelson # so for FLIST lines that have two filenames (a renamed file) 2930cdf0c1d5Smjnelson # keep only the old name. 2931cdf0c1d5Smjnelson # 2) Escape all forward slashes the filename. 2932cdf0c1d5Smjnelson # 3) Change the filename into another sed command that matches 2933cdf0c1d5Smjnelson # that file in "hg manifest -v" output: start of line, three 2934cdf0c1d5Smjnelson # octal digits for file permissions, space, a file type flag 2935cdf0c1d5Smjnelson # character, space, the filename, end of line. 2936*e6ccc173SEdward Pilatowicz # 4) Eliminate any duplicate entries. (This can occur if a 2937*e6ccc173SEdward Pilatowicz # file has been used as the source of an hg cp and it's 2938*e6ccc173SEdward Pilatowicz # also been modified in the same changeset.) 2939cdf0c1d5Smjnelson # 2940cdf0c1d5Smjnelson SEDFILE=/tmp/$$.manifest.sed 2941b0088928SVladimir Kotal $SED ' 2942cdf0c1d5Smjnelson s#^[^ ]* ## 2943cdf0c1d5Smjnelson s#/#\\\/#g 2944cdf0c1d5Smjnelson s#^.*$#/^... . &$/p# 2945*e6ccc173SEdward Pilatowicz ' < $FLIST | $SORT -u > $SEDFILE 2946cdf0c1d5Smjnelson 2947cdf0c1d5Smjnelson # 2948cdf0c1d5Smjnelson # Apply the generated script to the output of "hg manifest -v" 2949cdf0c1d5Smjnelson # to get the relevant subset for this webrev. 2950cdf0c1d5Smjnelson # 2951cdf0c1d5Smjnelson HG_PARENT_MANIFEST=/tmp/$$.manifest 2952cdf0c1d5Smjnelson hg -R $CWS manifest -v -r $HG_PARENT | 2953b0088928SVladimir Kotal $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST 2954cdf0c1d5Smjnelsonfi 2955cdf0c1d5Smjnelson 2956cdf0c1d5Smjnelson# 2957daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files. 2958daaffb31Sdp# 2959daaffb31Sdpcat $FLIST | while read LINE 29607c478bd9Sstevel@tonic-gatedo 29617c478bd9Sstevel@tonic-gate set - $LINE 29627c478bd9Sstevel@tonic-gate P=$1 29637c478bd9Sstevel@tonic-gate 2964daaffb31Sdp # 2965daaffb31Sdp # Normally, each line in the file list is just a pathname of a 2966daaffb31Sdp # file that has been modified or created in the child. A file 2967daaffb31Sdp # that is renamed in the child workspace has two names on the 2968daaffb31Sdp # line: new name followed by the old name. 2969daaffb31Sdp # 2970daaffb31Sdp oldname="" 2971daaffb31Sdp oldpath="" 2972daaffb31Sdp rename= 2973daaffb31Sdp if [[ $# -eq 2 ]]; then 29747c478bd9Sstevel@tonic-gate PP=$2 # old filename 2975*e6ccc173SEdward Pilatowicz if [[ -f $PP ]]; then 2976*e6ccc173SEdward Pilatowicz oldname=" (copied from $PP)" 2977*e6ccc173SEdward Pilatowicz else 2978*e6ccc173SEdward Pilatowicz oldname=" (renamed from $PP)" 2979*e6ccc173SEdward Pilatowicz fi 2980daaffb31Sdp oldpath="$PP" 2981daaffb31Sdp rename=1 29827c478bd9Sstevel@tonic-gate PDIR=${PP%/*} 2983daaffb31Sdp if [[ $PDIR == $PP ]]; then 29847c478bd9Sstevel@tonic-gate PDIR="." # File at root of workspace 29857c478bd9Sstevel@tonic-gate fi 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate PF=${PP##*/} 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate DIR=${P%/*} 2990daaffb31Sdp if [[ $DIR == $P ]]; then 29917c478bd9Sstevel@tonic-gate DIR="." # File at root of workspace 29927c478bd9Sstevel@tonic-gate fi 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate F=${P##*/} 2995daaffb31Sdp 29967c478bd9Sstevel@tonic-gate else 29977c478bd9Sstevel@tonic-gate DIR=${P%/*} 2998daaffb31Sdp if [[ "$DIR" == "$P" ]]; then 29997c478bd9Sstevel@tonic-gate DIR="." # File at root of workspace 30007c478bd9Sstevel@tonic-gate fi 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate F=${P##*/} 30037c478bd9Sstevel@tonic-gate 30047c478bd9Sstevel@tonic-gate PP=$P 30057c478bd9Sstevel@tonic-gate PDIR=$DIR 30067c478bd9Sstevel@tonic-gate PF=$F 30077c478bd9Sstevel@tonic-gate fi 30087c478bd9Sstevel@tonic-gate 3009daaffb31Sdp COMM=`getcomments html $P $PP` 30107c478bd9Sstevel@tonic-gate 3011daaffb31Sdp print "\t$P$oldname\n\t\t\c" 30127c478bd9Sstevel@tonic-gate 30137c478bd9Sstevel@tonic-gate # Make the webrev mirror directory if necessary 30147c478bd9Sstevel@tonic-gate mkdir -p $WDIR/$DIR 30157c478bd9Sstevel@tonic-gate 3016daaffb31Sdp # 3017daaffb31Sdp # If we're in OpenSolaris mode, we enforce a minor policy: 3018daaffb31Sdp # help to make sure the reviewer doesn't accidentally publish 3019e0e0293aSjmcp # source which is in usr/closed/* or deleted_files/usr/closed/* 3020daaffb31Sdp # 3021e0e0293aSjmcp if [[ -n "$Oflag" ]]; then 3022daaffb31Sdp pclosed=${P##usr/closed/} 3023e0e0293aSjmcp pdeleted=${P##deleted_files/usr/closed/} 3024e0e0293aSjmcp if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then 3025daaffb31Sdp print "*** Omitting closed source for OpenSolaris" \ 3026daaffb31Sdp "mode review" 3027daaffb31Sdp continue 3028daaffb31Sdp fi 3029daaffb31Sdp fi 3030daaffb31Sdp 3031daaffb31Sdp # 3032cdf0c1d5Smjnelson # We stash old and new files into parallel directories in $WDIR 3033daaffb31Sdp # and do our diffs there. This makes it possible to generate 3034daaffb31Sdp # clean looking diffs which don't have absolute paths present. 3035daaffb31Sdp # 3036daaffb31Sdp 3037cdf0c1d5Smjnelson build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \ 30387c478bd9Sstevel@tonic-gate continue 30397c478bd9Sstevel@tonic-gate 3040cdf0c1d5Smjnelson # 3041cdf0c1d5Smjnelson # Keep the old PWD around, so we can safely switch back after 3042cdf0c1d5Smjnelson # diff generation, such that build_old_new runs in a 3043cdf0c1d5Smjnelson # consistent environment. 3044cdf0c1d5Smjnelson # 3045cdf0c1d5Smjnelson OWD=$PWD 3046daaffb31Sdp cd $WDIR/raw_files 3047daaffb31Sdp ofile=old/$PDIR/$PF 3048daaffb31Sdp nfile=new/$DIR/$F 30497c478bd9Sstevel@tonic-gate 3050daaffb31Sdp mv_but_nodiff= 3051daaffb31Sdp cmp $ofile $nfile > /dev/null 2>&1 3052daaffb31Sdp if [[ $? == 0 && $rename == 1 ]]; then 3053daaffb31Sdp mv_but_nodiff=1 3054daaffb31Sdp fi 3055daaffb31Sdp 3056daaffb31Sdp # 3057daaffb31Sdp # If we have old and new versions of the file then run the appropriate 3058daaffb31Sdp # diffs. This is complicated by a couple of factors: 3059daaffb31Sdp # 3060daaffb31Sdp # - renames must be handled specially: we emit a 'remove' 3061daaffb31Sdp # diff and an 'add' diff 3062daaffb31Sdp # - new files and deleted files must be handled specially 3063daaffb31Sdp # - Solaris patch(1m) can't cope with file creation 3064daaffb31Sdp # (and hence renames) as of this writing. 3065daaffb31Sdp # - To make matters worse, gnu patch doesn't interpret the 3066daaffb31Sdp # output of Solaris diff properly when it comes to 3067daaffb31Sdp # adds and deletes. We need to do some "cleansing" 3068daaffb31Sdp # transformations: 3069daaffb31Sdp # [to add a file] @@ -1,0 +X,Y @@ --> @@ -0,0 +X,Y @@ 3070daaffb31Sdp # [to del a file] @@ -X,Y +1,0 @@ --> @@ -X,Y +0,0 @@ 3071daaffb31Sdp # 3072b0088928SVladimir Kotal cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'" 3073b0088928SVladimir Kotal cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'" 3074daaffb31Sdp 3075daaffb31Sdp rm -f $WDIR/$DIR/$F.patch 3076daaffb31Sdp if [[ -z $rename ]]; then 3077e0e0293aSjmcp if [ ! -f "$ofile" ]; then 3078daaffb31Sdp diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ 3079daaffb31Sdp > $WDIR/$DIR/$F.patch 3080e0e0293aSjmcp elif [ ! -f "$nfile" ]; then 3081daaffb31Sdp diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ 3082daaffb31Sdp > $WDIR/$DIR/$F.patch 3083daaffb31Sdp else 3084daaffb31Sdp diff -u $ofile $nfile > $WDIR/$DIR/$F.patch 3085daaffb31Sdp fi 3086daaffb31Sdp else 3087daaffb31Sdp diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \ 3088daaffb31Sdp > $WDIR/$DIR/$F.patch 3089daaffb31Sdp 3090daaffb31Sdp diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \ 3091daaffb31Sdp >> $WDIR/$DIR/$F.patch 3092daaffb31Sdp fi 3093daaffb31Sdp 3094daaffb31Sdp # 3095daaffb31Sdp # Tack the patch we just made onto the accumulated patch for the 3096daaffb31Sdp # whole wad. 3097daaffb31Sdp # 3098daaffb31Sdp cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch 3099daaffb31Sdp 3100daaffb31Sdp print " patch\c" 3101daaffb31Sdp 3102daaffb31Sdp if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then 3103daaffb31Sdp 3104daaffb31Sdp ${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff 3105daaffb31Sdp diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \ 3106daaffb31Sdp > $WDIR/$DIR/$F.cdiff.html 31077c478bd9Sstevel@tonic-gate print " cdiffs\c" 31087c478bd9Sstevel@tonic-gate 3109daaffb31Sdp ${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff 3110daaffb31Sdp diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \ 3111daaffb31Sdp > $WDIR/$DIR/$F.udiff.html 3112daaffb31Sdp 31137c478bd9Sstevel@tonic-gate print " udiffs\c" 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate if [[ -x $WDIFF ]]; then 3116daaffb31Sdp $WDIFF -c "$COMM" \ 3117daaffb31Sdp -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \ 3118daaffb31Sdp $WDIR/$DIR/$F.wdiff.html 2>/dev/null 3119daaffb31Sdp if [[ $? -eq 0 ]]; then 31207c478bd9Sstevel@tonic-gate print " wdiffs\c" 3121daaffb31Sdp else 3122daaffb31Sdp print " wdiffs[fail]\c" 3123daaffb31Sdp fi 31247c478bd9Sstevel@tonic-gate fi 31257c478bd9Sstevel@tonic-gate 3126daaffb31Sdp sdiff_to_html $ofile $nfile $F $DIR "$COMM" \ 3127daaffb31Sdp > $WDIR/$DIR/$F.sdiff.html 31287c478bd9Sstevel@tonic-gate print " sdiffs\c" 31297c478bd9Sstevel@tonic-gate 31307c478bd9Sstevel@tonic-gate print " frames\c" 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff 31337c478bd9Sstevel@tonic-gate 3134daaffb31Sdp difflines $ofile $nfile > $WDIR/$DIR/$F.count 3135daaffb31Sdp 3136daaffb31Sdp elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then 3137daaffb31Sdp # renamed file: may also have differences 3138daaffb31Sdp difflines $ofile $nfile > $WDIR/$DIR/$F.count 3139daaffb31Sdp elif [[ -f $nfile ]]; then 31407c478bd9Sstevel@tonic-gate # new file: count added lines 3141daaffb31Sdp difflines /dev/null $nfile > $WDIR/$DIR/$F.count 3142daaffb31Sdp elif [[ -f $ofile ]]; then 31437c478bd9Sstevel@tonic-gate # old file: count deleted lines 3144daaffb31Sdp difflines $ofile /dev/null > $WDIR/$DIR/$F.count 31457c478bd9Sstevel@tonic-gate fi 31467c478bd9Sstevel@tonic-gate 3147daaffb31Sdp # 3148daaffb31Sdp # Now we generate the postscript for this file. We generate diffs 3149daaffb31Sdp # only in the event that there is delta, or the file is new (it seems 3150daaffb31Sdp # tree-killing to print out the contents of deleted files). 3151daaffb31Sdp # 3152daaffb31Sdp if [[ -f $nfile ]]; then 3153daaffb31Sdp ocr=$ofile 3154daaffb31Sdp [[ ! -f $ofile ]] && ocr=/dev/null 3155daaffb31Sdp 3156daaffb31Sdp if [[ -z $mv_but_nodiff ]]; then 3157daaffb31Sdp textcomm=`getcomments text $P $PP` 315814983201Sdp if [[ -x $CODEREVIEW ]]; then 315914983201Sdp $CODEREVIEW -y "$textcomm" \ 316014983201Sdp -e $ocr $nfile \ 316114983201Sdp > /tmp/$$.psfile 2>/dev/null && 316214983201Sdp cat /tmp/$$.psfile >> $WDIR/$WNAME.ps 3163daaffb31Sdp if [[ $? -eq 0 ]]; then 3164daaffb31Sdp print " ps\c" 3165daaffb31Sdp else 3166daaffb31Sdp print " ps[fail]\c" 3167daaffb31Sdp fi 3168daaffb31Sdp fi 3169daaffb31Sdp fi 317014983201Sdp fi 3171daaffb31Sdp 3172cdf0c1d5Smjnelson if [[ -f $ofile ]]; then 3173cdf0c1d5Smjnelson source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html 31747c478bd9Sstevel@tonic-gate print " old\c" 31757c478bd9Sstevel@tonic-gate fi 31767c478bd9Sstevel@tonic-gate 3177daaffb31Sdp if [[ -f $nfile ]]; then 3178daaffb31Sdp source_to_html New $P < $nfile > $WDIR/$DIR/$F.html 31797c478bd9Sstevel@tonic-gate print " new\c" 31807c478bd9Sstevel@tonic-gate fi 31817c478bd9Sstevel@tonic-gate 3182cdf0c1d5Smjnelson cd $OWD 3183cdf0c1d5Smjnelson 3184daaffb31Sdp print 31857c478bd9Sstevel@tonic-gatedone 31867c478bd9Sstevel@tonic-gate 3187daaffb31Sdpframe_nav_js > $WDIR/ancnav.js 31887c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html 3189daaffb31Sdp 319014983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then 319114983201Sdp print " Generating PDF: Skipped: no output available" 319214983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then 319314983201Sdp print " Generating PDF: \c" 319414983201Sdp fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf 3195daaffb31Sdp print "Done." 319614983201Sdpelse 319714983201Sdp print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'" 319814983201Sdpfi 31997c478bd9Sstevel@tonic-gate 3200e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR, 3201e0e0293aSjmcp# delete it - prevent accidental publishing of closed source 3202e0e0293aSjmcp 3203e0e0293aSjmcpif [[ -n "$Oflag" ]]; then 3204ba44d8a2SVladimir Kotal $FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \; 3205e0e0293aSjmcpfi 3206e0e0293aSjmcp 32077c478bd9Sstevel@tonic-gate# Now build the index.html file that contains 32087c478bd9Sstevel@tonic-gate# links to the source files and their diffs. 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gatecd $CWS 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection. 3213daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines 32147c478bd9Sstevel@tonic-gate 3215daaffb31Sdpprint " index.html: \c" 32167c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html 32177c478bd9Sstevel@tonic-gateexec 3<&1 # duplicate stdout to FD3. 32187c478bd9Sstevel@tonic-gateexec 1<&- # Close stdout. 32197c478bd9Sstevel@tonic-gateexec > $INDEXFILE # Open stdout to index file. 32207c478bd9Sstevel@tonic-gate 3221daaffb31Sdpprint "$HTML<head>$STDHEAD" 3222daaffb31Sdpprint "<title>$WNAME</title>" 3223daaffb31Sdpprint "</head>" 3224daaffb31Sdpprint "<body id=\"SUNWwebrev\">" 3225daaffb31Sdpprint "<div class=\"summary\">" 3226daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>" 32277c478bd9Sstevel@tonic-gate 3228daaffb31Sdpprint "<table>" 32297c478bd9Sstevel@tonic-gate 3230daaffb31Sdp# 3231cdf0c1d5Smjnelson# Get the preparer's name: 3232daaffb31Sdp# 3233cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property 3234cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape 3235cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address. 3236cdf0c1d5Smjnelson# 3237cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but 3238cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions. 3239cdf0c1d5Smjnelson# 3240cdf0c1d5Smjnelsonpreparer= 3241cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then 3242cdf0c1d5Smjnelson preparer=`hg showconfig ui.username 2>/dev/null` 3243cdf0c1d5Smjnelson if [[ -n "$preparer" ]]; then 3244cdf0c1d5Smjnelson preparer="$(echo "$preparer" | html_quote)" 3245cdf0c1d5Smjnelson fi 3246cdf0c1d5Smjnelsonfi 3247cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then 3248cdf0c1d5Smjnelson preparer=$( 3249cdf0c1d5Smjnelson $PERL -e ' 3250cdf0c1d5Smjnelson ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<); 3251cdf0c1d5Smjnelson if ($login) { 3252cdf0c1d5Smjnelson $gcos =~ s/\&/ucfirst($login)/e; 3253cdf0c1d5Smjnelson printf "%s (%s)\n", $gcos, $login; 3254cdf0c1d5Smjnelson } else { 3255cdf0c1d5Smjnelson printf "(unknown)\n"; 3256cdf0c1d5Smjnelson } 3257cdf0c1d5Smjnelson ') 3258daaffb31Sdpfi 3259daaffb31Sdp 326048bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z) 326148bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>" 3262cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS" 3263cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then 3264cdf0c1d5Smjnelson print "(at $CWS_REV)" 3265cdf0c1d5Smjnelsonfi 3266cdf0c1d5Smjnelsonprint "</td></tr>" 3267daaffb31Sdpprint "<tr><th>Compare against:</th><td>" 3268daaffb31Sdpif [[ -n $parent_webrev ]]; then 3269daaffb31Sdp print "webrev at $parent_webrev" 3270daaffb31Sdpelse 3271daaffb31Sdp print "$PWS" 3272cdf0c1d5Smjnelson if [[ -n $hg_parent_short ]]; then 3273cdf0c1d5Smjnelson print "(at $hg_parent_short)" 3274cdf0c1d5Smjnelson fi 3275daaffb31Sdpfi 3276daaffb31Sdpprint "</td></tr>" 3277daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>" 3278daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC 3279daaffb31Sdpprint "</td></tr>" 3280daaffb31Sdp 3281daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then 3282371d72daSLubomir Sedlacik wpatch_url="$(print $WNAME.patch | url_encode)" 3283daaffb31Sdp print "<tr><th>Patch of changes:</th><td>" 3284371d72daSLubomir Sedlacik print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>" 3285daaffb31Sdpfi 3286daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then 3287371d72daSLubomir Sedlacik wpdf_url="$(print $WNAME.pdf | url_encode)" 3288daaffb31Sdp print "<tr><th>Printable review:</th><td>" 3289371d72daSLubomir Sedlacik print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>" 3290daaffb31Sdpfi 3291daaffb31Sdp 3292daaffb31Sdpif [[ -n "$iflag" ]]; then 3293daaffb31Sdp print "<tr><th>Author comments:</th><td><div>" 3294daaffb31Sdp cat /tmp/$$.include 3295daaffb31Sdp print "</div></td></tr>" 3296daaffb31Sdpfi 3297daaffb31Sdpprint "</table>" 3298daaffb31Sdpprint "</div>" 3299daaffb31Sdp 3300daaffb31Sdp# 3301daaffb31Sdp# Second pass through the files: generate the rest of the index file 3302daaffb31Sdp# 3303daaffb31Sdpcat $FLIST | while read LINE 33047c478bd9Sstevel@tonic-gatedo 33057c478bd9Sstevel@tonic-gate set - $LINE 33067c478bd9Sstevel@tonic-gate P=$1 33077c478bd9Sstevel@tonic-gate 3308daaffb31Sdp if [[ $# == 2 ]]; then 33097c478bd9Sstevel@tonic-gate PP=$2 3310cdf0c1d5Smjnelson oldname="$PP" 33117c478bd9Sstevel@tonic-gate else 33127c478bd9Sstevel@tonic-gate PP=$P 3313daaffb31Sdp oldname="" 3314daaffb31Sdp fi 3315daaffb31Sdp 3316cdf0c1d5Smjnelson mv_but_nodiff= 3317cdf0c1d5Smjnelson cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1 3318cdf0c1d5Smjnelson if [[ $? == 0 && -n "$oldname" ]]; then 3319cdf0c1d5Smjnelson mv_but_nodiff=1 3320cdf0c1d5Smjnelson fi 3321cdf0c1d5Smjnelson 3322daaffb31Sdp DIR=${P%/*} 3323daaffb31Sdp if [[ $DIR == $P ]]; then 3324daaffb31Sdp DIR="." # File at root of workspace 33257c478bd9Sstevel@tonic-gate fi 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate # Avoid processing the same file twice. 33287c478bd9Sstevel@tonic-gate # It's possible for renamed files to 33297c478bd9Sstevel@tonic-gate # appear twice in the file list 33307c478bd9Sstevel@tonic-gate 33317c478bd9Sstevel@tonic-gate F=$WDIR/$P 33327c478bd9Sstevel@tonic-gate 3333daaffb31Sdp print "<p>" 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate # If there's a diffs file, make diffs links 33367c478bd9Sstevel@tonic-gate 3337daaffb31Sdp if [[ -f $F.cdiff.html ]]; then 3338371d72daSLubomir Sedlacik cdiff_url="$(print $P.cdiff.html | url_encode)" 3339371d72daSLubomir Sedlacik udiff_url="$(print $P.udiff.html | url_encode)" 3340371d72daSLubomir Sedlacik print "<a href=\"$cdiff_url\">Cdiffs</a>" 3341371d72daSLubomir Sedlacik print "<a href=\"$udiff_url\">Udiffs</a>" 33427c478bd9Sstevel@tonic-gate 3343daaffb31Sdp if [[ -f $F.wdiff.html && -x $WDIFF ]]; then 3344371d72daSLubomir Sedlacik wdiff_url="$(print $P.wdiff.html | url_encode)" 3345371d72daSLubomir Sedlacik print "<a href=\"$wdiff_url\">Wdiffs</a>" 33467c478bd9Sstevel@tonic-gate fi 33477c478bd9Sstevel@tonic-gate 3348371d72daSLubomir Sedlacik sdiff_url="$(print $P.sdiff.html | url_encode)" 3349371d72daSLubomir Sedlacik print "<a href=\"$sdiff_url\">Sdiffs</a>" 33507c478bd9Sstevel@tonic-gate 3351371d72daSLubomir Sedlacik frames_url="$(print $P.frames.html | url_encode)" 3352371d72daSLubomir Sedlacik print "<a href=\"$frames_url\">Frames</a>" 33537c478bd9Sstevel@tonic-gate else 3354daaffb31Sdp print " ------ ------ ------" 33557c478bd9Sstevel@tonic-gate 3356daaffb31Sdp if [[ -x $WDIFF ]]; then 33577c478bd9Sstevel@tonic-gate print " ------" 33587c478bd9Sstevel@tonic-gate fi 3359daaffb31Sdp 3360daaffb31Sdp print " ------" 33617c478bd9Sstevel@tonic-gate fi 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate # If there's an old file, make the link 33647c478bd9Sstevel@tonic-gate 3365daaffb31Sdp if [[ -f $F-.html ]]; then 3366371d72daSLubomir Sedlacik oldfile_url="$(print $P-.html | url_encode)" 3367371d72daSLubomir Sedlacik print "<a href=\"$oldfile_url\">Old</a>" 33687c478bd9Sstevel@tonic-gate else 3369daaffb31Sdp print " ---" 33707c478bd9Sstevel@tonic-gate fi 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate # If there's an new file, make the link 33737c478bd9Sstevel@tonic-gate 3374daaffb31Sdp if [[ -f $F.html ]]; then 3375371d72daSLubomir Sedlacik newfile_url="$(print $P.html | url_encode)" 3376371d72daSLubomir Sedlacik print "<a href=\"$newfile_url\">New</a>" 33777c478bd9Sstevel@tonic-gate else 3378daaffb31Sdp print " ---" 33797c478bd9Sstevel@tonic-gate fi 33807c478bd9Sstevel@tonic-gate 3381daaffb31Sdp if [[ -f $F.patch ]]; then 3382371d72daSLubomir Sedlacik patch_url="$(print $P.patch | url_encode)" 3383371d72daSLubomir Sedlacik print "<a href=\"$patch_url\">Patch</a>" 3384daaffb31Sdp else 3385daaffb31Sdp print " -----" 3386daaffb31Sdp fi 3387daaffb31Sdp 3388daaffb31Sdp if [[ -f $WDIR/raw_files/new/$P ]]; then 3389371d72daSLubomir Sedlacik rawfiles_url="$(print raw_files/new/$P | url_encode)" 3390371d72daSLubomir Sedlacik print "<a href=\"$rawfiles_url\">Raw</a>" 3391daaffb31Sdp else 3392daaffb31Sdp print " ---" 3393daaffb31Sdp fi 3394daaffb31Sdp 3395cdf0c1d5Smjnelson print "<b>$P</b>" 3396cdf0c1d5Smjnelson 3397cdf0c1d5Smjnelson # For renamed files, clearly state whether or not they are modified 3398*e6ccc173SEdward Pilatowicz if [[ -f "$oldname" ]]; then 3399cdf0c1d5Smjnelson if [[ -n "$mv_but_nodiff" ]]; then 3400*e6ccc173SEdward Pilatowicz print "<i>(copied from $oldname)</i>" 3401cdf0c1d5Smjnelson else 3402*e6ccc173SEdward Pilatowicz print "<i>(copied and modified from $oldname)</i>" 3403*e6ccc173SEdward Pilatowicz fi 3404*e6ccc173SEdward Pilatowicz elif [[ -n "$oldname" ]]; then 3405*e6ccc173SEdward Pilatowicz if [[ -n "$mv_but_nodiff" ]]; then 3406*e6ccc173SEdward Pilatowicz print "<i>(renamed from $oldname)</i>" 3407*e6ccc173SEdward Pilatowicz else 3408*e6ccc173SEdward Pilatowicz print "<i>(renamed and modified from $oldname)</i>" 3409cdf0c1d5Smjnelson fi 3410cdf0c1d5Smjnelson fi 3411cdf0c1d5Smjnelson 3412cdf0c1d5Smjnelson # If there's an old file, but no new file, the file was deleted 3413cdf0c1d5Smjnelson if [[ -f $F-.html && ! -f $F.html ]]; then 3414cdf0c1d5Smjnelson print " <i>(deleted)</i>" 3415cdf0c1d5Smjnelson fi 3416daaffb31Sdp 3417daaffb31Sdp # 3418e0e0293aSjmcp # Check for usr/closed and deleted_files/usr/closed 3419daaffb31Sdp # 3420daaffb31Sdp if [ ! -z "$Oflag" ]; then 3421e0e0293aSjmcp if [[ $P == usr/closed/* || \ 3422e0e0293aSjmcp $P == deleted_files/usr/closed/* ]]; then 3423daaffb31Sdp print " <i>Closed source: omitted from" \ 3424daaffb31Sdp "this review</i>" 3425daaffb31Sdp fi 3426daaffb31Sdp fi 3427daaffb31Sdp 3428daaffb31Sdp print "</p>" 34297c478bd9Sstevel@tonic-gate # Insert delta comments 34307c478bd9Sstevel@tonic-gate 3431daaffb31Sdp print "<blockquote><pre>" 3432daaffb31Sdp getcomments html $P $PP 3433daaffb31Sdp print "</pre>" 34347c478bd9Sstevel@tonic-gate 34357c478bd9Sstevel@tonic-gate # Add additional comments comment 34367c478bd9Sstevel@tonic-gate 3437daaffb31Sdp print "<!-- Add comments to explain changes in $P here -->" 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate # Add count of changes. 34407c478bd9Sstevel@tonic-gate 3441daaffb31Sdp if [[ -f $F.count ]]; then 34427c478bd9Sstevel@tonic-gate cat $F.count 34437c478bd9Sstevel@tonic-gate rm $F.count 34447c478bd9Sstevel@tonic-gate fi 3445cdf0c1d5Smjnelson 3446cdf0c1d5Smjnelson if [[ $SCM_MODE == "teamware" || 3447cdf0c1d5Smjnelson $SCM_MODE == "mercurial" || 3448cdf0c1d5Smjnelson $SCM_MODE == "unknown" ]]; then 3449cdf0c1d5Smjnelson 3450cdf0c1d5Smjnelson # Include warnings for important file mode situations: 3451cdf0c1d5Smjnelson # 1) New executable files 3452cdf0c1d5Smjnelson # 2) Permission changes of any kind 3453cdf0c1d5Smjnelson # 3) Existing executable files 3454cdf0c1d5Smjnelson 3455cdf0c1d5Smjnelson old_mode= 3456cdf0c1d5Smjnelson if [[ -f $WDIR/raw_files/old/$PP ]]; then 3457cdf0c1d5Smjnelson old_mode=`get_file_mode $WDIR/raw_files/old/$PP` 3458cdf0c1d5Smjnelson fi 3459cdf0c1d5Smjnelson 3460cdf0c1d5Smjnelson new_mode= 3461cdf0c1d5Smjnelson if [[ -f $WDIR/raw_files/new/$P ]]; then 3462cdf0c1d5Smjnelson new_mode=`get_file_mode $WDIR/raw_files/new/$P` 3463cdf0c1d5Smjnelson fi 3464cdf0c1d5Smjnelson 3465cdf0c1d5Smjnelson if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then 3466cdf0c1d5Smjnelson print "<span class=\"chmod\">" 3467cdf0c1d5Smjnelson print "<p>new executable file: mode $new_mode</p>" 3468cdf0c1d5Smjnelson print "</span>" 3469cdf0c1d5Smjnelson elif [[ -n "$old_mode" && -n "$new_mode" && 3470cdf0c1d5Smjnelson "$old_mode" != "$new_mode" ]]; then 3471cdf0c1d5Smjnelson print "<span class=\"chmod\">" 3472cdf0c1d5Smjnelson print "<p>mode change: $old_mode to $new_mode</p>" 3473cdf0c1d5Smjnelson print "</span>" 3474cdf0c1d5Smjnelson elif [[ "$new_mode" = *[1357]* ]]; then 3475cdf0c1d5Smjnelson print "<span class=\"chmod\">" 3476cdf0c1d5Smjnelson print "<p>executable file: mode $new_mode</p>" 3477cdf0c1d5Smjnelson print "</span>" 3478cdf0c1d5Smjnelson fi 3479cdf0c1d5Smjnelson fi 3480cdf0c1d5Smjnelson 3481daaffb31Sdp print "</blockquote>" 34827c478bd9Sstevel@tonic-gatedone 34837c478bd9Sstevel@tonic-gate 3484daaffb31Sdpprint 3485daaffb31Sdpprint 3486cac38512Smjnelsonprint "<hr></hr>" 3487daaffb31Sdpprint "<p style=\"font-size: small\">" 34889a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>." 3489daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">" 3490daaffb31Sdpprint "OpenSolaris</a> project. The latest version may be obtained" 3491e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>" 3492daaffb31Sdpprint "</body>" 3493daaffb31Sdpprint "</html>" 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gateexec 1<&- # Close FD 1. 34967c478bd9Sstevel@tonic-gateexec 1<&3 # dup FD 3 to restore stdout. 34977c478bd9Sstevel@tonic-gateexec 3<&- # close FD 3. 34987c478bd9Sstevel@tonic-gate 3499daaffb31Sdpprint "Done." 350002d26c39SVladimir Kotal 3501b0088928SVladimir Kotal# 3502ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue. 3503b0088928SVladimir Kotal# 3504ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then 3505b0088928SVladimir Kotal delete_webrev 1 1 3506ba44d8a2SVladimir Kotal (( $? == 0 )) || exit $? 3507ba44d8a2SVladimir Kotalfi 3508ba44d8a2SVladimir Kotal 350902d26c39SVladimir Kotalif [[ -n $Uflag ]]; then 351002d26c39SVladimir Kotal upload_webrev 351102d26c39SVladimir Kotal exit $? 351202d26c39SVladimir Kotalfi 3513