xref: /titanic_53/usr/src/tools/scripts/webrev.sh (revision 8bcea973790ad3e762bf78b7c6ad5776e463fd51)
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#
2478add226Sjmcp# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bd9Sstevel@tonic-gate#
26cdf0c1d5Smjnelson
272f54b716SRichard Lowe# Copyright 2008, 2010, Richard Lowe
282f54b716SRichard Lowe
29cdf0c1d5Smjnelson#
30daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
31daaffb31Sdp# suitable for doing a code review of source changes via a web page.
32daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
33daaffb31Sdp# type 'webrev -h'.
347c478bd9Sstevel@tonic-gate#
35daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
36daaffb31Sdp# man page.
377c478bd9Sstevel@tonic-gate#
38daaffb31Sdp
397c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
407c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
417c478bd9Sstevel@tonic-gateNEW_COLOR=blue
427c478bd9Sstevel@tonic-gate
43daaffb31SdpHTML='<?xml version="1.0"?>
44daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
45daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
46daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
47daaffb31Sdp
48daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
49daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
50daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
51daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
52daaffb31Sdp
53cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
54cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
55cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
56daaffb31Sdp<!--
57daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
58daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
59daaffb31Sdp   mechanism available in some browsers.
60daaffb31Sdp
61daaffb31Sdp   For example, to have all "removed" information be red instead of
62daaffb31Sdp   brown, set a rule in your userContent.css file like:
63daaffb31Sdp
64daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
65daaffb31Sdp-->
66daaffb31Sdp<style type="text/css" media="screen">
67daaffb31Sdpbody {
68daaffb31Sdp    background-color: #eeeeee;
69daaffb31Sdp}
70daaffb31Sdphr {
71daaffb31Sdp    border: none 0;
72daaffb31Sdp    border-top: 1px solid #aaa;
73daaffb31Sdp    height: 1px;
74daaffb31Sdp}
75daaffb31Sdpdiv.summary {
76daaffb31Sdp    font-size: .8em;
77daaffb31Sdp    border-bottom: 1px solid #aaa;
78daaffb31Sdp    padding-left: 1em;
79daaffb31Sdp    padding-right: 1em;
80daaffb31Sdp}
81daaffb31Sdpdiv.summary h2 {
82daaffb31Sdp    margin-bottom: 0.3em;
83daaffb31Sdp}
84daaffb31Sdpdiv.summary table th {
85daaffb31Sdp    text-align: right;
86daaffb31Sdp    vertical-align: top;
87daaffb31Sdp    white-space: nowrap;
88daaffb31Sdp}
89daaffb31Sdpspan.lineschanged {
90daaffb31Sdp    font-size: 0.7em;
91daaffb31Sdp}
92daaffb31Sdpspan.oldmarker {
93daaffb31Sdp    color: red;
94daaffb31Sdp    font-size: large;
95daaffb31Sdp    font-weight: bold;
96daaffb31Sdp}
97daaffb31Sdpspan.newmarker {
98daaffb31Sdp    color: green;
99daaffb31Sdp    font-size: large;
100daaffb31Sdp    font-weight: bold;
101daaffb31Sdp}
102daaffb31Sdpspan.removed {
103daaffb31Sdp    color: brown;
104daaffb31Sdp}
105daaffb31Sdpspan.changed {
106daaffb31Sdp    color: blue;
107daaffb31Sdp}
108daaffb31Sdpspan.new {
109daaffb31Sdp    color: blue;
110daaffb31Sdp    font-weight: bold;
111daaffb31Sdp}
112cdf0c1d5Smjnelsonspan.chmod {
113cdf0c1d5Smjnelson    font-size: 0.7em;
114cdf0c1d5Smjnelson    color: #db7800;
115cdf0c1d5Smjnelson}
116daaffb31Sdpa.print { font-size: x-small; }
117daaffb31Sdpa:hover { background-color: #ffcc99; }
118daaffb31Sdp</style>
119daaffb31Sdp
120daaffb31Sdp<style type="text/css" media="print">
121daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
122daaffb31Sdpspan.removed { color: #444; font-style: italic }
123daaffb31Sdpspan.changed { font-weight: bold; }
124daaffb31Sdpspan.new { font-weight: bold; }
125daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
126daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
127daaffb31Sdpa.print {display: none}
128daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
129daaffb31Sdp</style>
130daaffb31Sdp'
131daaffb31Sdp
132daaffb31Sdp#
133daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
134daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
135daaffb31Sdp#
136daaffb31SdpUDIFFCSS='
137daaffb31Sdp<style type="text/css" media="screen">
138daaffb31Sdpspan.new {
139daaffb31Sdp    color: blue;
140daaffb31Sdp    font-weight: normal;
141daaffb31Sdp}
142daaffb31Sdp</style>
143daaffb31Sdp'
144daaffb31Sdp
145b0088928SVladimir Kotal#
146b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
147b0088928SVladimir Kotal#
148b0088928SVladimir Kotalfunction print_upload_header
149b0088928SVladimir Kotal{
150b0088928SVladimir Kotal	typeset -r prefix=$1
151b0088928SVladimir Kotal	typeset display_target
152b0088928SVladimir Kotal
153b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
154b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
155b0088928SVladimir Kotal	else
156b0088928SVladimir Kotal		display_target=${remote_target}
157b0088928SVladimir Kotal	fi
158b0088928SVladimir Kotal
159b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
160b0088928SVladimir Kotal		display_target=${display_target}/
161b0088928SVladimir Kotal	fi
162b0088928SVladimir Kotal
163b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
164b0088928SVladimir Kotal	    "     Uploading: \c"
165b0088928SVladimir Kotal}
166b0088928SVladimir Kotal
167b0088928SVladimir Kotal#
16802d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
169b0088928SVladimir Kotal#
170ba44d8a2SVladimir Kotalfunction rsync_upload
17102d26c39SVladimir Kotal{
172b0088928SVladimir Kotal	if (( $# != 2 )); then
173b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
174b0088928SVladimir Kotal		exit 1
17502d26c39SVladimir Kotal	fi
17602d26c39SVladimir Kotal
177b0088928SVladimir Kotal	typeset -r dst=$1
178b0088928SVladimir Kotal	integer -r print_err_msg=$2
17902d26c39SVladimir Kotal
180b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
181b0088928SVladimir Kotal	print "rsync ... \c"
1828a34f8dcSVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
183b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
184b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
185b0088928SVladimir Kotal		return 1
186b0088928SVladimir Kotal	fi
187b0088928SVladimir Kotal	#
188b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
189b0088928SVladimir Kotal	# directory contents, not the whole directory.
190b0088928SVladimir Kotal	#
191b0088928SVladimir Kotal	typeset src_dir=$WDIR
192b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
193b0088928SVladimir Kotal		src_dir=${src_dir}/
194b0088928SVladimir Kotal	fi
195b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
19602d26c39SVladimir Kotal	if (( $? != 0 )); then
197b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
198b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
199b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
200b0088928SVladimir Kotal			print "error messages:"
201b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
202b0088928SVladimir Kotal			rm -f $err_msg
203b0088928SVladimir Kotal		fi
20402d26c39SVladimir Kotal		return 1
20502d26c39SVladimir Kotal	fi
20602d26c39SVladimir Kotal
207b0088928SVladimir Kotal	rm -f $err_msg
20802d26c39SVladimir Kotal	print "Done."
20902d26c39SVladimir Kotal	return 0
21002d26c39SVladimir Kotal}
21102d26c39SVladimir Kotal
212b0088928SVladimir Kotal#
213b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
214b0088928SVladimir Kotal# 1 on failure.
215b0088928SVladimir Kotal#
216b0088928SVladimir Kotalfunction remote_mkdirs
217b0088928SVladimir Kotal{
218b0088928SVladimir Kotal	typeset -r dir_spec=$1
2199d3952abSVladimir Kotal	typeset -r host_spec=$2
220b0088928SVladimir Kotal
221b0088928SVladimir Kotal	#
222b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
223b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
224b0088928SVladimir Kotal	# except the last one which will be created by scp.
225b0088928SVladimir Kotal	#
226b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
227b0088928SVladimir Kotal		print "mkdirs \c"
228b0088928SVladimir Kotal		#
229b0088928SVladimir Kotal		# Remove the last directory from directory specification.
230b0088928SVladimir Kotal		#
231b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
2328a34f8dcSVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP \
2338a34f8dcSVladimir Kotal		    /tmp/webrev_mkdir.XXXXXX )
234b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
235b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
236b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
237b0088928SVladimir Kotal			return 1
238b0088928SVladimir Kotal		fi
239b0088928SVladimir Kotal                OLDIFS=$IFS
240b0088928SVladimir Kotal                IFS=/
241b0088928SVladimir Kotal		typeset dir
242b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
243b0088928SVladimir Kotal			#
244b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
245b0088928SVladimir Kotal			# to avoid an error in case the directory already
246b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
247b0088928SVladimir Kotal			# there is one.
248b0088928SVladimir Kotal			#
249b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
250b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
251b0088928SVladimir Kotal                done
252b0088928SVladimir Kotal                IFS=$OLDIFS
2538a34f8dcSVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
254b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
255b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
256b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
257b0088928SVladimir Kotal			return 1
258b0088928SVladimir Kotal		fi
259b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
260b0088928SVladimir Kotal		if (( $? != 0 )); then
261b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
262b0088928SVladimir Kotal			print "error messages:"
263b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
264b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
265b0088928SVladimir Kotal			return 1
266b0088928SVladimir Kotal		fi
267b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
268b0088928SVladimir Kotal	fi
269b0088928SVladimir Kotal
270b0088928SVladimir Kotal	return 0
271b0088928SVladimir Kotal}
272b0088928SVladimir Kotal
273b0088928SVladimir Kotal#
27402d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
275b0088928SVladimir Kotal#
276ba44d8a2SVladimir Kotalfunction ssh_upload
27702d26c39SVladimir Kotal{
27802d26c39SVladimir Kotal	if (( $# != 1 )); then
279b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
280b0088928SVladimir Kotal		exit 1
28102d26c39SVladimir Kotal	fi
28202d26c39SVladimir Kotal
28302d26c39SVladimir Kotal	typeset dst=$1
28402d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
285ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
28602d26c39SVladimir Kotal
287b0088928SVladimir Kotal	#
288b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
289b0088928SVladimir Kotal	# because it will also print its progress.
290b0088928SVladimir Kotal	#
291b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
292b0088928SVladimir Kotal
293b0088928SVladimir Kotal	#
294b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
295b0088928SVladimir Kotal	# to perform it again.
296b0088928SVladimir Kotal	#
297ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
298b0088928SVladimir Kotal		#
299b0088928SVladimir Kotal		# We do not care about return value because this might be
300b0088928SVladimir Kotal		# the first time this directory is uploaded.
301b0088928SVladimir Kotal		#
302ba44d8a2SVladimir Kotal		delete_webrev 0
30302d26c39SVladimir Kotal	fi
30402d26c39SVladimir Kotal
305b0088928SVladimir Kotal	#
306b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
307b0088928SVladimir Kotal	# in remote_mkdirs function.
308b0088928SVladimir Kotal	#
3099d3952abSVladimir Kotal	remote_mkdirs ${dir_spec} ${host_spec}
31002d26c39SVladimir Kotal	if (( $? != 0 )); then
31102d26c39SVladimir Kotal		return 1
31202d26c39SVladimir Kotal	fi
31302d26c39SVladimir Kotal
314b0088928SVladimir Kotal	print "upload ... \c"
3158a34f8dcSVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
316b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
317b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
318b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
319b0088928SVladimir Kotal		return 1
320b0088928SVladimir Kotal	fi
32102d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
322b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
32302d26c39SVladimir Kotal	if (( $? != 0 )); then
324b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
325b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
326b0088928SVladimir Kotal		print "error messages:"
327b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
328b0088928SVladimir Kotal		rm -f ${scp_err_msg}
32902d26c39SVladimir Kotal		return 1
33002d26c39SVladimir Kotal	fi
33102d26c39SVladimir Kotal
332b0088928SVladimir Kotal	rm -f ${scp_err_msg}
33302d26c39SVladimir Kotal	print "Done."
33402d26c39SVladimir Kotal	return 0
33502d26c39SVladimir Kotal}
33602d26c39SVladimir Kotal
33702d26c39SVladimir Kotal#
338ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
339b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
340b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
341b0088928SVladimir Kotal# only performs deletion.
342ba44d8a2SVladimir Kotal#
343ba44d8a2SVladimir Kotalfunction delete_webrev
344ba44d8a2SVladimir Kotal{
345b0088928SVladimir Kotal	if (( $# < 1 )); then
346b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
347b0088928SVladimir Kotal		exit 1
348ba44d8a2SVladimir Kotal	fi
349ba44d8a2SVladimir Kotal
350b0088928SVladimir Kotal	integer -r check=$1
351b0088928SVladimir Kotal	integer delete_only=0
352b0088928SVladimir Kotal	if (( $# == 2 )); then
353b0088928SVladimir Kotal		delete_only=1
354b0088928SVladimir Kotal	fi
355b0088928SVladimir Kotal
356b0088928SVladimir Kotal	#
357ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
358b0088928SVladimir Kotal	#
359ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
360ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
361ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
362ba44d8a2SVladimir Kotal	typeset dir_rm
363ba44d8a2SVladimir Kotal
364b0088928SVladimir Kotal	#
365ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
366b0088928SVladimir Kotal	#
367ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
368ba44d8a2SVladimir Kotal		return 1
369ba44d8a2SVladimir Kotal	fi
370ba44d8a2SVladimir Kotal
371b0088928SVladimir Kotal	#
372ba44d8a2SVladimir Kotal	# Strip the ending slash.
373b0088928SVladimir Kotal	#
374ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
375ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
376ba44d8a2SVladimir Kotal	else
377ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
378ba44d8a2SVladimir Kotal	fi
379ba44d8a2SVladimir Kotal
380b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
381b0088928SVladimir Kotal		print "       Removing: \c"
382b0088928SVladimir Kotal	else
383b0088928SVladimir Kotal		print "rmdir \c"
384b0088928SVladimir Kotal	fi
385ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
386b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
387ba44d8a2SVladimir Kotal		return 1
388ba44d8a2SVladimir Kotal	fi
389ba44d8a2SVladimir Kotal
390b0088928SVladimir Kotal	#
391ba44d8a2SVladimir Kotal	# Prepare batch file.
392b0088928SVladimir Kotal	#
3938a34f8dcSVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
394ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
395b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
396ba44d8a2SVladimir Kotal		return 1
397ba44d8a2SVladimir Kotal	fi
398ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
399ba44d8a2SVladimir Kotal
400b0088928SVladimir Kotal	#
401ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
402b0088928SVladimir Kotal	#
4038a34f8dcSVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
404b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
405b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
406b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
407b0088928SVladimir Kotal		return 1
408b0088928SVladimir Kotal	fi
409b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
410ba44d8a2SVladimir Kotal	integer -r ret=$?
411ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
412ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
413b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
414b0088928SVladimir Kotal		print "error messages:"
415b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
416b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
417ba44d8a2SVladimir Kotal		return $ret
418ba44d8a2SVladimir Kotal	fi
419b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
420b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
421ba44d8a2SVladimir Kotal		print "Done."
422b0088928SVladimir Kotal	fi
423ba44d8a2SVladimir Kotal
424ba44d8a2SVladimir Kotal	return 0
425ba44d8a2SVladimir Kotal}
426ba44d8a2SVladimir Kotal
427ba44d8a2SVladimir Kotal#
42802d26c39SVladimir Kotal# Upload webrev to remote site
42902d26c39SVladimir Kotal#
430ba44d8a2SVladimir Kotalfunction upload_webrev
43102d26c39SVladimir Kotal{
432b0088928SVladimir Kotal	integer ret
43302d26c39SVladimir Kotal
43402d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
435b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
43602d26c39SVladimir Kotal		return 1
43702d26c39SVladimir Kotal	fi
43802d26c39SVladimir Kotal
439b0088928SVladimir Kotal	#
44002d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
44102d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
44202d26c39SVladimir Kotal	# target he probably knows what he is doing.
443b0088928SVladimir Kotal	#
44402d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
445ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
44602d26c39SVladimir Kotal			| $GREP closed >/dev/null
44702d26c39SVladimir Kotal		if (( $? == 0 )); then
448b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
449b0088928SVladimir Kotal			    "\"closed\" directory"
45002d26c39SVladimir Kotal			return 1
45102d26c39SVladimir Kotal		fi
45202d26c39SVladimir Kotal	fi
45302d26c39SVladimir Kotal
454b0088928SVladimir Kotal
455b0088928SVladimir Kotal	#
456b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
457b0088928SVladimir Kotal	#
45802d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
45902d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
460b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
461b0088928SVladimir Kotal			ret=$?
462b0088928SVladimir Kotal			return $ret
46302d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
46402d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
465b0088928SVladimir Kotal			ret=$?
466b0088928SVladimir Kotal			return $ret
46702d26c39SVladimir Kotal		fi
46802d26c39SVladimir Kotal	else
469b0088928SVladimir Kotal		#
470b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
471b0088928SVladimir Kotal		#
472b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
473b0088928SVladimir Kotal		ret=$?
474b0088928SVladimir Kotal		if (( $ret != 0 )); then
475b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
476ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
477b0088928SVladimir Kotal			ret=$?
47802d26c39SVladimir Kotal		fi
479b0088928SVladimir Kotal		return $ret
48002d26c39SVladimir Kotal	fi
48102d26c39SVladimir Kotal}
48202d26c39SVladimir Kotal
483daaffb31Sdp#
484371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
485371d72daSLubomir Sedlacik#
486371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
487371d72daSLubomir Sedlacik#
488371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
489371d72daSLubomir Sedlacik#
490371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
491371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
492371d72daSLubomir Sedlacik# a path delimiter.
493371d72daSLubomir Sedlacik#
49425cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make
49525cc4e45SVladimir Kotal# the substitution work with GNU sed.
49625cc4e45SVladimir Kotal#
497371d72daSLubomir Sedlacikfunction url_encode
498371d72daSLubomir Sedlacik{
499b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
500371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
501371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
502371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
50325cc4e45SVladimir Kotal	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
504371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
505371d72daSLubomir Sedlacik}
506371d72daSLubomir Sedlacik
507371d72daSLubomir Sedlacik#
508daaffb31Sdp# input_cmd | html_quote | output_cmd
509daaffb31Sdp# or
510daaffb31Sdp# html_quote filename | output_cmd
5117c478bd9Sstevel@tonic-gate#
5127c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5137c478bd9Sstevel@tonic-gate#
5147c478bd9Sstevel@tonic-gatehtml_quote()
5157c478bd9Sstevel@tonic-gate{
516b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5177c478bd9Sstevel@tonic-gate}
5187c478bd9Sstevel@tonic-gate
519daaffb31Sdp#
520*8bcea973SRichard Lowe# Trim a digest-style revision to a conventionally readable yet useful length
521*8bcea973SRichard Lowe#
522*8bcea973SRichard Lowetrim_digest()
523*8bcea973SRichard Lowe{
524*8bcea973SRichard Lowe	typeset digest=$1
525*8bcea973SRichard Lowe
526*8bcea973SRichard Lowe	echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'
527*8bcea973SRichard Lowe}
528*8bcea973SRichard Lowe
529*8bcea973SRichard Lowe#
5300fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
531daaffb31Sdp#
5320fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
5330fd2682eSMark J. Nelson# relevant databases.
534daaffb31Sdp#
5350fd2682eSMark J. Nelsonits2url()
5367c478bd9Sstevel@tonic-gate{
5370fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
538daaffb31Sdp}
539daaffb31Sdp
5407c478bd9Sstevel@tonic-gate#
541daaffb31Sdp# strip_unchanged <infile> | output_cmd
5427c478bd9Sstevel@tonic-gate#
543daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
544daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5457c478bd9Sstevel@tonic-gate#
546daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
547daaffb31Sdp# identical lines are retained before and after the changed lines to
548daaffb31Sdp# provide some context.  The number of these lines is controlled by the
549cdf0c1d5Smjnelson# variable C in the $AWK script below.
550daaffb31Sdp#
551daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
552daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
553daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
554daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
555daaffb31Sdp#
556daaffb31Sdpstrip_unchanged()
557daaffb31Sdp{
558cdf0c1d5Smjnelson	$AWK '
559daaffb31Sdp	BEGIN	{ C = c = 20 }
560cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
561daaffb31Sdp		if (c > C) {
562daaffb31Sdp			c -= C
563daaffb31Sdp			inx = 0
564daaffb31Sdp			if (c > C) {
565cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
566daaffb31Sdp				inx = c % C
567daaffb31Sdp				c = C
568daaffb31Sdp			}
569daaffb31Sdp
570daaffb31Sdp			for (i = 0; i < c; i++)
571daaffb31Sdp				print ln[(inx + i) % C]
572daaffb31Sdp		}
573daaffb31Sdp		c = 0;
574daaffb31Sdp		print
575daaffb31Sdp		next
576daaffb31Sdp	}
577daaffb31Sdp	{	if (c >= C) {
578daaffb31Sdp			ln[c % C] = $0
579daaffb31Sdp			c++;
580daaffb31Sdp			next;
581daaffb31Sdp		}
582daaffb31Sdp		c++;
583daaffb31Sdp		print
584daaffb31Sdp	}
585cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
586daaffb31Sdp
587daaffb31Sdp	' $1
588daaffb31Sdp}
589daaffb31Sdp
590daaffb31Sdp#
591daaffb31Sdp# sdiff_to_html
592daaffb31Sdp#
593daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
594daaffb31Sdp# processes the diff output to present the files as an HTML document with
595daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
596daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
597daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
598daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
599daaffb31Sdp# e.g.
600daaffb31Sdp#
601daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
602daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
603daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
604daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
605daaffb31Sdp#          1234567</a> my bugid' > <file>.html
606daaffb31Sdp#
607daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
608daaffb31Sdp# in the webrev tree.
609daaffb31Sdp#
610daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
611daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
612daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
613daaffb31Sdp# the editing codes, e.g.
6147c478bd9Sstevel@tonic-gate#
6157c478bd9Sstevel@tonic-gate#      8c8
6167c478bd9Sstevel@tonic-gate#      57a61
6177c478bd9Sstevel@tonic-gate#      63c66,76
6187c478bd9Sstevel@tonic-gate#      68,93d80
6197c478bd9Sstevel@tonic-gate#      106d90
6207c478bd9Sstevel@tonic-gate#      108,110d91
6217c478bd9Sstevel@tonic-gate#
622daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
623daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
624daaffb31Sdp#  into something like this:
6257c478bd9Sstevel@tonic-gate#
6267c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6277c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
628daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6297c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6307c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6317c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6327c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6337c478bd9Sstevel@tonic-gate#        :               :
6347c478bd9Sstevel@tonic-gate#
635daaffb31Sdp#  This script is then run on the original source file to generate the
636daaffb31Sdp#  HTML that corresponds to the source file.
6377c478bd9Sstevel@tonic-gate#
638daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
639daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
640daaffb31Sdp#  notice that the changes are color-coded:
6417c478bd9Sstevel@tonic-gate#
6427c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6437c478bd9Sstevel@tonic-gate#   blue      - changed lines
6447c478bd9Sstevel@tonic-gate#   bold blue - new lines
6457c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6467c478bd9Sstevel@tonic-gate#
647daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
648daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
649daaffb31Sdp#  Teamware's filemerge tool.
650daaffb31Sdp#
651daaffb31Sdpsdiff_to_html()
652daaffb31Sdp{
6537c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6547c478bd9Sstevel@tonic-gate
655daaffb31Sdp	TNAME=$3
656daaffb31Sdp	TPATH=$4
657daaffb31Sdp	COMMENT=$5
658daaffb31Sdp
6597c478bd9Sstevel@tonic-gate	#
6607c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6617c478bd9Sstevel@tonic-gate	#
662cdf0c1d5Smjnelson	$AWK '
6637c478bd9Sstevel@tonic-gate	BEGIN	{
6647c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
665daaffb31Sdp		printf "function removed() "
666daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
667daaffb31Sdp		printf "function changed() "
668daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
669daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6707c478bd9Sstevel@tonic-gate}
6717c478bd9Sstevel@tonic-gate	/^</	{next}
6727c478bd9Sstevel@tonic-gate	/^>/	{next}
6737c478bd9Sstevel@tonic-gate	/^---/	{next}
674daaffb31Sdp
6757c478bd9Sstevel@tonic-gate	{
6767c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6777c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6787c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6797c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6807c478bd9Sstevel@tonic-gate			if (n == 1)
6817c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6827c478bd9Sstevel@tonic-gate			else
6837c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6847c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6857c478bd9Sstevel@tonic-gate			next
6867c478bd9Sstevel@tonic-gate		}
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6897c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6907c478bd9Sstevel@tonic-gate		s = r[1];
6917c478bd9Sstevel@tonic-gate		if (n == 1)
6927c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6937c478bd9Sstevel@tonic-gate		else {
6947c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6957c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6967c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6977c478bd9Sstevel@tonic-gate		}
6987c478bd9Sstevel@tonic-gate		next
6997c478bd9Sstevel@tonic-gate	}
7007c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7017c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7027c478bd9Sstevel@tonic-gate		n1 = r[1]
7037c478bd9Sstevel@tonic-gate		n2 = r[2]
7047c478bd9Sstevel@tonic-gate		if (n == 1)
705daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
7067c478bd9Sstevel@tonic-gate		else
707daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
7087c478bd9Sstevel@tonic-gate		next
7097c478bd9Sstevel@tonic-gate	}
7107c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7117c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7127c478bd9Sstevel@tonic-gate		n1 = r[1]
7137c478bd9Sstevel@tonic-gate		n2 = r[2]
7147c478bd9Sstevel@tonic-gate		final = n2
7157c478bd9Sstevel@tonic-gate		d1 = 0
7167c478bd9Sstevel@tonic-gate		if (n == 1)
717daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7187c478bd9Sstevel@tonic-gate		else {
7197c478bd9Sstevel@tonic-gate			d1 = n2 - n1
720daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7217c478bd9Sstevel@tonic-gate		}
7227c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7237c478bd9Sstevel@tonic-gate		n1 = r[1]
7247c478bd9Sstevel@tonic-gate		n2 = r[2]
7257c478bd9Sstevel@tonic-gate		if (m > 1) {
7267c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7277c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7287c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7297c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7307c478bd9Sstevel@tonic-gate			}
7317c478bd9Sstevel@tonic-gate		}
7327c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate		next
7357c478bd9Sstevel@tonic-gate	}
7367c478bd9Sstevel@tonic-gate	}
7377c478bd9Sstevel@tonic-gate
738daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
739daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate	#
7427c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7437c478bd9Sstevel@tonic-gate	#
744cdf0c1d5Smjnelson	$AWK '
7457c478bd9Sstevel@tonic-gate	BEGIN	{
7467c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
747daaffb31Sdp		printf "function new() "
748daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
749daaffb31Sdp		printf "function changed() "
750daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
751daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7527c478bd9Sstevel@tonic-gate	}
753daaffb31Sdp
7547c478bd9Sstevel@tonic-gate	/^</	{next}
7557c478bd9Sstevel@tonic-gate	/^>/	{next}
7567c478bd9Sstevel@tonic-gate	/^---/	{next}
757daaffb31Sdp
7587c478bd9Sstevel@tonic-gate	{
7597c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7607c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7617c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7627c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7637c478bd9Sstevel@tonic-gate			if (n == 1)
7647c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7657c478bd9Sstevel@tonic-gate			else
7667c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7677c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7687c478bd9Sstevel@tonic-gate			next
7697c478bd9Sstevel@tonic-gate		}
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7727c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7737c478bd9Sstevel@tonic-gate		s = r[1];
7747c478bd9Sstevel@tonic-gate		if (n == 1)
7757c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7767c478bd9Sstevel@tonic-gate		else {
7777c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7787c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7797c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7807c478bd9Sstevel@tonic-gate		}
7817c478bd9Sstevel@tonic-gate		next
7827c478bd9Sstevel@tonic-gate	}
7837c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7847c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7857c478bd9Sstevel@tonic-gate		n1 = r[1]
7867c478bd9Sstevel@tonic-gate		n2 = r[2]
7877c478bd9Sstevel@tonic-gate		if (n == 1)
788daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7897c478bd9Sstevel@tonic-gate		else
790daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7917c478bd9Sstevel@tonic-gate		next
7927c478bd9Sstevel@tonic-gate	}
7937c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7947c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7957c478bd9Sstevel@tonic-gate		n1 = r[1]
7967c478bd9Sstevel@tonic-gate		n2 = r[2]
7977c478bd9Sstevel@tonic-gate		final = n2
7987c478bd9Sstevel@tonic-gate		d2 = 0;
7997c478bd9Sstevel@tonic-gate		if (n == 1) {
8007c478bd9Sstevel@tonic-gate			final = n1
801daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
8027c478bd9Sstevel@tonic-gate		} else {
8037c478bd9Sstevel@tonic-gate			d2 = n2 - n1
804daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
8057c478bd9Sstevel@tonic-gate		}
8067c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
8077c478bd9Sstevel@tonic-gate		n1 = r[1]
8087c478bd9Sstevel@tonic-gate		n2 = r[2]
8097c478bd9Sstevel@tonic-gate		if (m > 1) {
8107c478bd9Sstevel@tonic-gate			d1  = n2 - n1
8117c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8127c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8137c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8147c478bd9Sstevel@tonic-gate			}
8157c478bd9Sstevel@tonic-gate		}
8167c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8177c478bd9Sstevel@tonic-gate		next
8187c478bd9Sstevel@tonic-gate	}
8197c478bd9Sstevel@tonic-gate	}
820daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8217c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8227c478bd9Sstevel@tonic-gate
823daaffb31Sdp	#
824cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
825daaffb31Sdp	#
826cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8277c478bd9Sstevel@tonic-gate
828cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8297c478bd9Sstevel@tonic-gate
830daaffb31Sdp	#
831daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
832daaffb31Sdp	#
833daaffb31Sdp	print "$HTML<head>$STDHEAD"
834cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
835daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
836daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
837daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
838daaffb31Sdp	print "<table><tr valign=\"top\">"
839daaffb31Sdp	print "<td><pre>"
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8427c478bd9Sstevel@tonic-gate
843daaffb31Sdp	print "</pre></td><td><pre>"
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8467c478bd9Sstevel@tonic-gate
847daaffb31Sdp	print "</pre></td>"
848daaffb31Sdp	print "</tr></table>"
849daaffb31Sdp	print "</body></html>"
8507c478bd9Sstevel@tonic-gate
851daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
852daaffb31Sdp	    "$COMMENT"
8537c478bd9Sstevel@tonic-gate}
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate
856daaffb31Sdp#
857daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
858daaffb31Sdp#
859daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
860daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
861daaffb31Sdp# and then emit the main frame.  Content is placed into:
862daaffb31Sdp#
863daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
864daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
865daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
866daaffb31Sdp#
867daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
868daaffb31Sdp#
8697c478bd9Sstevel@tonic-gatefunction framed_sdiff
8707c478bd9Sstevel@tonic-gate{
8717c478bd9Sstevel@tonic-gate	typeset TNAME=$1
872daaffb31Sdp	typeset TPATH=$2
873daaffb31Sdp	typeset lhsfile=$3
874daaffb31Sdp	typeset rhsfile=$4
875daaffb31Sdp	typeset comments=$5
8767c478bd9Sstevel@tonic-gate	typeset RTOP
877daaffb31Sdp
8787c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
879daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
880daaffb31Sdp
881daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
882daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
883daaffb31Sdp
884daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8858b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8867c478bd9Sstevel@tonic-gate	    </head>
887daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
888cac38512Smjnelson	    <a name="0"></a>
889cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
890daaffb31Sdp	EOF
891daaffb31Sdp
892daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
893daaffb31Sdp
894daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
895daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
896daaffb31Sdp
897daaffb31Sdp	close='</body></html>'
898daaffb31Sdp
899daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
900daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
901daaffb31Sdp
902daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
903daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
904daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
905daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
906daaffb31Sdp	  <frameset rows="*,60">
907daaffb31Sdp	    <frameset cols="50%,50%">
908cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
909cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
910daaffb31Sdp	    </frameset>
9118b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
912cac38512Smjnelson	   marginheight="0" name="nav"></frame>
913daaffb31Sdp	  <noframes>
914daaffb31Sdp            <body id="SUNWwebrev">
915daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9167c478bd9Sstevel@tonic-gate	      and has the feature enabled.
917daaffb31Sdp            </body>
918daaffb31Sdp	  </noframes>
919daaffb31Sdp	  </frameset>
9207c478bd9Sstevel@tonic-gate	</html>
9217c478bd9Sstevel@tonic-gate	EOF
9227c478bd9Sstevel@tonic-gate}
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate
925daaffb31Sdp#
926daaffb31Sdp# fix_postscript
927daaffb31Sdp#
928daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
929daaffb31Sdp#	- removing all extraneous headers/trailers
930daaffb31Sdp#	- making the page numbers right
931daaffb31Sdp#	- removing pages devoid of contents which confuse some
932daaffb31Sdp#	  postscript readers.
933daaffb31Sdp#
934daaffb31Sdp# From Casper.
935daaffb31Sdp#
936daaffb31Sdpfunction fix_postscript
9377c478bd9Sstevel@tonic-gate{
938daaffb31Sdp	infile=$1
9397c478bd9Sstevel@tonic-gate
940daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9417c478bd9Sstevel@tonic-gate
942daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
943daaffb31Sdp	print "%%Orientation: Landscape\n";
9447c478bd9Sstevel@tonic-gate
945daaffb31Sdp	$pno = 0;
946daaffb31Sdp	$doprint = 1;
947daaffb31Sdp
948daaffb31Sdp	$page = "";
949daaffb31Sdp
950daaffb31Sdp	while (<>) {
951daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
952daaffb31Sdp
953daaffb31Sdp		if (/^%%Page:/) {
954daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
955daaffb31Sdp				# Header or single page containing text
956daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
957daaffb31Sdp				print $page;
958daaffb31Sdp				$pno++;
959daaffb31Sdp			} else {
960daaffb31Sdp				# Empty page, skip it.
9617c478bd9Sstevel@tonic-gate			}
962daaffb31Sdp			$page = "";
963daaffb31Sdp			$doprint = 1;
9647c478bd9Sstevel@tonic-gate			next;
9657c478bd9Sstevel@tonic-gate		}
9667c478bd9Sstevel@tonic-gate
967daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
968daaffb31Sdp		# %%Page of the next
969daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
970daaffb31Sdp		$page .= $_ if ($doprint);
9717c478bd9Sstevel@tonic-gate	}
9727c478bd9Sstevel@tonic-gate
973daaffb31Sdp	if ($page =~ /\)S/) {
974daaffb31Sdp		print "%%Page: ? $pno\n";
975daaffb31Sdp		print $page;
976daaffb31Sdp	} else {
977daaffb31Sdp		$pno--;
978daaffb31Sdp	}
979daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
980daaffb31SdpEOF
981daaffb31Sdp
98214983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
983daaffb31Sdp}
984daaffb31Sdp
985daaffb31Sdp
986daaffb31Sdp#
987daaffb31Sdp# input_cmd | insert_anchors | output_cmd
988daaffb31Sdp#
9897c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
990daaffb31Sdp# anchors.  These are used to drive the frames version of the
9917c478bd9Sstevel@tonic-gate# sdiffs output.
9927c478bd9Sstevel@tonic-gate#
9937c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9947c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9957c478bd9Sstevel@tonic-gate#
996daaffb31Sdp# The script detects changed lines as any line that has a "<span
997daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
998daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
9997c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
10007c478bd9Sstevel@tonic-gate# deleted.
10017c478bd9Sstevel@tonic-gate#
1002daaffb31Sdpfunction insert_anchors
1003daaffb31Sdp{
1004cdf0c1d5Smjnelson	$AWK '
10057c478bd9Sstevel@tonic-gate	function ia() {
1006daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
10077c478bd9Sstevel@tonic-gate	}
1008daaffb31Sdp
10097c478bd9Sstevel@tonic-gate	BEGIN {
1010daaffb31Sdp		anc=1;
10117c478bd9Sstevel@tonic-gate		inblock=1;
1012daaffb31Sdp		printf "<pre>\n";
10137c478bd9Sstevel@tonic-gate	}
1014daaffb31Sdp	NF == 0 || /^<span class=/ {
10157c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10167c478bd9Sstevel@tonic-gate			ia();
10177c478bd9Sstevel@tonic-gate			inblock=1;
10187c478bd9Sstevel@tonic-gate		}
10197c478bd9Sstevel@tonic-gate		print;
10207c478bd9Sstevel@tonic-gate		next;
10217c478bd9Sstevel@tonic-gate	}
10227c478bd9Sstevel@tonic-gate	{
10237c478bd9Sstevel@tonic-gate		inblock=0;
10247c478bd9Sstevel@tonic-gate		print;
10257c478bd9Sstevel@tonic-gate	}
10267c478bd9Sstevel@tonic-gate	END {
10277c478bd9Sstevel@tonic-gate		ia();
1028daaffb31Sdp
1029daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1030daaffb31Sdp		printf "--- EOF ---</b>"
10317c478bd9Sstevel@tonic-gate		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1032daaffb31Sdp		printf "</pre>"
1033daaffb31Sdp		printf "<form name=\"eof\">";
1034cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1035cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1036daaffb31Sdp		printf "</form>";
10377c478bd9Sstevel@tonic-gate	}
10387c478bd9Sstevel@tonic-gate	' $1
10397c478bd9Sstevel@tonic-gate}
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate
1042daaffb31Sdp#
1043daaffb31Sdp# relative_dir
1044daaffb31Sdp#
1045daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1046daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1047daaffb31Sdp# this function would print "../../../../".
1048daaffb31Sdp#
1049daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1050daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1051daaffb31Sdp# is not relocatable.
1052daaffb31Sdp#
1053daaffb31Sdpfunction relative_dir
10547c478bd9Sstevel@tonic-gate{
1055daaffb31Sdp        typeset cur="${1##$2?(/)}"
10568b3b7b16SMark J. Nelson
10578b3b7b16SMark J. Nelson        #
10588b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
10598b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
10608b3b7b16SMark J. Nelson        #
10610fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1062daaffb31Sdp                # Should never happen.
106314983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1064daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1065daaffb31Sdp                print -u2 "will not be relocatable!"
1066daaffb31Sdp                print $2
1067daaffb31Sdp                return
1068daaffb31Sdp        fi
1069daaffb31Sdp
10708b3b7b16SMark J. Nelson	#
10718b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
10728b3b7b16SMark J. Nelson	#
10738b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
10748b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
10758b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
10768b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
10778b3b7b16SMark J. Nelson	#    the end of a relative path.
10788b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
10798b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
10808b3b7b16SMark J. Nelson	#    level of relative separation.
10818b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
10828b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
10838b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
10848b3b7b16SMark J. Nelson	#
10850fd2682eSMark J. Nelson	print $cur | $SED -e '{
10868b3b7b16SMark J. Nelson		s:^\./*::
10878b3b7b16SMark J. Nelson		s:/$::
10888b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
10890fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
10900fd2682eSMark J. Nelson	}'
10917c478bd9Sstevel@tonic-gate}
10927c478bd9Sstevel@tonic-gate
1093daaffb31Sdp#
1094daaffb31Sdp# frame_nav_js
1095daaffb31Sdp#
1096daaffb31Sdp# Emit javascript for frame navigation
1097daaffb31Sdp#
1098daaffb31Sdpfunction frame_nav_js
10997c478bd9Sstevel@tonic-gate{
11007c478bd9Sstevel@tonic-gatecat << \EOF
11017c478bd9Sstevel@tonic-gatevar myInt;
11027c478bd9Sstevel@tonic-gatevar scrolling=0;
1103daaffb31Sdpvar sfactor = 3;
11047c478bd9Sstevel@tonic-gatevar scount=10;
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gatefunction scrollByPix() {
11077c478bd9Sstevel@tonic-gate	if (scount<=0) {
11087c478bd9Sstevel@tonic-gate		sfactor*=1.2;
11097c478bd9Sstevel@tonic-gate		scount=10;
11107c478bd9Sstevel@tonic-gate	}
11117c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11127c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11137c478bd9Sstevel@tonic-gate	scount--;
11147c478bd9Sstevel@tonic-gate}
11157c478bd9Sstevel@tonic-gate
1116daaffb31Sdpfunction scrollToAnc(num) {
1117daaffb31Sdp
1118daaffb31Sdp	// Update the value of the anchor in the form which we use as
1119daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1120daaffb31Sdp	// correcting for overflow and underflow of the value and return
1121daaffb31Sdp	// us the new value.
1122daaffb31Sdp	num = setAncValue(num);
1123daaffb31Sdp
1124daaffb31Sdp	// Set location and scroll back a little to expose previous
1125daaffb31Sdp	// lines.
1126daaffb31Sdp	//
1127daaffb31Sdp	// Note that this could be improved: it is possible although
1128daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1129daaffb31Sdp	// scroll to that location directly.
1130daaffb31Sdp	//
11317c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11327c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1133daaffb31Sdp
11347c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11357c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11367c478bd9Sstevel@tonic-gate}
11377c478bd9Sstevel@tonic-gate
1138daaffb31Sdpfunction getAncValue()
1139daaffb31Sdp{
1140daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1141daaffb31Sdp}
1142daaffb31Sdp
1143daaffb31Sdpfunction setAncValue(val)
1144daaffb31Sdp{
1145daaffb31Sdp	if (val <= 0) {
1146daaffb31Sdp		val = 0;
1147daaffb31Sdp		parent.nav.document.diff.real.value = val;
1148daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1149daaffb31Sdp		return (val);
1150daaffb31Sdp	}
1151daaffb31Sdp
1152daaffb31Sdp	//
1153daaffb31Sdp	// The way we compute the max anchor value is to stash it
1154daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1155daaffb31Sdp	// on each side, so we pluck from the left.
1156daaffb31Sdp	//
1157daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1158daaffb31Sdp	if (val < maxval) {
1159daaffb31Sdp		parent.nav.document.diff.real.value = val;
1160daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1161daaffb31Sdp		return (val);
1162daaffb31Sdp	}
1163daaffb31Sdp
1164daaffb31Sdp	// this must be: val >= maxval
1165daaffb31Sdp	val = maxval;
1166daaffb31Sdp	parent.nav.document.diff.real.value = val;
1167daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1168daaffb31Sdp	return (val);
1169daaffb31Sdp}
1170daaffb31Sdp
11717c478bd9Sstevel@tonic-gatefunction stopScroll() {
11727c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11737c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11747c478bd9Sstevel@tonic-gate		scrolling=0;
11757c478bd9Sstevel@tonic-gate	}
11767c478bd9Sstevel@tonic-gate}
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gatefunction startScroll() {
11797c478bd9Sstevel@tonic-gate	stopScroll();
11807c478bd9Sstevel@tonic-gate	scrolling=1;
11817c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11827c478bd9Sstevel@tonic-gate}
11837c478bd9Sstevel@tonic-gate
11847c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1185daaffb31Sdp
11867c478bd9Sstevel@tonic-gate	switch (b) {
11877c478bd9Sstevel@tonic-gate	    case 1 :
1188daaffb31Sdp		scrollToAnc(-1);
11897c478bd9Sstevel@tonic-gate		break;
11907c478bd9Sstevel@tonic-gate	    case 2 :
1191daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11927c478bd9Sstevel@tonic-gate		break;
11937c478bd9Sstevel@tonic-gate	    case 3 :
11947c478bd9Sstevel@tonic-gate		sfactor=-3;
11957c478bd9Sstevel@tonic-gate		startScroll();
11967c478bd9Sstevel@tonic-gate		break;
11977c478bd9Sstevel@tonic-gate	    case 4 :
11987c478bd9Sstevel@tonic-gate		sfactor=3;
11997c478bd9Sstevel@tonic-gate		startScroll();
12007c478bd9Sstevel@tonic-gate		break;
12017c478bd9Sstevel@tonic-gate	    case 5 :
1202daaffb31Sdp		scrollToAnc(getAncValue() + 1);
12037c478bd9Sstevel@tonic-gate		break;
12047c478bd9Sstevel@tonic-gate	    case 6 :
1205daaffb31Sdp		scrollToAnc(999999);
12067c478bd9Sstevel@tonic-gate		break;
12077c478bd9Sstevel@tonic-gate	}
12087c478bd9Sstevel@tonic-gate}
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
12117c478bd9Sstevel@tonic-gate	stopScroll();
12127c478bd9Sstevel@tonic-gate}
12137c478bd9Sstevel@tonic-gate
1214daaffb31Sdpfunction keypress(ev) {
1215daaffb31Sdp	var keynum;
1216daaffb31Sdp	var keychar;
1217daaffb31Sdp
1218daaffb31Sdp	if (window.event) { // IE
1219daaffb31Sdp		keynum = ev.keyCode;
1220daaffb31Sdp	} else if (ev.which) { // non-IE
1221daaffb31Sdp		keynum = ev.which;
1222daaffb31Sdp	}
1223daaffb31Sdp
1224daaffb31Sdp	keychar = String.fromCharCode(keynum);
1225daaffb31Sdp
1226daaffb31Sdp	if (keychar == "k") {
1227daaffb31Sdp		handlePress(2);
1228daaffb31Sdp		return (0);
1229daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1230daaffb31Sdp		handlePress(5);
1231daaffb31Sdp		return (0);
1232daaffb31Sdp	}
1233daaffb31Sdp	return (1);
1234daaffb31Sdp}
1235daaffb31Sdp
12367c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1237daaffb31Sdp	val = parent.nav.document.diff.display.value;
1238daaffb31Sdp	if (val == "EOF") {
1239daaffb31Sdp		scrollToAnc(999999);
1240daaffb31Sdp		return;
1241daaffb31Sdp	}
1242daaffb31Sdp
1243daaffb31Sdp	if (val == "BOF") {
1244daaffb31Sdp		scrollToAnc(0);
1245daaffb31Sdp		return;
1246daaffb31Sdp	}
1247daaffb31Sdp
1248daaffb31Sdp        i=parseInt(val);
12497c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1250daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12517c478bd9Sstevel@tonic-gate        } else {
1252daaffb31Sdp                scrollToAnc(i);
12537c478bd9Sstevel@tonic-gate        }
12547c478bd9Sstevel@tonic-gate        return false;
12557c478bd9Sstevel@tonic-gate}
12567c478bd9Sstevel@tonic-gate
1257daaffb31SdpEOF
1258daaffb31Sdp}
1259daaffb31Sdp
1260daaffb31Sdp#
1261daaffb31Sdp# frame_navigation
1262daaffb31Sdp#
1263daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1264daaffb31Sdp#
1265daaffb31Sdpfunction frame_navigation
1266daaffb31Sdp{
1267daaffb31Sdp	print "$HTML<head>$STDHEAD"
1268daaffb31Sdp
1269daaffb31Sdp	cat << \EOF
1270daaffb31Sdp<title>Anchor Navigation</title>
1271daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1272daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1273daaffb31Sdp
1274daaffb31Sdp<style type="text/css">
1275daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1276daaffb31Sdp		    background-color: #eee; text-align: center;
1277daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1278daaffb31Sdp    div.button a { font-weight: bold; color: black }
1279daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1280daaffb31Sdp</style>
1281daaffb31SdpEOF
1282daaffb31Sdp
1283cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1284daaffb31Sdp
1285daaffb31Sdp	cat << \EOF
12867c478bd9Sstevel@tonic-gate</head>
1287daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1288daaffb31Sdp	onkeypress="keypress(event);">
12897c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12907c478bd9Sstevel@tonic-gate      <center>
1291cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12927c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12937c478bd9Sstevel@tonic-gate      </center>
12947c478bd9Sstevel@tonic-gate    </noscript>
12957c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1296daaffb31Sdp	<tr>
1297daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1298daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1299daaffb31Sdp          at right</td>
1300daaffb31Sdp	  <td align="center" valign="top" width="50%">
13017c478bd9Sstevel@tonic-gate	    <div class="button">
1302daaffb31Sdp	      <table border="0" align="center">
1303daaffb31Sdp                  <tr>
1304daaffb31Sdp		    <td>
13057c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
13067c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
13077c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
13087c478bd9Sstevel@tonic-gate			 onClick="return false;"
13097c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1310daaffb31Sdp		    <td>
13117c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13127c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13137c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13147c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1315daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1316daaffb31Sdp		    <td>
13177c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13187c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13197c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13207c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13217c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13227c478bd9Sstevel@tonic-gate		    </td></tr>
1323daaffb31Sdp
13247c478bd9Sstevel@tonic-gate		  <tr>
1325daaffb31Sdp		    <td>
13267c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13277c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13287c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13297c478bd9Sstevel@tonic-gate			 onClick="return false;"
13307c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1331daaffb31Sdp		    <td>
13327c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13337c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13347c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13357c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1336daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1337daaffb31Sdp		    <td>
13387c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13397c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13407c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13417c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13427c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1343daaffb31Sdp		  </tr>
1344daaffb31Sdp              </table>
1345daaffb31Sdp	    </div>
1346daaffb31Sdp	  </td>
13477c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1348daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1349cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1350cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13517c478bd9Sstevel@tonic-gate	    </form>
13527c478bd9Sstevel@tonic-gate	  </th>
1353daaffb31Sdp	</tr>
13547c478bd9Sstevel@tonic-gate    </table>
13557c478bd9Sstevel@tonic-gate  </body>
13567c478bd9Sstevel@tonic-gate</html>
13577c478bd9Sstevel@tonic-gateEOF
13587c478bd9Sstevel@tonic-gate}
13597c478bd9Sstevel@tonic-gate
13607c478bd9Sstevel@tonic-gate
1361daaffb31Sdp
1362daaffb31Sdp#
1363daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1364daaffb31Sdp#
1365daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1366daaffb31Sdp# context or unified diffs.
1367daaffb31Sdp#
13687c478bd9Sstevel@tonic-gatediff_to_html()
13697c478bd9Sstevel@tonic-gate{
13707c478bd9Sstevel@tonic-gate	TNAME=$1
1371daaffb31Sdp	TPATH=$2
1372daaffb31Sdp	DIFFTYPE=$3
1373daaffb31Sdp	COMMENT=$4
1374daaffb31Sdp
1375daaffb31Sdp	print "$HTML<head>$STDHEAD"
1376daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1377daaffb31Sdp
1378daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1379daaffb31Sdp		print "$UDIFFCSS"
1380daaffb31Sdp	fi
1381daaffb31Sdp
1382daaffb31Sdp	cat <<-EOF
1383daaffb31Sdp	</head>
1384daaffb31Sdp	<body id="SUNWwebrev">
1385daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1386daaffb31Sdp	<pre>$COMMENT</pre>
1387daaffb31Sdp        <pre>
1388daaffb31Sdp	EOF
13897c478bd9Sstevel@tonic-gate
1390cdf0c1d5Smjnelson	html_quote | $AWK '
1391daaffb31Sdp	/^--- new/	{ next }
1392daaffb31Sdp	/^\+\+\+ new/	{ next }
1393daaffb31Sdp	/^--- old/	{ next }
1394daaffb31Sdp	/^\*\*\* old/	{ next }
1395daaffb31Sdp	/^\*\*\*\*/	{ next }
13967c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1397cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1398daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1399daaffb31Sdp			  next}
1400daaffb31Sdp
1401cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1402daaffb31Sdp			  next}
1403daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1404daaffb31Sdp			  next}
1405daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1406daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1407daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1408daaffb31Sdp			{printf "%s\n", $0; next}
14097c478bd9Sstevel@tonic-gate	'
1410daaffb31Sdp
1411daaffb31Sdp	print "</pre></body></html>\n"
14127c478bd9Sstevel@tonic-gate}
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate
1415daaffb31Sdp#
1416daaffb31Sdp# source_to_html { new | old } <filename>
1417daaffb31Sdp#
1418daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1419daaffb31Sdp#
14207c478bd9Sstevel@tonic-gatesource_to_html()
14217c478bd9Sstevel@tonic-gate{
14227c478bd9Sstevel@tonic-gate	WHICH=$1
14237c478bd9Sstevel@tonic-gate	TNAME=$2
14247c478bd9Sstevel@tonic-gate
1425daaffb31Sdp	print "$HTML<head>$STDHEAD"
1426cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1427daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1428daaffb31Sdp	print "<pre>"
1429cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1430daaffb31Sdp	print "</pre></body></html>"
14317c478bd9Sstevel@tonic-gate}
14327c478bd9Sstevel@tonic-gate
1433daaffb31Sdp#
1434cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1435daaffb31Sdp#
1436daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1437daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1438daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1439daaffb31Sdp# delta in that list (the first delta unique to the child).
14407c478bd9Sstevel@tonic-gate#
14417c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1442daaffb31Sdp#
1443daaffb31Sdpcomments_from_teamware()
14447c478bd9Sstevel@tonic-gate{
1445daaffb31Sdp	fmt=$1
1446daaffb31Sdp	pfile=$PWS/$2
1447daaffb31Sdp	cfile=$CWS/$3
14487c478bd9Sstevel@tonic-gate
1449cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1450cdf0c1d5Smjnelson		pfile=$RWS/$2
1451cdf0c1d5Smjnelson	fi
1452cdf0c1d5Smjnelson
1453daaffb31Sdp	if [[ -f $pfile ]]; then
1454cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14557c478bd9Sstevel@tonic-gate	else
14567c478bd9Sstevel@tonic-gate		psid=1.1
14577c478bd9Sstevel@tonic-gate	fi
14587c478bd9Sstevel@tonic-gate
1459cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14607c478bd9Sstevel@tonic-gate	N=${#sids[@]}
14617c478bd9Sstevel@tonic-gate
1462daaffb31Sdp	nawkprg='
1463daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1464daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1465daaffb31Sdp		NF == 0u	{ continue }
1466daaffb31Sdp		{if (p==0) continue; print $0 }'
1467daaffb31Sdp
14687c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
14697c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14707c478bd9Sstevel@tonic-gate
1471daaffb31Sdp		if [[ $fmt == "text" ]]; then
1472cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1473cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1474daaffb31Sdp			return
1475daaffb31Sdp		fi
1476daaffb31Sdp
1477cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
14780fd2682eSMark J. Nelson		    html_quote | its2url | $AWK "$nawkprg"
14797c478bd9Sstevel@tonic-gate	fi
14807c478bd9Sstevel@tonic-gate}
14817c478bd9Sstevel@tonic-gate
1482daaffb31Sdp#
1483cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1484daaffb31Sdp#
1485cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1486cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1487cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1488cdf0c1d5Smjnelson# are turned into URLs.
1489cdf0c1d5Smjnelson#
1490cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1491daaffb31Sdp#
1492daaffb31Sdpcomments_from_wx()
14937c478bd9Sstevel@tonic-gate{
1494daaffb31Sdp	typeset fmt=$1
1495daaffb31Sdp	typeset p=$2
14967c478bd9Sstevel@tonic-gate
1497cdf0c1d5Smjnelson	comm=`$AWK '
1498daaffb31Sdp	$1 == "'$p'" {
14997c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
15007c478bd9Sstevel@tonic-gate		getline
15017c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
15027c478bd9Sstevel@tonic-gate		exit
1503daaffb31Sdp	}' < $wxfile`
1504daaffb31Sdp
1505cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1506cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1507cdf0c1d5Smjnelson	fi
1508cdf0c1d5Smjnelson
1509daaffb31Sdp	if [[ $fmt == "text" ]]; then
1510cdf0c1d5Smjnelson		print -- "$comm"
1511daaffb31Sdp		return
1512daaffb31Sdp	fi
1513daaffb31Sdp
15140fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1515cdf0c1d5Smjnelson
15167c478bd9Sstevel@tonic-gate}
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate#
1519daaffb31Sdp# getcomments {text|html} filepath parentpath
1520daaffb31Sdp#
1521daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1522daaffb31Sdp#
1523daaffb31Sdpgetcomments()
1524daaffb31Sdp{
1525daaffb31Sdp	typeset fmt=$1
1526daaffb31Sdp	typeset p=$2
1527daaffb31Sdp	typeset pp=$3
15287c478bd9Sstevel@tonic-gate
15293df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15303df69ef3SDarren Moffat		return
15313df69ef3SDarren Moffat	fi
1532cdf0c1d5Smjnelson	#
1533cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1534cdf0c1d5Smjnelson	# will be used there, too
1535cdf0c1d5Smjnelson	#
1536daaffb31Sdp	if [[ -n $wxfile ]]; then
1537daaffb31Sdp		comments_from_wx $fmt $p
1538daaffb31Sdp	else
1539daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1540daaffb31Sdp			comments_from_teamware $fmt $pp $p
1541daaffb31Sdp		fi
1542daaffb31Sdp	fi
1543daaffb31Sdp}
1544daaffb31Sdp
1545daaffb31Sdp#
1546daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1547daaffb31Sdp#
1548daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1549daaffb31Sdp#
1550daaffb31Sdpfunction printCI
1551daaffb31Sdp{
1552daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1553daaffb31Sdp	typeset str
1554daaffb31Sdp	if (( tot == 1 )); then
1555daaffb31Sdp		str="line"
1556daaffb31Sdp	else
1557daaffb31Sdp		str="lines"
1558daaffb31Sdp	fi
1559daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1560daaffb31Sdp	    $tot $str $ins $del $mod $unc
1561daaffb31Sdp}
1562daaffb31Sdp
1563daaffb31Sdp
1564daaffb31Sdp#
1565daaffb31Sdp# difflines <oldfile> <newfile>
1566daaffb31Sdp#
1567daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1568daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1569daaffb31Sdp#
15707c478bd9Sstevel@tonic-gatefunction difflines
15717c478bd9Sstevel@tonic-gate{
1572daaffb31Sdp	integer tot mod del ins unc err
15737c478bd9Sstevel@tonic-gate	typeset filename
15747c478bd9Sstevel@tonic-gate
1575cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1576daaffb31Sdp	# Change range of lines: N,Nc
15777c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15787c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15797c478bd9Sstevel@tonic-gate		if (n != 2) {
15807c478bd9Sstevel@tonic-gate		    error=2
15817c478bd9Sstevel@tonic-gate		    exit;
15827c478bd9Sstevel@tonic-gate		}
1583daaffb31Sdp		#
1584daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1585daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1586daaffb31Sdp		#
15877c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1588daaffb31Sdp
1589daaffb31Sdp		#
1590daaffb31Sdp		# Now count replacement lines: each represents a change instead
1591daaffb31Sdp		# of a delete, so increment c and decrement r.
1592daaffb31Sdp		#
15937c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15947c478bd9Sstevel@tonic-gate			c++;
15957c478bd9Sstevel@tonic-gate			r--;
15967c478bd9Sstevel@tonic-gate		}
1597daaffb31Sdp		#
1598daaffb31Sdp		# If there were more replacement lines than original lines,
1599daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1600daaffb31Sdp		# but there are r changes that should be counted as adds, and
1601daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1602daaffb31Sdp		#
16037c478bd9Sstevel@tonic-gate		if (r < 0) {
16047c478bd9Sstevel@tonic-gate			a-=r;
16057c478bd9Sstevel@tonic-gate			c+=r;
16067c478bd9Sstevel@tonic-gate		}
1607daaffb31Sdp
1608daaffb31Sdp		#
1609daaffb31Sdp		# If there were more original lines than replacement lines, then
1610daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1611daaffb31Sdp		#
16127c478bd9Sstevel@tonic-gate		if (r > 0) {
16137c478bd9Sstevel@tonic-gate			d+=r;
16147c478bd9Sstevel@tonic-gate		}
16157c478bd9Sstevel@tonic-gate		next;
16167c478bd9Sstevel@tonic-gate	}
16177c478bd9Sstevel@tonic-gate
1618daaffb31Sdp	# Change lines: Nc
16197c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1620daaffb31Sdp		# The first line is a replacement; any more are additions.
16217c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16227c478bd9Sstevel@tonic-gate			c++;
16237c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16247c478bd9Sstevel@tonic-gate		}
16257c478bd9Sstevel@tonic-gate		next;
16267c478bd9Sstevel@tonic-gate	}
16277c478bd9Sstevel@tonic-gate
1628daaffb31Sdp	# Add lines: both Na and N,Na
16297c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16307c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16317c478bd9Sstevel@tonic-gate		next;
16327c478bd9Sstevel@tonic-gate	}
16337c478bd9Sstevel@tonic-gate
1634daaffb31Sdp	# Delete range of lines: N,Nd
16357c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16367c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16377c478bd9Sstevel@tonic-gate		if (n != 2) {
16387c478bd9Sstevel@tonic-gate			error=2
16397c478bd9Sstevel@tonic-gate			exit;
16407c478bd9Sstevel@tonic-gate		}
1641daaffb31Sdp		#
1642daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1643daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1644daaffb31Sdp		#
16457c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16467c478bd9Sstevel@tonic-gate		d+=r;
16477c478bd9Sstevel@tonic-gate		next;
16487c478bd9Sstevel@tonic-gate	}
16497c478bd9Sstevel@tonic-gate
1650daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16517c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16527c478bd9Sstevel@tonic-gate
1653daaffb31Sdp	# Should not get here!
16547c478bd9Sstevel@tonic-gate	{
16557c478bd9Sstevel@tonic-gate		error=1;
16567c478bd9Sstevel@tonic-gate		exit;
16577c478bd9Sstevel@tonic-gate	}
16587c478bd9Sstevel@tonic-gate
1659daaffb31Sdp	# Finish off - print results
16607c478bd9Sstevel@tonic-gate	END {
1661daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16627c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16637c478bd9Sstevel@tonic-gate	}' )
16647c478bd9Sstevel@tonic-gate
1665cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16667c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1667daaffb31Sdp		print "Unexpected Error occurred reading" \
1668daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1669daaffb31Sdp		return
1670daaffb31Sdp	fi
1671daaffb31Sdp
16727c478bd9Sstevel@tonic-gate	# Accumulate totals
16737c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1674daaffb31Sdp	(( TMOD += mod ))
16757c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16767c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16777c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1678cdf0c1d5Smjnelson	unc=`wc -l < $1`
16797c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1680daaffb31Sdp		(( unc -= del + mod ))
16817c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16827c478bd9Sstevel@tonic-gate	fi
16837c478bd9Sstevel@tonic-gate	# print summary
1684daaffb31Sdp	print "<span class=\"lineschanged\">"
1685daaffb31Sdp	printCI $tot $ins $del $mod $unc
1686daaffb31Sdp	print "</span>"
16877c478bd9Sstevel@tonic-gate}
16887c478bd9Sstevel@tonic-gate
1689daaffb31Sdp
16907c478bd9Sstevel@tonic-gate#
1691daaffb31Sdp# flist_from_wx
1692daaffb31Sdp#
1693daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1694daaffb31Sdp# Sets the global 'wxfile' variable.
1695daaffb31Sdp#
1696daaffb31Sdpfunction flist_from_wx
16977c478bd9Sstevel@tonic-gate{
1698daaffb31Sdp	typeset argfile=$1
1699daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1700daaffb31Sdp		#
1701daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1702daaffb31Sdp		# because the webrev does a "cd" later on.
1703daaffb31Sdp		#
1704daaffb31Sdp		wxfile=$PWD/$argfile
17057c478bd9Sstevel@tonic-gate	else
1706daaffb31Sdp		wxfile=$argfile
17077c478bd9Sstevel@tonic-gate	fi
17087c478bd9Sstevel@tonic-gate
1709cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
17107c478bd9Sstevel@tonic-gate	  while (getline) {
17117c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
17127c478bd9Sstevel@tonic-gate		if (c > 0) print
17137c478bd9Sstevel@tonic-gate	  }
1714daaffb31Sdp	}' $wxfile > $FLIST
17157c478bd9Sstevel@tonic-gate
1716daaffb31Sdp	print " Done."
1717daaffb31Sdp}
17187c478bd9Sstevel@tonic-gate
1719daaffb31Sdp#
1720daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1721daaffb31Sdp#
1722daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1723daaffb31Sdp# names may come from the "update/create" messages and others from the
1724daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1725daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1726daaffb31Sdp# -n as well, but remove them if they are already defined.
1727daaffb31Sdp#
1728daaffb31Sdpfunction flist_from_teamware
1729daaffb31Sdp{
1730cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1731daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1732daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1733daaffb31Sdp			    "valid teamware workspace"
17347c478bd9Sstevel@tonic-gate			exit 1
17357c478bd9Sstevel@tonic-gate		fi
1736daaffb31Sdp		parent_args="-p $codemgr_parent"
17377c478bd9Sstevel@tonic-gate	fi
17387c478bd9Sstevel@tonic-gate
1739daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17407c478bd9Sstevel@tonic-gate
1741daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1742cdf0c1d5Smjnelson	    $AWK '
1743daaffb31Sdp		/^update:|^create:/	{print $2}
1744daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1745daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1746daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1747daaffb31Sdp		NF == 0			{p=0 ; continue}
1748daaffb31Sdp		/^rename/		{old=$3}
1749daaffb31Sdp		$1 == "to:"		{print $2, old}
1750daaffb31Sdp		/^"/			{continue}
1751daaffb31Sdp		p == 1			{print $1}' |
1752daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17537c478bd9Sstevel@tonic-gate
1754daaffb31Sdp	print " Done."
1755daaffb31Sdp}
1756daaffb31Sdp
1757cdf0c1d5Smjnelson#
1758cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1759cdf0c1d5Smjnelson#
1760cdf0c1d5Smjnelsonfunction hg_active_wxfile
1761cdf0c1d5Smjnelson{
1762cdf0c1d5Smjnelson	typeset child=$1
1763cdf0c1d5Smjnelson	typeset parent=$2
1764cdf0c1d5Smjnelson
1765cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17669a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1767cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1768cdf0c1d5Smjnelson}
1769cdf0c1d5Smjnelson
1770cdf0c1d5Smjnelson#
1771cdf0c1d5Smjnelson# flist_from_mercurial
1772cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1773cdf0c1d5Smjnelson# flist_from_wx
1774cdf0c1d5Smjnelson#
1775cdf0c1d5Smjnelsonfunction flist_from_mercurial
1776cdf0c1d5Smjnelson{
1777cdf0c1d5Smjnelson	typeset child=$1
1778cdf0c1d5Smjnelson	typeset parent=$2
1779cdf0c1d5Smjnelson
1780cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1781cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1782cdf0c1d5Smjnelson		print		# Blank line for the \c above
1783cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1784cdf0c1d5Smjnelson		exit 1
1785cdf0c1d5Smjnelson	fi
1786cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1787cdf0c1d5Smjnelson
1788cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1789cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1790cdf0c1d5Smjnelson}
1791cdf0c1d5Smjnelson
1792cdf0c1d5Smjnelson#
1793*8bcea973SRichard Lowe# Transform a specified 'git log' output format into a wx-like active list.
1794*8bcea973SRichard Lowe#
1795*8bcea973SRichard Lowefunction git_wxfile
1796*8bcea973SRichard Lowe{
1797*8bcea973SRichard Lowe	typeset child="$1"
1798*8bcea973SRichard Lowe	typeset parent="$2"
1799*8bcea973SRichard Lowe
1800*8bcea973SRichard Lowe	TMPFLIST=/tmp/$$.active
1801*8bcea973SRichard Lowe	$PERL -e 'my (%files, %realfiles, $msg);
1802*8bcea973SRichard Lowe	my $branch = $ARGV[0];
1803*8bcea973SRichard Lowe
1804*8bcea973SRichard Lowe	open(F, "git diff -M --name-status $branch |");
1805*8bcea973SRichard Lowe	while (<F>) {
1806*8bcea973SRichard Lowe	    chomp;
1807*8bcea973SRichard Lowe	    if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
1808*8bcea973SRichard Lowe		if ($1 >= 75) {			 # Probably worth treating as a rename
1809*8bcea973SRichard Lowe		    $realfiles{$3} = $2
1810*8bcea973SRichard Lowe		} else {
1811*8bcea973SRichard Lowe		    $realfiles{$3} = $3;
1812*8bcea973SRichard Lowe		    $realfiles{$2} = $2;
1813*8bcea973SRichard Lowe		}
1814*8bcea973SRichard Lowe	    } else {
1815*8bcea973SRichard Lowe		my $f = (split /\s+/, $_)[1];
1816*8bcea973SRichard Lowe		$realfiles{$f} = $f;
1817*8bcea973SRichard Lowe	    }
1818*8bcea973SRichard Lowe	}
1819*8bcea973SRichard Lowe	close(F);
1820*8bcea973SRichard Lowe
1821*8bcea973SRichard Lowe	my $state = 1;		    # 0|comments, 1|files
1822*8bcea973SRichard Lowe	open(F, "git whatchanged --pretty=format:%B $branch.. |");
1823*8bcea973SRichard Lowe	while (<F>) {
1824*8bcea973SRichard Lowe	    chomp;
1825*8bcea973SRichard Lowe	    if (/^:[0-9]{6}/) {
1826*8bcea973SRichard Lowe		my $fname = (split /\t/, $_)[1];
1827*8bcea973SRichard Lowe		next if !defined($realfiles{$fname}); # No real change
1828*8bcea973SRichard Lowe		$state = 1;
1829*8bcea973SRichard Lowe		$files{$fname} = $msg;
1830*8bcea973SRichard Lowe	    } else {
1831*8bcea973SRichard Lowe		if ($state == 1) {
1832*8bcea973SRichard Lowe		    $state = 0;
1833*8bcea973SRichard Lowe		    $msg = /^\n/ ? "" : "\n";
1834*8bcea973SRichard Lowe		}
1835*8bcea973SRichard Lowe		$msg .= "$_\n" if ($_);
1836*8bcea973SRichard Lowe	    }
1837*8bcea973SRichard Lowe	}
1838*8bcea973SRichard Lowe	close(F);
1839*8bcea973SRichard Lowe
1840*8bcea973SRichard Lowe	for (sort keys %files) {
1841*8bcea973SRichard Lowe	    if ($realfiles{$_} ne $_) {
1842*8bcea973SRichard Lowe		print "$_ $realfiles{$_}\n$files{$_}\n";
1843*8bcea973SRichard Lowe	    } else {
1844*8bcea973SRichard Lowe		print "$_\n$files{$_}\n"
1845*8bcea973SRichard Lowe	    }
1846*8bcea973SRichard Lowe	}' ${parent} > $TMPFLIST
1847*8bcea973SRichard Lowe
1848*8bcea973SRichard Lowe	wxfile=$TMPFLIST
1849*8bcea973SRichard Lowe}
1850*8bcea973SRichard Lowe
1851*8bcea973SRichard Lowe#
1852*8bcea973SRichard Lowe# flist_from_git
1853*8bcea973SRichard Lowe# Build a wx-style active list, and hand it off to flist_from_wx
1854*8bcea973SRichard Lowe#
1855*8bcea973SRichard Lowefunction flist_from_git
1856*8bcea973SRichard Lowe{
1857*8bcea973SRichard Lowe	typeset child=$1
1858*8bcea973SRichard Lowe	typeset parent=$2
1859*8bcea973SRichard Lowe
1860*8bcea973SRichard Lowe	print " File list from: git ...\c"
1861*8bcea973SRichard Lowe	git_wxfile "$child" "$parent";
1862*8bcea973SRichard Lowe
1863*8bcea973SRichard Lowe	# flist_from_wx prints the Done, so we don't have to.
1864*8bcea973SRichard Lowe	flist_from_wx $TMPFLIST
1865*8bcea973SRichard Lowe}
1866*8bcea973SRichard Lowe
1867*8bcea973SRichard Lowe#
1868cdf0c1d5Smjnelson# flist_from_subversion
1869cdf0c1d5Smjnelson#
1870cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1871cdf0c1d5Smjnelson#
1872cdf0c1d5Smjnelsonfunction flist_from_subversion
1873cdf0c1d5Smjnelson{
1874cdf0c1d5Smjnelson	CWS=$1
1875cdf0c1d5Smjnelson	OLDPWD=$2
1876cdf0c1d5Smjnelson
1877cdf0c1d5Smjnelson	cd $CWS
1878cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1879cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1880cdf0c1d5Smjnelson	print -u2 " Done."
1881cdf0c1d5Smjnelson	cd $OLDPWD
1882cdf0c1d5Smjnelson}
1883cdf0c1d5Smjnelson
1884daaffb31Sdpfunction env_from_flist
1885daaffb31Sdp{
1886daaffb31Sdp	[[ -r $FLIST ]] || return
1887daaffb31Sdp
1888daaffb31Sdp	#
1889daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1890daaffb31Sdp	# list.  Then copy those into our local versions of those
1891daaffb31Sdp	# variables if they have not been set already.
1892daaffb31Sdp	#
1893b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18947c478bd9Sstevel@tonic-gate
1895cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1896cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1897cdf0c1d5Smjnelson		export CODEMGR_WS
1898cdf0c1d5Smjnelson	fi
18997c478bd9Sstevel@tonic-gate
1900daaffb31Sdp	#
1901daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1902daaffb31Sdp	#
1903cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1904daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1905cdf0c1d5Smjnelson		export CODEMGR_PARENT
1906daaffb31Sdp	fi
1907daaffb31Sdp}
1908daaffb31Sdp
190914983201Sdpfunction look_for_prog
191014983201Sdp{
191114983201Sdp	typeset path
191214983201Sdp	typeset ppath
191314983201Sdp	typeset progname=$1
191414983201Sdp
191514983201Sdp	ppath=$PATH
191614983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
191714983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1918cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
191914983201Sdp
192014983201Sdp	PATH=$ppath prog=`whence $progname`
192114983201Sdp	if [[ -n $prog ]]; then
192214983201Sdp		print $prog
192314983201Sdp	fi
192414983201Sdp}
192514983201Sdp
1926cdf0c1d5Smjnelsonfunction get_file_mode
1927cdf0c1d5Smjnelson{
1928cdf0c1d5Smjnelson	$PERL -e '
1929cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1930cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1931cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1932cdf0c1d5Smjnelson			exit 0;
1933cdf0c1d5Smjnelson		} else {
1934cdf0c1d5Smjnelson			exit 1;
1935cdf0c1d5Smjnelson		}
1936cdf0c1d5Smjnelson	    ' $1
1937cdf0c1d5Smjnelson}
1938cdf0c1d5Smjnelson
1939cdf0c1d5Smjnelsonfunction build_old_new_teamware
1940cdf0c1d5Smjnelson{
1941cdf0c1d5Smjnelson	typeset olddir="$1"
1942cdf0c1d5Smjnelson	typeset newdir="$2"
1943cdf0c1d5Smjnelson
1944cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1945cdf0c1d5Smjnelson	# get a readonly copy.
1946cdf0c1d5Smjnelson
1947cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1948cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1949cdf0c1d5Smjnelson	fi
1950cdf0c1d5Smjnelson
1951cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1952cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1953cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1954cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1955cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1956cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1957cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1958cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1959cdf0c1d5Smjnelson	# permissions that would result after check in.
1960cdf0c1d5Smjnelson
1961cdf0c1d5Smjnelson	#
1962cdf0c1d5Smjnelson	# Snag new version of file.
1963cdf0c1d5Smjnelson	#
1964cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1965cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1966cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1967cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1968cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1969cdf0c1d5Smjnelson	fi
1970cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1971cdf0c1d5Smjnelson
1972cdf0c1d5Smjnelson	#
1973cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1974cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1975cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1976cdf0c1d5Smjnelson	#
1977cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1978cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1979cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1980cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1981cdf0c1d5Smjnelson		# the old file.
1982cdf0c1d5Smjnelson
1983cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1984cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1985cdf0c1d5Smjnelson	else
1986cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1987cdf0c1d5Smjnelson			real_parent=$PWS
1988cdf0c1d5Smjnelson		else
1989cdf0c1d5Smjnelson			real_parent=$RWS
1990cdf0c1d5Smjnelson		fi
1991cdf0c1d5Smjnelson
1992cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1993cdf0c1d5Smjnelson
1994cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1995cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1996cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1997cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1998cdf0c1d5Smjnelson			else
1999cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
2000cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
2001cdf0c1d5Smjnelson			fi
2002cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
2003cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
2004cdf0c1d5Smjnelson		fi
2005cdf0c1d5Smjnelson	fi
2006cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
2007cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
2008cdf0c1d5Smjnelson	fi
2009cdf0c1d5Smjnelson}
2010cdf0c1d5Smjnelson
2011cdf0c1d5Smjnelsonfunction build_old_new_mercurial
2012cdf0c1d5Smjnelson{
2013cdf0c1d5Smjnelson	typeset olddir="$1"
2014cdf0c1d5Smjnelson	typeset newdir="$2"
2015cdf0c1d5Smjnelson	typeset old_mode=
2016cdf0c1d5Smjnelson	typeset new_mode=
2017cdf0c1d5Smjnelson	typeset file
2018cdf0c1d5Smjnelson
2019cdf0c1d5Smjnelson	#
2020cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
2021cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
2022cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
2023cdf0c1d5Smjnelson	#
2024cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
2025cdf0c1d5Smjnelson		file="$PF"
2026cdf0c1d5Smjnelson	else
2027cdf0c1d5Smjnelson		file="$PDIR/$PF"
2028cdf0c1d5Smjnelson	fi
2029b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
2030cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
2031b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
2032cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
2033cdf0c1d5Smjnelson
2034cdf0c1d5Smjnelson	#
2035cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
2036cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
2037cdf0c1d5Smjnelson	#
2038cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
2039cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
2040cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
2041cdf0c1d5Smjnelson			new_mode=755
2042cdf0c1d5Smjnelson		else
2043cdf0c1d5Smjnelson			new_mode=644
2044cdf0c1d5Smjnelson		fi
2045cdf0c1d5Smjnelson	fi
2046cdf0c1d5Smjnelson
2047cdf0c1d5Smjnelson	#
2048cdf0c1d5Smjnelson	# new version of the file.
2049cdf0c1d5Smjnelson	#
2050cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
2051cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
2052cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
2053cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
2054cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
2055cdf0c1d5Smjnelson		else
2056cdf0c1d5Smjnelson			# should never happen
2057cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
2058cdf0c1d5Smjnelson		fi
2059cdf0c1d5Smjnelson	fi
2060cdf0c1d5Smjnelson
2061cdf0c1d5Smjnelson	#
2062cdf0c1d5Smjnelson	# parent's version of the file
2063cdf0c1d5Smjnelson	#
2064cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
2065cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
2066cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
2067cdf0c1d5Smjnelson	#
2068cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
2069cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2070cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
2071cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
2072cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
2073cdf0c1d5Smjnelson
207402d26c39SVladimir Kotal		if (( $? != 0 )); then
2075cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
2076cdf0c1d5Smjnelson		else
2077cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
2078cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
2079cdf0c1d5Smjnelson			else
2080cdf0c1d5Smjnelson				# should never happen
2081cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
2082cdf0c1d5Smjnelson			fi
2083cdf0c1d5Smjnelson		fi
2084cdf0c1d5Smjnelson	fi
2085cdf0c1d5Smjnelson}
2086cdf0c1d5Smjnelson
2087*8bcea973SRichard Lowefunction build_old_new_git
2088*8bcea973SRichard Lowe{
2089*8bcea973SRichard Lowe	typeset olddir="$1"
2090*8bcea973SRichard Lowe	typeset newdir="$2"
2091*8bcea973SRichard Lowe	typeset o_mode=
2092*8bcea973SRichard Lowe	typeset n_mode=
2093*8bcea973SRichard Lowe	typeset o_object=
2094*8bcea973SRichard Lowe	typeset n_object=
2095*8bcea973SRichard Lowe	typeset OWD=$PWD
2096*8bcea973SRichard Lowe	typeset file
2097*8bcea973SRichard Lowe	typeset type
2098*8bcea973SRichard Lowe
2099*8bcea973SRichard Lowe	cd $CWS
2100*8bcea973SRichard Lowe
2101*8bcea973SRichard Lowe	#
2102*8bcea973SRichard Lowe	# Get old file and its mode from the git object tree
2103*8bcea973SRichard Lowe	#
2104*8bcea973SRichard Lowe	if [[ "$PDIR" == "." ]]; then
2105*8bcea973SRichard Lowe		file="$PF"
2106*8bcea973SRichard Lowe	else
2107*8bcea973SRichard Lowe	       file="$PDIR/$PF"
2108*8bcea973SRichard Lowe	fi
2109*8bcea973SRichard Lowe
2110*8bcea973SRichard Lowe	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
2111*8bcea973SRichard Lowe		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2112*8bcea973SRichard Lowe	else
2113*8bcea973SRichard Lowe                $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk
2114*8bcea973SRichard Lowe                $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null
2115*8bcea973SRichard Lowe
2116*8bcea973SRichard Lowe                if (( $? != 0 )); then
2117*8bcea973SRichard Lowe                        rm -f $olddir/$file
2118*8bcea973SRichard Lowe                elif [[ -n $o_mode ]]; then
2119*8bcea973SRichard Lowe                        # Strip the first 3 digits, to get a regular octal mode
2120*8bcea973SRichard Lowe                        o_mode=${o_mode/???/}
2121*8bcea973SRichard Lowe                        chmod $o_mode $olddir/$file
2122*8bcea973SRichard Lowe                else
2123*8bcea973SRichard Lowe                        # should never happen
2124*8bcea973SRichard Lowe                        print -u2 "ERROR: set mode of $olddir/$file"
2125*8bcea973SRichard Lowe                fi
2126*8bcea973SRichard Lowe	fi
2127*8bcea973SRichard Lowe
2128*8bcea973SRichard Lowe	#
2129*8bcea973SRichard Lowe	# new version of the file.
2130*8bcea973SRichard Lowe	#
2131*8bcea973SRichard Lowe	if [[ "$DIR" == "." ]]; then
2132*8bcea973SRichard Lowe		file="$F"
2133*8bcea973SRichard Lowe	else
2134*8bcea973SRichard Lowe		file="$DIR/$F"
2135*8bcea973SRichard Lowe	fi
2136*8bcea973SRichard Lowe	rm -rf $newdir/$file
2137*8bcea973SRichard Lowe
2138*8bcea973SRichard Lowe        if [[ -e $CWS/$DIR/$F ]]; then
2139*8bcea973SRichard Lowe            cp $CWS/$DIR/$F $newdir/$DIR/$F
2140*8bcea973SRichard Lowe            chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F
2141*8bcea973SRichard Lowe        fi
2142*8bcea973SRichard Lowe	cd $OWD
2143*8bcea973SRichard Lowe}
2144*8bcea973SRichard Lowe
2145cdf0c1d5Smjnelsonfunction build_old_new_subversion
2146cdf0c1d5Smjnelson{
2147cdf0c1d5Smjnelson	typeset olddir="$1"
2148cdf0c1d5Smjnelson	typeset newdir="$2"
2149cdf0c1d5Smjnelson
2150cdf0c1d5Smjnelson	# Snag new version of file.
2151cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2152cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2153cdf0c1d5Smjnelson
2154cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2155cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2156cdf0c1d5Smjnelson	else
2157cdf0c1d5Smjnelson		# Get the parent's version of the file.
2158cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2159cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2160cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2161cdf0c1d5Smjnelson		fi
2162cdf0c1d5Smjnelson	fi
2163cdf0c1d5Smjnelson}
2164cdf0c1d5Smjnelson
2165cdf0c1d5Smjnelsonfunction build_old_new_unknown
2166cdf0c1d5Smjnelson{
2167cdf0c1d5Smjnelson	typeset olddir="$1"
2168cdf0c1d5Smjnelson	typeset newdir="$2"
2169cdf0c1d5Smjnelson
2170cdf0c1d5Smjnelson	#
2171cdf0c1d5Smjnelson	# Snag new version of file.
2172cdf0c1d5Smjnelson	#
2173cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2174cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2175cdf0c1d5Smjnelson
2176cdf0c1d5Smjnelson	#
2177cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2178cdf0c1d5Smjnelson	#
2179cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2180cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2181cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2182cdf0c1d5Smjnelson	fi
2183cdf0c1d5Smjnelson}
2184cdf0c1d5Smjnelson
2185cdf0c1d5Smjnelsonfunction build_old_new
2186cdf0c1d5Smjnelson{
2187cdf0c1d5Smjnelson	typeset WDIR=$1
2188cdf0c1d5Smjnelson	typeset PWS=$2
2189cdf0c1d5Smjnelson	typeset PDIR=$3
2190cdf0c1d5Smjnelson	typeset PF=$4
2191cdf0c1d5Smjnelson	typeset CWS=$5
2192cdf0c1d5Smjnelson	typeset DIR=$6
2193cdf0c1d5Smjnelson	typeset F=$7
2194cdf0c1d5Smjnelson
2195cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2196cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2197cdf0c1d5Smjnelson
2198cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2199cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2200cdf0c1d5Smjnelson
2201cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2202cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
2203cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
2204cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
2205*8bcea973SRichard Lowe	elif [[ $SCM_MODE == "git" ]]; then
2206*8bcea973SRichard Lowe		build_old_new_git "$olddir" "$newdir"
2207cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2208cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2209cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2210cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2211cdf0c1d5Smjnelson	fi
2212cdf0c1d5Smjnelson
2213cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2214cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2215cdf0c1d5Smjnelson		return 1
2216cdf0c1d5Smjnelson	fi
2217cdf0c1d5Smjnelson	return 0
2218cdf0c1d5Smjnelson}
2219cdf0c1d5Smjnelson
2220cdf0c1d5Smjnelson
2221daaffb31Sdp#
2222daaffb31Sdp# Usage message.
2223daaffb31Sdp#
2224daaffb31Sdpfunction usage
2225daaffb31Sdp{
2226daaffb31Sdp	print 'Usage:\twebrev [common-options]
2227daaffb31Sdp	webrev [common-options] ( <file> | - )
2228daaffb31Sdp	webrev [common-options] -w <wx file>
2229daaffb31Sdp
2230daaffb31SdpOptions:
22310fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2232ba44d8a2SVladimir Kotal	-D: delete remote webrev
2233daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
22340fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2235ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2236ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2237daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2238daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
223902d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
224002d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2241daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2242daaffb31Sdp
2243daaffb31SdpEnvironment:
2244daaffb31Sdp	WDIR: Control the output directory.
2245ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2246daaffb31Sdp
2247cdf0c1d5SmjnelsonSCM Specific Options:
2248cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
2249cdf0c1d5Smjnelson
2250daaffb31SdpSCM Environment:
2251cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2252cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2253daaffb31Sdp'
2254daaffb31Sdp
2255daaffb31Sdp	exit 2
2256daaffb31Sdp}
2257daaffb31Sdp
2258daaffb31Sdp#
2259daaffb31Sdp#
2260daaffb31Sdp# Main program starts here
2261daaffb31Sdp#
2262daaffb31Sdp#
2263daaffb31Sdp
2264daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2265daaffb31Sdp
2266daaffb31Sdpset +o noclobber
2267daaffb31Sdp
2268*8bcea973SRichard LowePATH=$(/bin/dirname "$(whence $0)"):$PATH
2269cdf0c1d5Smjnelson
227014983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
227114983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2272cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2273*8bcea973SRichard Lowe[[ -z $GIT ]] && GIT=`look_for_prog git`
2274cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
227514983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
227614983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
227714983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
227802d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2279cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2280cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2281cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2282cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
228302d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2284b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
228502d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2286e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort`
228702d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
228802d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2289ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2290cdf0c1d5Smjnelson
2291ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2292ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2293ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
229414983201Sdp
229514983201Sdpif [[ ! -x $PERL ]]; then
229614983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
229714983201Sdp	exit 1
2298daaffb31Sdpfi
229914983201Sdp
2300cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2301cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2302cdf0c1d5Smjnelson	exit 1
2303cdf0c1d5Smjnelsonfi
2304cdf0c1d5Smjnelson
230514983201Sdp#
230614983201Sdp# These aren't fatal, but we want to note them to the user.
230714983201Sdp# We don't warn on the absence of 'wx' until later when we've
230814983201Sdp# determined that we actually need to try to invoke it.
230914983201Sdp#
231014983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
231114983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
231214983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2313daaffb31Sdp
2314daaffb31Sdp# Declare global total counters.
2315daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2316daaffb31Sdp
2317ba44d8a2SVladimir Kotal# default remote host for upload/delete
2318ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2319b0088928SVladimir Kotal# prefixes for upload targets
2320b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2321b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2322ba44d8a2SVladimir Kotal
23230fd2682eSMark J. NelsonCflag=
2324ba44d8a2SVladimir KotalDflag=
232514983201Sdpflist_mode=
232614983201Sdpflist_file=
2327daaffb31Sdpiflag=
23280fd2682eSMark J. NelsonIflag=
232902d26c39SVladimir Kotallflag=
233002d26c39SVladimir KotalNflag=
233102d26c39SVladimir Kotalnflag=
233202d26c39SVladimir KotalOflag=
2333daaffb31Sdpoflag=
2334daaffb31Sdppflag=
233502d26c39SVladimir Kotaltflag=
233602d26c39SVladimir Kotaluflag=
233702d26c39SVladimir KotalUflag=
2338daaffb31Sdpwflag=
233902d26c39SVladimir Kotalremote_target=
2340ba44d8a2SVladimir Kotal
2341ba44d8a2SVladimir Kotal#
2342ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2343ba44d8a2SVladimir Kotal#	with usr/src/tools/onbld/hgext/cdm.py
2344ba44d8a2SVladimir Kotal#
234525cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
2346daaffb31Sdpdo
2347daaffb31Sdp	case $opt in
23480fd2682eSMark J. Nelson	C)	Cflag=1
23490fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
23500fd2682eSMark J. Nelson
2351ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2352ba44d8a2SVladimir Kotal
2353daaffb31Sdp	i)	iflag=1
2354daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2355daaffb31Sdp
23560fd2682eSMark J. Nelson	I)	Iflag=1
23570fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
23580fd2682eSMark J. Nelson
2359daaffb31Sdp	#
2360daaffb31Sdp	# If -l has been specified, we need to abort further options
2361daaffb31Sdp	# processing, because subsequent arguments are going to be
2362daaffb31Sdp	# arguments to 'putback -n'.
2363daaffb31Sdp	#
2364daaffb31Sdp	l)	lflag=1
2365daaffb31Sdp		break;;
2366daaffb31Sdp
236702d26c39SVladimir Kotal	N)	Nflag=1;;
236802d26c39SVladimir Kotal
236902d26c39SVladimir Kotal	n)	nflag=1;;
2370daaffb31Sdp
2371daaffb31Sdp	O)	Oflag=1;;
2372daaffb31Sdp
237302d26c39SVladimir Kotal	o)	oflag=1
23749d3952abSVladimir Kotal		# Strip the trailing slash to correctly form remote target.
23759d3952abSVladimir Kotal		WDIR=${OPTARG%/};;
237602d26c39SVladimir Kotal
237702d26c39SVladimir Kotal	p)	pflag=1
237802d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
237902d26c39SVladimir Kotal
238002d26c39SVladimir Kotal	t)	tflag=1
238102d26c39SVladimir Kotal		remote_target=$OPTARG;;
238202d26c39SVladimir Kotal
238302d26c39SVladimir Kotal	U)	Uflag=1;;
238402d26c39SVladimir Kotal
238502d26c39SVladimir Kotal	w)	wflag=1;;
23863df69ef3SDarren Moffat
2387daaffb31Sdp	?)	usage;;
2388daaffb31Sdp	esac
2389daaffb31Sdpdone
2390daaffb31Sdp
2391daaffb31SdpFLIST=/tmp/$$.flist
2392daaffb31Sdp
2393daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2394daaffb31Sdp	usage
2395daaffb31Sdpfi
2396daaffb31Sdp
239702d26c39SVladimir Kotal# more sanity checking
239802d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2399ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2400ba44d8a2SVladimir Kotal	    "without -U"
240102d26c39SVladimir Kotal	exit 1
240202d26c39SVladimir Kotalfi
240302d26c39SVladimir Kotal
2404ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2405ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
240602d26c39SVladimir Kotal	exit 1
240702d26c39SVladimir Kotalfi
240802d26c39SVladimir Kotal
2409daaffb31Sdp#
24102d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume
24112d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name
24122d9224a3SMark J. Nelson# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
24132d9224a3SMark J. Nelson# logic.
24142d9224a3SMark J. Nelson#
24152d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1
24162d9224a3SMark J. Nelsonif [[ $SCM_MODE == "teamware" ]]; then
24172d9224a3SMark J. Nelson	#
24182d9224a3SMark J. Nelson	# Teamware priorities:
24192d9224a3SMark J. Nelson	# 1. CODEMGR_WS from the environment
24202d9224a3SMark J. Nelson	# 2. workspace name
24212d9224a3SMark J. Nelson	#
24222d9224a3SMark J. Nelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
24232d9224a3SMark J. Nelson	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
24242d9224a3SMark J. Nelson		print -u2 "$codemgr_ws: no such workspace"
24252d9224a3SMark J. Nelson		exit 1
24262d9224a3SMark J. Nelson	fi
24272d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
24282d9224a3SMark J. Nelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
24292d9224a3SMark J. Nelson	CODEMGR_WS=$codemgr_ws
24302d9224a3SMark J. Nelson	CWS=$codemgr_ws
24312d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "mercurial" ]]; then
24322d9224a3SMark J. Nelson	#
24332d9224a3SMark J. Nelson	# Mercurial priorities:
24342d9224a3SMark J. Nelson	# 1. hg root from CODEMGR_WS environment variable
243578add226Sjmcp	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
243678add226Sjmcp	#    usr/closed when we run webrev
24372d9224a3SMark J. Nelson	# 2. hg root from directory of invocation
24382d9224a3SMark J. Nelson	#
243978add226Sjmcp	if [[ ${PWD} =~ "usr/closed" ]]; then
244078add226Sjmcp		testparent=${CODEMGR_WS}/usr/closed
244178add226Sjmcp		# If we're in OpenSolaris mode, we enforce a minor policy:
244278add226Sjmcp		# help to make sure the reviewer doesn't accidentally publish
244378add226Sjmcp		# source which is under usr/closed
244478add226Sjmcp		if [[ -n "$Oflag" ]]; then
244578add226Sjmcp			print -u2 "OpenSolaris output not permitted with" \
244678add226Sjmcp			    "usr/closed changes"
244778add226Sjmcp			exit 1
244878add226Sjmcp		fi
244978add226Sjmcp	else
245078add226Sjmcp	        testparent=${CODEMGR_WS}
245178add226Sjmcp	fi
245278add226Sjmcp	[[ -z $codemgr_ws && -n $testparent ]] && \
245378add226Sjmcp	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
24542d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
24552d9224a3SMark J. Nelson	CWS=$codemgr_ws
2456*8bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
2457*8bcea973SRichard Lowe	#
2458*8bcea973SRichard Lowe	# Git priorities:
2459*8bcea973SRichard Lowe	# 1. git rev-parse --git-dir from CODEMGR_WS environment variable
2460*8bcea973SRichard Lowe	# 2. git rev-parse --git-dir from directory of invocation
2461*8bcea973SRichard Lowe	#
2462*8bcea973SRichard Lowe	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2463*8bcea973SRichard Lowe	    codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
2464*8bcea973SRichard Lowe                2>/dev/null)
2465*8bcea973SRichard Lowe	[[ -z $codemgr_ws ]] && \
2466*8bcea973SRichard Lowe	    codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
2467*8bcea973SRichard Lowe
2468*8bcea973SRichard Lowe	if [[ "$codemgr_ws" == ".git" ]]; then
2469*8bcea973SRichard Lowe		codemgr_ws="${PWD}/${codemgr_ws}"
2470*8bcea973SRichard Lowe	fi
2471*8bcea973SRichard Lowe
2472*8bcea973SRichard Lowe	codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
2473*8bcea973SRichard Lowe	CWS="$codemgr_ws"
24742d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then
24752d9224a3SMark J. Nelson	#
24762d9224a3SMark J. Nelson	# Subversion priorities:
24772d9224a3SMark J. Nelson	# 1. CODEMGR_WS from environment
24782d9224a3SMark J. Nelson	# 2. Relative path from current directory to SVN repository root
24792d9224a3SMark J. Nelson	#
24802d9224a3SMark J. Nelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
24812d9224a3SMark J. Nelson		CWS=$CODEMGR_WS
24822d9224a3SMark J. Nelson	else
24832d9224a3SMark J. Nelson		svn info | while read line; do
24842d9224a3SMark J. Nelson			if [[ $line == "URL: "* ]]; then
24852d9224a3SMark J. Nelson				url=${line#URL: }
24862d9224a3SMark J. Nelson			elif [[ $line == "Repository Root: "* ]]; then
24872d9224a3SMark J. Nelson				repo=${line#Repository Root: }
24882d9224a3SMark J. Nelson			fi
24892d9224a3SMark J. Nelson		done
24902d9224a3SMark J. Nelson
24912d9224a3SMark J. Nelson		rel=${url#$repo}
24922d9224a3SMark J. Nelson		CWS=${PWD%$rel}
24932d9224a3SMark J. Nelson	fi
24942d9224a3SMark J. Nelsonfi
24952d9224a3SMark J. Nelson
24962d9224a3SMark J. Nelson#
24972d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting
24982d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set.
24992d9224a3SMark J. Nelson#
25002d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then
25012d9224a3SMark J. Nelson	CWS=${CODEMGR_WS:-.}
25022d9224a3SMark J. Nelsonfi
25032d9224a3SMark J. Nelson
25042d9224a3SMark J. Nelson#
25050fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
25060fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
25070fd2682eSMark J. Nelson# ton of logic we can skip.
25080fd2682eSMark J. Nelson#
25090fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
25100fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
25110fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
25120fd2682eSMark J. Nelson#
25130fd2682eSMark J. Nelsonfor do_everything in 1; do
25140fd2682eSMark J. Nelson
25150fd2682eSMark J. Nelson# DO_EVERYTHING: break point
25160fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
25170fd2682eSMark J. Nelson	break
25180fd2682eSMark J. Nelsonfi
25190fd2682eSMark J. Nelson
25200fd2682eSMark J. Nelson#
2521daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2522daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2523daaffb31Sdp#
2524daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2525*8bcea973SRichard Lowe	parent_webrev=$(readlink -f "$codemgr_parent")
2526*8bcea973SRichard Lowe	codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new")
2527daaffb31Sdpfi
2528daaffb31Sdp
2529daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2530daaffb31Sdp	shift $(($OPTIND - 1))
2531daaffb31Sdp
2532daaffb31Sdp	if [[ $1 == "-" ]]; then
2533daaffb31Sdp		cat > $FLIST
253414983201Sdp		flist_mode="stdin"
253514983201Sdp		flist_done=1
253614983201Sdp		shift
2537daaffb31Sdp	elif [[ -n $1 ]]; then
253814983201Sdp		if [[ ! -r $1 ]]; then
2539daaffb31Sdp			print -u2 "$1: no such file or not readable"
2540daaffb31Sdp			usage
2541daaffb31Sdp		fi
2542daaffb31Sdp		cat $1 > $FLIST
254314983201Sdp		flist_mode="file"
254414983201Sdp		flist_file=$1
254514983201Sdp		flist_done=1
254614983201Sdp		shift
2547daaffb31Sdp	else
254814983201Sdp		flist_mode="auto"
2549daaffb31Sdp	fi
2550daaffb31Sdpfi
2551daaffb31Sdp
2552daaffb31Sdp#
2553daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2554daaffb31Sdp# is in use.
2555daaffb31Sdp#
2556cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2557*8bcea973SRichard Loweteamware|mercurial|git|subversion)
2558cdf0c1d5Smjnelson	;;
2559cdf0c1d5Smjnelsonunknown)
2560cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2561cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2562cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
25637c478bd9Sstevel@tonic-gate		exit 1
25647c478bd9Sstevel@tonic-gate	fi
2565cdf0c1d5Smjnelson	;;
2566cdf0c1d5Smjnelson*)
2567cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2568cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2569cdf0c1d5Smjnelson		exit 1
2570cdf0c1d5Smjnelson	fi
2571cdf0c1d5Smjnelson	;;
2572cdf0c1d5Smjnelsonesac
25737c478bd9Sstevel@tonic-gate
2574daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2575daaffb31Sdp
2576daaffb31Sdpif [[ -n $lflag ]]; then
2577daaffb31Sdp	#
2578daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2579daaffb31Sdp	# then generate the file list by extracting file names from a
2580daaffb31Sdp	# putback -n.
2581daaffb31Sdp	#
2582daaffb31Sdp	shift $(($OPTIND - 1))
2583cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2584daaffb31Sdp		flist_from_teamware "$*"
2585cdf0c1d5Smjnelson	else
2586cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2587cdf0c1d5Smjnelson		exit 1
2588cdf0c1d5Smjnelson	fi
2589daaffb31Sdp	flist_done=1
2590daaffb31Sdp	shift $#
2591daaffb31Sdpelif [[ -n $wflag ]]; then
2592daaffb31Sdp	#
2593daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2594daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2595daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2596daaffb31Sdp	# in building the index.html file.
2597daaffb31Sdp	#
2598daaffb31Sdp	shift $(($OPTIND - 1))
2599daaffb31Sdp	wxfile=$1
2600daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2601daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2602daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2603daaffb31Sdp		fi
2604daaffb31Sdp	fi
2605daaffb31Sdp
2606daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2607daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2608daaffb31Sdp
2609cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2610cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2611cdf0c1d5Smjnelson		usage
2612cdf0c1d5Smjnelson	fi
2613cdf0c1d5Smjnelson
2614daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2615daaffb31Sdp	flist_from_wx $wxfile
2616daaffb31Sdp	flist_done=1
2617daaffb31Sdp	if [[ -n "$*" ]]; then
2618daaffb31Sdp		shift
2619daaffb31Sdp	fi
262014983201Sdpelif [[ $flist_mode == "stdin" ]]; then
262114983201Sdp	print -u2 " File list from: standard input"
262214983201Sdpelif [[ $flist_mode == "file" ]]; then
262314983201Sdp	print -u2 " File list from: $flist_file"
2624daaffb31Sdpfi
2625daaffb31Sdp
2626daaffb31Sdpif [[ $# -gt 0 ]]; then
262714983201Sdp	print -u2 "WARNING: unused arguments: $*"
2628daaffb31Sdpfi
2629daaffb31Sdp
26302d9224a3SMark J. Nelson#
26312d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS
26322d9224a3SMark J. Nelson# and CODEMGR_WS as needed.  Here, we set the parent workspace.
26332d9224a3SMark J. Nelson#
26342d9224a3SMark J. Nelson
2635daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
26362d9224a3SMark J. Nelson
2637daaffb31Sdp	#
26382d9224a3SMark J. Nelson	# Teamware priorities:
2639daaffb31Sdp	#
26402d9224a3SMark J. Nelson	#      1) via -p command line option
2641daaffb31Sdp	#      2) in the user environment
2642daaffb31Sdp	#      3) in the flist
26432d9224a3SMark J. Nelson	#      4) automatically based on the workspace
2644daaffb31Sdp	#
2645daaffb31Sdp
2646daaffb31Sdp	#
26472d9224a3SMark J. Nelson	# For 1, codemgr_parent will already be set.  Here's 2:
2648daaffb31Sdp	#
2649daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2650daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2651daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2652daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
26537c478bd9Sstevel@tonic-gate		exit 1
26547c478bd9Sstevel@tonic-gate	fi
26557c478bd9Sstevel@tonic-gate
2656daaffb31Sdp	#
2657daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2658daaffb31Sdp	# list, then see if we can get it by probing for wx.
2659daaffb31Sdp	#
266014983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
266114983201Sdp		if [[ ! -x $WX ]]; then
266214983201Sdp			print -u2 "WARNING: wx not found!"
2663daaffb31Sdp		fi
26647c478bd9Sstevel@tonic-gate
2665daaffb31Sdp		#
2666daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2667daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2668daaffb31Sdp		# hang asking us to initialize our wx information.
2669daaffb31Sdp		#
267014983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2671daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2672daaffb31Sdp			$WX list -w > $FLIST
2673daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2674daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2675daaffb31Sdp			print -u2 "done"
2676daaffb31Sdp			flist_done=1
2677daaffb31Sdp		fi
2678daaffb31Sdp	fi
2679daaffb31Sdp
2680daaffb31Sdp	#
2681daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2682daaffb31Sdp	# from the command line), eval it to extract environment variables from
26832d9224a3SMark J. Nelson	# it: This is method 3 for finding the parent.
2684daaffb31Sdp	#
2685daaffb31Sdp	if [[ -z $flist_done ]]; then
2686daaffb31Sdp		flist_from_teamware
2687daaffb31Sdp	fi
26882d9224a3SMark J. Nelson	env_from_flist
2689daaffb31Sdp
2690daaffb31Sdp	#
2691daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2692daaffb31Sdp	# from workspace.
2693daaffb31Sdp	#
2694daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2695daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2696daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2697daaffb31Sdp		exit 1
2698daaffb31Sdp	fi
2699daaffb31Sdp
2700daaffb31Sdp	PWS=$codemgr_parent
2701cdf0c1d5Smjnelson
2702cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2703cdf0c1d5Smjnelson
2704cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2705cdf0c1d5Smjnelson	#
2706cdf0c1d5Smjnelson	# Parent can either be specified with -p
2707cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2708cdf0c1d5Smjnelson	# or taken from hg's default path.
2709cdf0c1d5Smjnelson	#
2710cdf0c1d5Smjnelson
2711cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2712cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2713cdf0c1d5Smjnelson	fi
2714cdf0c1d5Smjnelson
2715cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2716cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2717cdf0c1d5Smjnelson	fi
2718cdf0c1d5Smjnelson
2719cdf0c1d5Smjnelson	PWS=$codemgr_parent
2720cdf0c1d5Smjnelson
2721cdf0c1d5Smjnelson	#
2722cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2723cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2724cdf0c1d5Smjnelson	#
2725cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2726cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2727cdf0c1d5Smjnelson	else
2728cdf0c1d5Smjnelson		real_parent=$PWS
2729cdf0c1d5Smjnelson	fi
2730cdf0c1d5Smjnelson
2731cdf0c1d5Smjnelson	#
2732cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2733cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2734cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2735cdf0c1d5Smjnelson	# files mentioned in the flist.
2736cdf0c1d5Smjnelson	#
2737cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2738cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2739cdf0c1d5Smjnelson		flist_done=1
2740cdf0c1d5Smjnelson	fi
2741cdf0c1d5Smjnelson
2742cdf0c1d5Smjnelson	#
2743cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2744cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2745cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2746cdf0c1d5Smjnelson	# in the user-specified flist.
2747cdf0c1d5Smjnelson	#
2748cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2749cdf0c1d5Smjnelson		env_from_flist
2750cdf0c1d5Smjnelson	fi
2751cdf0c1d5Smjnelson
2752cdf0c1d5Smjnelson	#
2753cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2754cdf0c1d5Smjnelson	#
2755cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2756cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2757cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2758cdf0c1d5Smjnelson		print " Done."
2759cdf0c1d5Smjnelson	fi
2760cdf0c1d5Smjnelson
2761cdf0c1d5Smjnelson	#
2762cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2763cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2764cdf0c1d5Smjnelson	# if we don't have one.
2765cdf0c1d5Smjnelson	#
2766cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2767b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2768cdf0c1d5Smjnelson	fi
2769cdf0c1d5Smjnelson
2770cdf0c1d5Smjnelson	#
2771cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2772cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2773cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2774cdf0c1d5Smjnelson	#
2775cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2776cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2777b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2778cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2779cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2780cdf0c1d5Smjnelson		exit 1
2781cdf0c1d5Smjnelson	fi
2782*8bcea973SRichard Lowe
2783*8bcea973SRichard Lowe	pnode=$(trim_digest $HG_PARENT)
2784*8bcea973SRichard Lowe	PRETTY_PWS="${PWS} (at ${pnode})"
2785*8bcea973SRichard Lowe	cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
2786*8bcea973SRichard Lowe	    2>/dev/null)
2787*8bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"}
2788*8bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
2789*8bcea973SRichard Lowe	#
2790*8bcea973SRichard Lowe	# Parent can either be specified with -p, or specified with
2791*8bcea973SRichard Lowe	# CODEMGR_PARENT in the environment.
2792*8bcea973SRichard Lowe	#
2793*8bcea973SRichard Lowe
2794*8bcea973SRichard Lowe	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2795*8bcea973SRichard Lowe		codemgr_parent=$CODEMGR_PARENT
2796*8bcea973SRichard Lowe	fi
2797*8bcea973SRichard Lowe
2798*8bcea973SRichard Lowe	# Try to figure out the parent based on the branch the current
2799*8bcea973SRichard Lowe	# branch is tracking, if we fail, use origin/master
2800*8bcea973SRichard Lowe	this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }')
2801*8bcea973SRichard Lowe	par_branch="origin/master"
2802*8bcea973SRichard Lowe
2803*8bcea973SRichard Lowe        # If we're not on a branch there's nothing we can do
2804*8bcea973SRichard Lowe        if [[ $this_branch != "(no branch)" ]]; then
2805*8bcea973SRichard Lowe                $GIT for-each-ref                                                 \
2806*8bcea973SRichard Lowe                    --format='%(refname:short) %(upstream:short)' refs/heads/ |   \
2807*8bcea973SRichard Lowe                    while read local remote; do                                   \
2808*8bcea973SRichard Lowe                	[[ "$local" == "$this_branch" ]] && par_branch="$remote"; \
2809*8bcea973SRichard Lowe                    done
2810*8bcea973SRichard Lowe	fi
2811*8bcea973SRichard Lowe
2812*8bcea973SRichard Lowe	if [[ -z $codemgr_parent ]]; then
2813*8bcea973SRichard Lowe		codemgr_parent=$par_branch
2814*8bcea973SRichard Lowe	fi
2815*8bcea973SRichard Lowe	PWS=$codemgr_parent
2816*8bcea973SRichard Lowe
2817*8bcea973SRichard Lowe	#
2818*8bcea973SRichard Lowe	# If the parent is a webrev, we want to do some things against
2819*8bcea973SRichard Lowe	# the natural workspace parent (file list, comments, etc)
2820*8bcea973SRichard Lowe	#
2821*8bcea973SRichard Lowe	if [[ -n $parent_webrev ]]; then
2822*8bcea973SRichard Lowe		real_parent=$par_branch
2823*8bcea973SRichard Lowe	else
2824*8bcea973SRichard Lowe		real_parent=$PWS
2825*8bcea973SRichard Lowe	fi
2826*8bcea973SRichard Lowe
2827*8bcea973SRichard Lowe	if [[ -z $flist_done ]]; then
2828*8bcea973SRichard Lowe		flist_from_git "$CWS" "$real_parent"
2829*8bcea973SRichard Lowe		flist_done=1
2830*8bcea973SRichard Lowe	fi
2831*8bcea973SRichard Lowe
2832*8bcea973SRichard Lowe	#
2833*8bcea973SRichard Lowe	# If we have a file list now, pull out any variables set
2834*8bcea973SRichard Lowe	# therein.
2835*8bcea973SRichard Lowe	#
2836*8bcea973SRichard Lowe	if [[ -n $flist_done ]]; then
2837*8bcea973SRichard Lowe		env_from_flist
2838*8bcea973SRichard Lowe	fi
2839*8bcea973SRichard Lowe
2840*8bcea973SRichard Lowe	#
2841*8bcea973SRichard Lowe	# If we don't have a wx-format file list, build one we can pull change
2842*8bcea973SRichard Lowe	# comments from.
2843*8bcea973SRichard Lowe	#
2844*8bcea973SRichard Lowe	if [[ -z $wxfile ]]; then
2845*8bcea973SRichard Lowe		print "  Comments from: git...\c"
2846*8bcea973SRichard Lowe		git_wxfile "$CWS" "$real_parent"
2847*8bcea973SRichard Lowe		print " Done."
2848*8bcea973SRichard Lowe	fi
2849*8bcea973SRichard Lowe
2850*8bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
2851*8bcea973SRichard Lowe		GIT_PARENT=$($GIT merge-base "$real_parent" HEAD)
2852*8bcea973SRichard Lowe	fi
2853*8bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
2854*8bcea973SRichard Lowe		print -u2 "Error: Cannot discover parent revision"
2855*8bcea973SRichard Lowe		exit 1
2856*8bcea973SRichard Lowe	fi
2857*8bcea973SRichard Lowe
2858*8bcea973SRichard Lowe	pnode=$(trim_digest $GIT_PARENT)
2859*8bcea973SRichard Lowe
2860*8bcea973SRichard Lowe	if [[ $real_parent == */* ]]; then
2861*8bcea973SRichard Lowe		origin=$(echo $real_parent | cut -d/ -f1)
2862*8bcea973SRichard Lowe		origin=$($GIT remote -v | \
2863*8bcea973SRichard Lowe		    $AWK '$1 == "'$origin'" { print $2; exit }')
2864*8bcea973SRichard Lowe		PRETTY_PWS="${PWS} (${origin} at ${pnode})"
2865*8bcea973SRichard Lowe	else
2866*8bcea973SRichard Lowe		PRETTY_PWS="${PWS} (at ${pnode})"
2867*8bcea973SRichard Lowe	fi
2868*8bcea973SRichard Lowe
2869*8bcea973SRichard Lowe	cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \
2870*8bcea973SRichard Lowe	    2>/dev/null)
2871*8bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"
2872cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2873cdf0c1d5Smjnelson
2874cdf0c1d5Smjnelson	#
2875cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2876cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2877cdf0c1d5Smjnelson	#
2878cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2879cdf0c1d5Smjnelson
2880cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2881cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2882cdf0c1d5Smjnelson	fi
2883cdf0c1d5Smjnelsonelse
2884cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2885cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2886cdf0c1d5Smjnelson    else
2887cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2888cdf0c1d5Smjnelson    fi
2889cdf0c1d5Smjnelson
2890cdf0c1d5Smjnelson    env_from_flist
2891cdf0c1d5Smjnelson
2892cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2893cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2894cdf0c1d5Smjnelson	exit 1
2895cdf0c1d5Smjnelson    fi
2896cdf0c1d5Smjnelson
2897cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2898cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2899cdf0c1d5Smjnelson	exit 1
2900cdf0c1d5Smjnelson    fi
2901cdf0c1d5Smjnelson
2902cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2903cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2904daaffb31Sdpfi
2905daaffb31Sdp
2906daaffb31Sdp#
2907daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2908daaffb31Sdp# webrev-info file in the workspace directory.
2909daaffb31Sdp#
2910daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2911daaffb31Sdp	iflag=1
2912daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2913daaffb31Sdpfi
2914daaffb31Sdp
2915daaffb31Sdpif [[ -n $iflag ]]; then
2916daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2917daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2918daaffb31Sdp		    "not readable."
2919daaffb31Sdp		exit 1
2920daaffb31Sdp	else
2921daaffb31Sdp		#
2922daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2923daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2924daaffb31Sdp		#
2925daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2926daaffb31Sdp	fi
2927daaffb31Sdpfi
2928daaffb31Sdp
29290fd2682eSMark J. Nelson# DO_EVERYTHING: break point
29300fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
29310fd2682eSMark J. Nelson	break
29320fd2682eSMark J. Nelsonfi
29330fd2682eSMark J. Nelson
29340fd2682eSMark J. Nelsontypeset -A itsinfo
29350fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
29360fd2682eSMark J. Nelsonvalid_prefixes=
29370fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
2938*8bcea973SRichard Lowe	DEFREGFILE="$(/bin/dirname "$(whence $0)")/../etc/its.reg"
29390fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
29400fd2682eSMark J. Nelson		REGFILE=$ITSREG
29410fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
29420fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
29430fd2682eSMark J. Nelson	else
29440fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
29450fd2682eSMark J. Nelson	fi
29460fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
29470fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
29480fd2682eSMark J. Nelson		exit 1
29490fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
29500fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
29510fd2682eSMark J. Nelson	fi
29520fd2682eSMark J. Nelson
29530fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
29540fd2682eSMark J. Nelson
29550fd2682eSMark J. Nelson		name=${LINE%%=*}
29560fd2682eSMark J. Nelson		value="${LINE#*=}"
29570fd2682eSMark J. Nelson
29580fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
29590fd2682eSMark J. Nelson			p=${value}
29600fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
29610fd2682eSMark J. Nelson		else
29620fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
29630fd2682eSMark J. Nelson		fi
29640fd2682eSMark J. Nelson	done
29650fd2682eSMark J. Nelson
29660fd2682eSMark J. Nelson
2967*8bcea973SRichard Lowe	DEFCONFFILE="$(/bin/dirname "$(whence $0)")/../etc/its.conf"
29680fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
29690fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
29700fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
29710fd2682eSMark J. Nelson	fi
29720fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
29730fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
29740fd2682eSMark J. Nelson	fi
29750fd2682eSMark J. Nelson	its_domain=
29760fd2682eSMark J. Nelson	its_priority=
29770fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
29780fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
29790fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
29800fd2682eSMark J. Nelson			exit 1
29810fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
29820fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
29830fd2682eSMark J. Nelson		fi
29840fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
29850fd2682eSMark J. Nelson		    eval "${LINE}"
29860fd2682eSMark J. Nelson		done
29870fd2682eSMark J. Nelson	done
29880fd2682eSMark J. Nelson
29890fd2682eSMark J. Nelson	#
29900fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
29910fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
29920fd2682eSMark J. Nelson	#
29930fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
29940fd2682eSMark J. Nelson	#
29950fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
29960fd2682eSMark J. Nelson		#
29970fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
29980fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
29990fd2682eSMark J. Nelson		#
30000fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
30010fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
30020fd2682eSMark J. Nelson		else
30030fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
30040fd2682eSMark J. Nelson		fi
30050fd2682eSMark J. Nelson
30060fd2682eSMark J. Nelson		#
30070fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
30080fd2682eSMark J. Nelson		# to this information tracking system should resolve through
30090fd2682eSMark J. Nelson		# the same URL.
30100fd2682eSMark J. Nelson		#
30110fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
30120fd2682eSMark J. Nelson		#
30130fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
30140fd2682eSMark J. Nelson		# INTERNAL_URL.
30150fd2682eSMark J. Nelson		#
30160fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
30170fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
30180fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
30190fd2682eSMark J. Nelson				break
30200fd2682eSMark J. Nelson			fi
30210fd2682eSMark J. Nelson		done
30220fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
30230fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
30240fd2682eSMark J. Nelson		fi
30250fd2682eSMark J. Nelson
30260fd2682eSMark J. Nelson		#
30270fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
30280fd2682eSMark J. Nelson		#
30290fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
30300fd2682eSMark J. Nelson
30312f54b716SRichard Lowe		# The character class below contains a literal tab
30322f54b716SRichard Lowe		print "/^${p}[: 	]/ {
30330fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
30340fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
30350fd2682eSMark J. Nelson			}" >> ${its_sed_script}
30360fd2682eSMark J. Nelson	done
30370fd2682eSMark J. Nelson
30380fd2682eSMark J. Nelson	#
30390fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
30400fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
30410fd2682eSMark J. Nelson	#
30420fd2682eSMark J. Nelson	for p in ${its_priority}; do
30430fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
30442f54b716SRichard Lowe				s;^${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
30450fd2682eSMark J. Nelson			}" >> ${its_sed_script}
30460fd2682eSMark J. Nelson	done
30470fd2682eSMark J. Nelsonfi
30480fd2682eSMark J. Nelson
30490fd2682eSMark J. Nelson#
30500fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
30510fd2682eSMark J. Nelson# and explanation of this terminator.
30520fd2682eSMark J. Nelson#
30530fd2682eSMark J. Nelsondone
30540fd2682eSMark J. Nelson
3055daaffb31Sdp#
3056daaffb31Sdp# Output directory.
3057daaffb31Sdp#
3058daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
3059daaffb31Sdp
3060daaffb31Sdp#
306102d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
306202d26c39SVladimir Kotal# in the future this could potentially be an option.
3063daaffb31Sdp#
306402d26c39SVladimir Kotalif [[ -n $oflag ]]; then
306502d26c39SVladimir Kotal	WNAME=${WDIR##*/}
306602d26c39SVladimir Kotalelse
3067daaffb31Sdp	WNAME=${CWS##*/}
306802d26c39SVladimir Kotalfi
306902d26c39SVladimir Kotal
3070ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
3071ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
3072b0088928SVladimir Kotal	#
3073ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
3074ba44d8a2SVladimir Kotal	# the default values.
3075b0088928SVladimir Kotal	#
3076ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
3077ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
3078ba44d8a2SVladimir Kotal	else
3079b0088928SVladimir Kotal		#
3080b0088928SVladimir Kotal		# Check upload target prefix first.
3081b0088928SVladimir Kotal		#
3082b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
3083b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
3084b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
3085b0088928SVladimir Kotal			    "($remote_target)"
3086b0088928SVladimir Kotal			exit 1
3087b0088928SVladimir Kotal		fi
3088b0088928SVladimir Kotal		#
3089ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
3090ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
3091ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
3092ba44d8a2SVladimir Kotal		# local webrev directory name.
3093b0088928SVladimir Kotal		#
3094b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
3095b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
3096ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
3097b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
3098ba44d8a2SVladimir Kotal			fi
3099b0088928SVladimir Kotal		else
3100b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
3101b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
3102b0088928SVladimir Kotal					"($remote_target)"
3103b0088928SVladimir Kotal				exit 1
3104b0088928SVladimir Kotal			else
3105b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
3106ba44d8a2SVladimir Kotal			fi
3107ba44d8a2SVladimir Kotal		fi
3108ba44d8a2SVladimir Kotal	fi
3109ba44d8a2SVladimir Kotal
3110b0088928SVladimir Kotal	#
3111b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
3112b0088928SVladimir Kotal	# specification separately.
3113b0088928SVladimir Kotal	#
3114b0088928SVladimir Kotal	remote_target=${remote_target%/}
3115b0088928SVladimir Kotalfi
3116b0088928SVladimir Kotal
3117b0088928SVladimir Kotal#
3118ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
3119b0088928SVladimir Kotal#
3120ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
3121b0088928SVladimir Kotal	delete_webrev 1 1
3122ba44d8a2SVladimir Kotal	exit $?
3123ba44d8a2SVladimir Kotalfi
3124ba44d8a2SVladimir Kotal
3125b0088928SVladimir Kotal#
3126ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
3127b0088928SVladimir Kotal#
3128ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
3129ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
3130b0088928SVladimir Kotal		delete_webrev 1 1
3131ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
3132ba44d8a2SVladimir Kotal	fi
3133ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
313402d26c39SVladimir Kotal		upload_webrev
313502d26c39SVladimir Kotal		exit $?
313602d26c39SVladimir Kotal	fi
3137ba44d8a2SVladimir Kotalfi
3138daaffb31Sdp
3139e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
31407c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
31417c478bd9Sstevel@tonic-gatefi
3142daaffb31Sdp
3143daaffb31Sdpif [[ ! -d $WDIR ]]; then
3144daaffb31Sdp	mkdir -p $WDIR
3145ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
31467c478bd9Sstevel@tonic-gatefi
31477c478bd9Sstevel@tonic-gate
3148daaffb31Sdp#
3149daaffb31Sdp# Summarize what we're going to do.
3150daaffb31Sdp#
3151*8bcea973SRichard Loweprint "      Workspace: ${PRETTY_CWS:-$CWS}"
3152daaffb31Sdpif [[ -n $parent_webrev ]]; then
3153daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
3154daaffb31Sdpelse
3155*8bcea973SRichard Lowe	print "Compare against: ${PRETTY_PWS:-$PWS}"
3156cdf0c1d5Smjnelsonfi
3157daaffb31Sdp
3158daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
3159daaffb31Sdpprint "      Output to: $WDIR"
3160daaffb31Sdp
3161daaffb31Sdp#
31627c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
3163daaffb31Sdp#
3164daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
31657c478bd9Sstevel@tonic-gate
3166daaffb31Sdprm -f $WDIR/$WNAME.patch
3167daaffb31Sdprm -f $WDIR/$WNAME.ps
3168daaffb31Sdprm -f $WDIR/$WNAME.pdf
31697c478bd9Sstevel@tonic-gate
3170daaffb31Sdptouch $WDIR/$WNAME.patch
31717c478bd9Sstevel@tonic-gate
3172daaffb31Sdpprint "   Output Files:"
3173daaffb31Sdp
3174daaffb31Sdp#
3175daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
3176daaffb31Sdp#
3177b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
3178daaffb31SdpFLIST=/tmp/$$.flist.clean
3179daaffb31Sdp
3180daaffb31Sdp#
3181cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
3182cdf0c1d5Smjnelson#
3183cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
3184cdf0c1d5Smjnelson	#
3185cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
3186cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
3187cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
3188cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
3189cdf0c1d5Smjnelson	#    keep only the old name.
3190cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
3191cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
3192cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
3193cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
3194cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
3195e6ccc173SEdward Pilatowicz	# 4) Eliminate any duplicate entries.  (This can occur if a
3196e6ccc173SEdward Pilatowicz	#    file has been used as the source of an hg cp and it's
3197e6ccc173SEdward Pilatowicz	#    also been modified in the same changeset.)
3198cdf0c1d5Smjnelson	#
3199cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
3200b0088928SVladimir Kotal	$SED '
3201cdf0c1d5Smjnelson		s#^[^ ]* ##
3202cdf0c1d5Smjnelson		s#/#\\\/#g
3203cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
3204e6ccc173SEdward Pilatowicz	' < $FLIST | $SORT -u > $SEDFILE
3205cdf0c1d5Smjnelson
3206cdf0c1d5Smjnelson	#
3207cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
3208cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
3209cdf0c1d5Smjnelson	#
3210cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
3211cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
3212b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
3213cdf0c1d5Smjnelsonfi
3214cdf0c1d5Smjnelson
3215cdf0c1d5Smjnelson#
3216daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
3217daaffb31Sdp#
3218daaffb31Sdpcat $FLIST | while read LINE
32197c478bd9Sstevel@tonic-gatedo
32207c478bd9Sstevel@tonic-gate	set - $LINE
32217c478bd9Sstevel@tonic-gate	P=$1
32227c478bd9Sstevel@tonic-gate
3223daaffb31Sdp	#
3224daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
3225daaffb31Sdp	# file that has been modified or created in the child.  A file
3226daaffb31Sdp	# that is renamed in the child workspace has two names on the
3227daaffb31Sdp	# line: new name followed by the old name.
3228daaffb31Sdp	#
3229daaffb31Sdp	oldname=""
3230daaffb31Sdp	oldpath=""
3231daaffb31Sdp	rename=
3232daaffb31Sdp	if [[ $# -eq 2 ]]; then
32337c478bd9Sstevel@tonic-gate		PP=$2			# old filename
3234e6ccc173SEdward Pilatowicz		if [[ -f $PP ]]; then
3235e6ccc173SEdward Pilatowicz			oldname=" (copied from $PP)"
3236e6ccc173SEdward Pilatowicz		else
3237e6ccc173SEdward Pilatowicz			oldname=" (renamed from $PP)"
3238e6ccc173SEdward Pilatowicz		fi
3239daaffb31Sdp		oldpath="$PP"
3240daaffb31Sdp		rename=1
32417c478bd9Sstevel@tonic-gate		PDIR=${PP%/*}
3242daaffb31Sdp		if [[ $PDIR == $PP ]]; then
32437c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
32447c478bd9Sstevel@tonic-gate		fi
32457c478bd9Sstevel@tonic-gate
32467c478bd9Sstevel@tonic-gate		PF=${PP##*/}
32477c478bd9Sstevel@tonic-gate
32487c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3249daaffb31Sdp		if [[ $DIR == $P ]]; then
32507c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
32517c478bd9Sstevel@tonic-gate		fi
32527c478bd9Sstevel@tonic-gate
32537c478bd9Sstevel@tonic-gate		F=${P##*/}
3254daaffb31Sdp
32557c478bd9Sstevel@tonic-gate        else
32567c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3257daaffb31Sdp		if [[ "$DIR" == "$P" ]]; then
32587c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
32597c478bd9Sstevel@tonic-gate		fi
32607c478bd9Sstevel@tonic-gate
32617c478bd9Sstevel@tonic-gate		F=${P##*/}
32627c478bd9Sstevel@tonic-gate
32637c478bd9Sstevel@tonic-gate		PP=$P
32647c478bd9Sstevel@tonic-gate		PDIR=$DIR
32657c478bd9Sstevel@tonic-gate		PF=$F
32667c478bd9Sstevel@tonic-gate	fi
32677c478bd9Sstevel@tonic-gate
3268daaffb31Sdp	COMM=`getcomments html $P $PP`
32697c478bd9Sstevel@tonic-gate
3270daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
32717c478bd9Sstevel@tonic-gate
32727c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
32737c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
32747c478bd9Sstevel@tonic-gate
3275daaffb31Sdp	#
3276cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
3277daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
3278daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
3279daaffb31Sdp	#
3280daaffb31Sdp
3281cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
32827c478bd9Sstevel@tonic-gate	    continue
32837c478bd9Sstevel@tonic-gate
3284cdf0c1d5Smjnelson	#
3285cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3286cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3287cdf0c1d5Smjnelson	# consistent environment.
3288cdf0c1d5Smjnelson	#
3289cdf0c1d5Smjnelson	OWD=$PWD
3290daaffb31Sdp	cd $WDIR/raw_files
3291daaffb31Sdp	ofile=old/$PDIR/$PF
3292daaffb31Sdp	nfile=new/$DIR/$F
32937c478bd9Sstevel@tonic-gate
3294daaffb31Sdp	mv_but_nodiff=
3295daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3296daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3297daaffb31Sdp		mv_but_nodiff=1
3298daaffb31Sdp	fi
3299daaffb31Sdp
3300daaffb31Sdp	#
3301daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3302daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3303daaffb31Sdp	#
3304daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3305daaffb31Sdp	#	  diff and an 'add' diff
3306daaffb31Sdp	#	- new files and deleted files must be handled specially
3307daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
3308daaffb31Sdp	#	  (and hence renames) as of this writing.
3309daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
3310daaffb31Sdp	#	  output of Solaris diff properly when it comes to
3311daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
3312daaffb31Sdp	#         transformations:
3313daaffb31Sdp	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3314daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3315daaffb31Sdp	#
3316b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3317b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3318daaffb31Sdp
3319daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3320daaffb31Sdp	if [[ -z $rename ]]; then
3321e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3322daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3323daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3324e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3325daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3326daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3327daaffb31Sdp		else
3328daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3329daaffb31Sdp		fi
3330daaffb31Sdp	else
3331daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3332daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3333daaffb31Sdp
3334daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3335daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3336daaffb31Sdp	fi
3337daaffb31Sdp
3338daaffb31Sdp	#
3339daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3340daaffb31Sdp	# whole wad.
3341daaffb31Sdp	#
3342daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3343daaffb31Sdp
3344daaffb31Sdp	print " patch\c"
3345daaffb31Sdp
3346daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3347daaffb31Sdp
3348daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3349daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3350daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
33517c478bd9Sstevel@tonic-gate		print " cdiffs\c"
33527c478bd9Sstevel@tonic-gate
3353daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3354daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3355daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
3356daaffb31Sdp
33577c478bd9Sstevel@tonic-gate		print " udiffs\c"
33587c478bd9Sstevel@tonic-gate
33597c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3360daaffb31Sdp			$WDIFF -c "$COMM" \
3361daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3362daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3363daaffb31Sdp			if [[ $? -eq 0 ]]; then
33647c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3365daaffb31Sdp			else
3366daaffb31Sdp				print " wdiffs[fail]\c"
3367daaffb31Sdp			fi
33687c478bd9Sstevel@tonic-gate		fi
33697c478bd9Sstevel@tonic-gate
3370daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3371daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
33727c478bd9Sstevel@tonic-gate		print " sdiffs\c"
33737c478bd9Sstevel@tonic-gate
33747c478bd9Sstevel@tonic-gate		print " frames\c"
33757c478bd9Sstevel@tonic-gate
33767c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
33777c478bd9Sstevel@tonic-gate
3378daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3379daaffb31Sdp
3380daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3381daaffb31Sdp		# renamed file: may also have differences
3382daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3383daaffb31Sdp	elif [[ -f $nfile ]]; then
33847c478bd9Sstevel@tonic-gate		# new file: count added lines
3385daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3386daaffb31Sdp	elif [[ -f $ofile ]]; then
33877c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3388daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
33897c478bd9Sstevel@tonic-gate	fi
33907c478bd9Sstevel@tonic-gate
3391daaffb31Sdp	#
3392daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3393daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3394daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3395daaffb31Sdp	#
3396daaffb31Sdp	if [[ -f $nfile ]]; then
3397daaffb31Sdp		ocr=$ofile
3398daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3399daaffb31Sdp
3400daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3401daaffb31Sdp			textcomm=`getcomments text $P $PP`
340214983201Sdp			if [[ -x $CODEREVIEW ]]; then
340314983201Sdp				$CODEREVIEW -y "$textcomm" \
340414983201Sdp				    -e $ocr $nfile \
340514983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
340614983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3407daaffb31Sdp				if [[ $? -eq 0 ]]; then
3408daaffb31Sdp					print " ps\c"
3409daaffb31Sdp				else
3410daaffb31Sdp					print " ps[fail]\c"
3411daaffb31Sdp				fi
3412daaffb31Sdp			fi
3413daaffb31Sdp		fi
341414983201Sdp	fi
3415daaffb31Sdp
3416cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3417cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
34187c478bd9Sstevel@tonic-gate		print " old\c"
34197c478bd9Sstevel@tonic-gate	fi
34207c478bd9Sstevel@tonic-gate
3421daaffb31Sdp	if [[ -f $nfile ]]; then
3422daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
34237c478bd9Sstevel@tonic-gate		print " new\c"
34247c478bd9Sstevel@tonic-gate	fi
34257c478bd9Sstevel@tonic-gate
3426cdf0c1d5Smjnelson	cd $OWD
3427cdf0c1d5Smjnelson
3428daaffb31Sdp	print
34297c478bd9Sstevel@tonic-gatedone
34307c478bd9Sstevel@tonic-gate
3431daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
34327c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3433daaffb31Sdp
343414983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
343514983201Sdp	print " Generating PDF: Skipped: no output available"
343614983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
343714983201Sdp	print " Generating PDF: \c"
343814983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3439daaffb31Sdp	print "Done."
344014983201Sdpelse
344114983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
344214983201Sdpfi
34437c478bd9Sstevel@tonic-gate
3444e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3445e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3446e0e0293aSjmcp
3447e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3448ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3449e0e0293aSjmcpfi
3450e0e0293aSjmcp
34517c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
34527c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
34537c478bd9Sstevel@tonic-gate
34547c478bd9Sstevel@tonic-gatecd $CWS
34557c478bd9Sstevel@tonic-gate
34567c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3457daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
34587c478bd9Sstevel@tonic-gate
3459daaffb31Sdpprint "     index.html: \c"
34607c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
34617c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
34627c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
34637c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
34647c478bd9Sstevel@tonic-gate
3465daaffb31Sdpprint "$HTML<head>$STDHEAD"
3466daaffb31Sdpprint "<title>$WNAME</title>"
3467daaffb31Sdpprint "</head>"
3468daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3469daaffb31Sdpprint "<div class=\"summary\">"
3470daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
34717c478bd9Sstevel@tonic-gate
3472daaffb31Sdpprint "<table>"
34737c478bd9Sstevel@tonic-gate
3474daaffb31Sdp#
3475cdf0c1d5Smjnelson# Get the preparer's name:
3476daaffb31Sdp#
3477cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3478cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3479cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3480cdf0c1d5Smjnelson#
3481cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3482cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3483cdf0c1d5Smjnelson#
3484cdf0c1d5Smjnelsonpreparer=
3485cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3486cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3487cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3488cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3489cdf0c1d5Smjnelson	fi
3490cdf0c1d5Smjnelsonfi
3491cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3492cdf0c1d5Smjnelson	preparer=$(
3493cdf0c1d5Smjnelson	    $PERL -e '
3494cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3495cdf0c1d5Smjnelson	        if ($login) {
3496cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3497cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3498cdf0c1d5Smjnelson	        } else {
3499cdf0c1d5Smjnelson	            printf "(unknown)\n";
3500cdf0c1d5Smjnelson	        }
3501cdf0c1d5Smjnelson	')
3502daaffb31Sdpfi
3503daaffb31Sdp
350448bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
350548bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
3506*8bcea973SRichard Loweprint "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3507cdf0c1d5Smjnelsonprint "</td></tr>"
3508daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3509daaffb31Sdpif [[ -n $parent_webrev ]]; then
3510daaffb31Sdp	print "webrev at $parent_webrev"
3511daaffb31Sdpelse
3512*8bcea973SRichard Lowe	print "${PRETTY_PWS:-$PWS}"
3513daaffb31Sdpfi
3514daaffb31Sdpprint "</td></tr>"
3515daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3516daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3517daaffb31Sdpprint "</td></tr>"
3518daaffb31Sdp
3519daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3520371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3521daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3522371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3523daaffb31Sdpfi
3524daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3525371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3526daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3527371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3528daaffb31Sdpfi
3529daaffb31Sdp
3530daaffb31Sdpif [[ -n "$iflag" ]]; then
3531daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3532daaffb31Sdp	cat /tmp/$$.include
3533daaffb31Sdp	print "</div></td></tr>"
3534daaffb31Sdpfi
3535daaffb31Sdpprint "</table>"
3536daaffb31Sdpprint "</div>"
3537daaffb31Sdp
3538daaffb31Sdp#
3539daaffb31Sdp# Second pass through the files: generate the rest of the index file
3540daaffb31Sdp#
3541daaffb31Sdpcat $FLIST | while read LINE
35427c478bd9Sstevel@tonic-gatedo
35437c478bd9Sstevel@tonic-gate	set - $LINE
35447c478bd9Sstevel@tonic-gate	P=$1
35457c478bd9Sstevel@tonic-gate
3546daaffb31Sdp	if [[ $# == 2 ]]; then
35477c478bd9Sstevel@tonic-gate		PP=$2
3548cdf0c1d5Smjnelson		oldname="$PP"
35497c478bd9Sstevel@tonic-gate	else
35507c478bd9Sstevel@tonic-gate		PP=$P
3551daaffb31Sdp		oldname=""
3552daaffb31Sdp	fi
3553daaffb31Sdp
3554cdf0c1d5Smjnelson	mv_but_nodiff=
3555cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3556cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3557cdf0c1d5Smjnelson		mv_but_nodiff=1
3558cdf0c1d5Smjnelson	fi
3559cdf0c1d5Smjnelson
3560daaffb31Sdp	DIR=${P%/*}
3561daaffb31Sdp	if [[ $DIR == $P ]]; then
3562daaffb31Sdp		DIR="."   # File at root of workspace
35637c478bd9Sstevel@tonic-gate	fi
35647c478bd9Sstevel@tonic-gate
35657c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
35667c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
35677c478bd9Sstevel@tonic-gate	# appear twice in the file list
35687c478bd9Sstevel@tonic-gate
35697c478bd9Sstevel@tonic-gate	F=$WDIR/$P
35707c478bd9Sstevel@tonic-gate
3571daaffb31Sdp	print "<p>"
35727c478bd9Sstevel@tonic-gate
35737c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
35747c478bd9Sstevel@tonic-gate
3575daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3576371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3577371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3578371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3579371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
35807c478bd9Sstevel@tonic-gate
3581daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3582371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3583371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
35847c478bd9Sstevel@tonic-gate		fi
35857c478bd9Sstevel@tonic-gate
3586371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3587371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
35887c478bd9Sstevel@tonic-gate
3589371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3590371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
35917c478bd9Sstevel@tonic-gate	else
3592daaffb31Sdp		print " ------ ------ ------"
35937c478bd9Sstevel@tonic-gate
3594daaffb31Sdp		if [[ -x $WDIFF ]]; then
35957c478bd9Sstevel@tonic-gate			print " ------"
35967c478bd9Sstevel@tonic-gate		fi
3597daaffb31Sdp
3598daaffb31Sdp		print " ------"
35997c478bd9Sstevel@tonic-gate	fi
36007c478bd9Sstevel@tonic-gate
36017c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
36027c478bd9Sstevel@tonic-gate
3603daaffb31Sdp	if [[ -f $F-.html ]]; then
3604371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3605371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
36067c478bd9Sstevel@tonic-gate	else
3607daaffb31Sdp		print " ---"
36087c478bd9Sstevel@tonic-gate	fi
36097c478bd9Sstevel@tonic-gate
36107c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
36117c478bd9Sstevel@tonic-gate
3612daaffb31Sdp	if [[ -f $F.html ]]; then
3613371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3614371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
36157c478bd9Sstevel@tonic-gate	else
3616daaffb31Sdp		print " ---"
36177c478bd9Sstevel@tonic-gate	fi
36187c478bd9Sstevel@tonic-gate
3619daaffb31Sdp	if [[ -f $F.patch ]]; then
3620371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3621371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3622daaffb31Sdp	else
3623daaffb31Sdp		print " -----"
3624daaffb31Sdp	fi
3625daaffb31Sdp
3626daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3627371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3628371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3629daaffb31Sdp	else
3630daaffb31Sdp		print " ---"
3631daaffb31Sdp	fi
3632daaffb31Sdp
3633cdf0c1d5Smjnelson	print "<b>$P</b>"
3634cdf0c1d5Smjnelson
3635cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3636e6ccc173SEdward Pilatowicz	if [[ -f "$oldname" ]]; then
3637cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3638e6ccc173SEdward Pilatowicz			print "<i>(copied from $oldname)</i>"
3639cdf0c1d5Smjnelson		else
3640e6ccc173SEdward Pilatowicz			print "<i>(copied and modified from $oldname)</i>"
3641e6ccc173SEdward Pilatowicz		fi
3642e6ccc173SEdward Pilatowicz	elif [[ -n "$oldname" ]]; then
3643e6ccc173SEdward Pilatowicz		if [[ -n "$mv_but_nodiff" ]]; then
3644e6ccc173SEdward Pilatowicz			print "<i>(renamed from $oldname)</i>"
3645e6ccc173SEdward Pilatowicz		else
3646e6ccc173SEdward Pilatowicz			print "<i>(renamed and modified from $oldname)</i>"
3647cdf0c1d5Smjnelson		fi
3648cdf0c1d5Smjnelson	fi
3649cdf0c1d5Smjnelson
3650cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3651cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3652cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3653cdf0c1d5Smjnelson	fi
3654daaffb31Sdp
3655daaffb31Sdp	#
3656e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3657daaffb31Sdp	#
3658daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3659e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3660e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3661daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3662daaffb31Sdp			    "this review</i>"
3663daaffb31Sdp		fi
3664daaffb31Sdp	fi
3665daaffb31Sdp
3666daaffb31Sdp	print "</p>"
36677c478bd9Sstevel@tonic-gate	# Insert delta comments
36687c478bd9Sstevel@tonic-gate
3669daaffb31Sdp	print "<blockquote><pre>"
3670daaffb31Sdp	getcomments html $P $PP
3671daaffb31Sdp	print "</pre>"
36727c478bd9Sstevel@tonic-gate
36737c478bd9Sstevel@tonic-gate	# Add additional comments comment
36747c478bd9Sstevel@tonic-gate
3675daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
36767c478bd9Sstevel@tonic-gate
36777c478bd9Sstevel@tonic-gate	# Add count of changes.
36787c478bd9Sstevel@tonic-gate
3679daaffb31Sdp	if [[ -f $F.count ]]; then
36807c478bd9Sstevel@tonic-gate	    cat $F.count
36817c478bd9Sstevel@tonic-gate	    rm $F.count
36827c478bd9Sstevel@tonic-gate	fi
3683cdf0c1d5Smjnelson
3684cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3685cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3686cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3687cdf0c1d5Smjnelson
3688cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3689cdf0c1d5Smjnelson		# 1) New executable files
3690cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3691cdf0c1d5Smjnelson		# 3) Existing executable files
3692cdf0c1d5Smjnelson
3693cdf0c1d5Smjnelson		old_mode=
3694cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3695cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3696cdf0c1d5Smjnelson		fi
3697cdf0c1d5Smjnelson
3698cdf0c1d5Smjnelson		new_mode=
3699cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3700cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3701cdf0c1d5Smjnelson		fi
3702cdf0c1d5Smjnelson
3703cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3704cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3705cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3706cdf0c1d5Smjnelson			print "</span>"
3707cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3708cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3709cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3710cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3711cdf0c1d5Smjnelson			print "</span>"
3712cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3713cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3714cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3715cdf0c1d5Smjnelson			print "</span>"
3716cdf0c1d5Smjnelson		fi
3717cdf0c1d5Smjnelson	fi
3718cdf0c1d5Smjnelson
3719daaffb31Sdp	print "</blockquote>"
37207c478bd9Sstevel@tonic-gatedone
37217c478bd9Sstevel@tonic-gate
3722daaffb31Sdpprint
3723daaffb31Sdpprint
3724cac38512Smjnelsonprint "<hr></hr>"
3725daaffb31Sdpprint "<p style=\"font-size: small\">"
37269a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
372787a4464eSChris Loveprint "Webrev is maintained by the <a href=\"http://www.illumos.org\">"
372887a4464eSChris Loveprint "illumos</a> project.  The latest version may be obtained"
372987a4464eSChris Loveprint "<a href=\"http://src.illumos.org/source/xref/illumos-opengrok/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3730daaffb31Sdpprint "</body>"
3731daaffb31Sdpprint "</html>"
37327c478bd9Sstevel@tonic-gate
37337c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
37347c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
37357c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
37367c478bd9Sstevel@tonic-gate
3737daaffb31Sdpprint "Done."
373802d26c39SVladimir Kotal
3739b0088928SVladimir Kotal#
3740ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3741b0088928SVladimir Kotal#
3742ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3743b0088928SVladimir Kotal	delete_webrev 1 1
3744ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3745ba44d8a2SVladimir Kotalfi
3746ba44d8a2SVladimir Kotal
374702d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
374802d26c39SVladimir Kotal	upload_webrev
374902d26c39SVladimir Kotal	exit $?
375002d26c39SVladimir Kotalfi
3751