xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 7646c8f36bab39004fcffc7287250ea06924088e)
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
28*7646c8f3SMarcel Telka# Copyright 2012 Marcel Telka <marcel@telka.sk>
292f54b716SRichard Lowe
30cdf0c1d5Smjnelson#
31daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
32daaffb31Sdp# suitable for doing a code review of source changes via a web page.
33daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
34daaffb31Sdp# type 'webrev -h'.
357c478bd9Sstevel@tonic-gate#
36daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
37daaffb31Sdp# man page.
387c478bd9Sstevel@tonic-gate#
39daaffb31Sdp
407c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
417c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
427c478bd9Sstevel@tonic-gateNEW_COLOR=blue
437c478bd9Sstevel@tonic-gate
44daaffb31SdpHTML='<?xml version="1.0"?>
45daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
46daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
47daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
48daaffb31Sdp
49daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
50daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
51daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
52daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
53daaffb31Sdp
54cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
55cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
56cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
57daaffb31Sdp<!--
58daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
59daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
60daaffb31Sdp   mechanism available in some browsers.
61daaffb31Sdp
62daaffb31Sdp   For example, to have all "removed" information be red instead of
63daaffb31Sdp   brown, set a rule in your userContent.css file like:
64daaffb31Sdp
65daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
66daaffb31Sdp-->
67daaffb31Sdp<style type="text/css" media="screen">
68daaffb31Sdpbody {
69daaffb31Sdp    background-color: #eeeeee;
70daaffb31Sdp}
71daaffb31Sdphr {
72daaffb31Sdp    border: none 0;
73daaffb31Sdp    border-top: 1px solid #aaa;
74daaffb31Sdp    height: 1px;
75daaffb31Sdp}
76daaffb31Sdpdiv.summary {
77daaffb31Sdp    font-size: .8em;
78daaffb31Sdp    border-bottom: 1px solid #aaa;
79daaffb31Sdp    padding-left: 1em;
80daaffb31Sdp    padding-right: 1em;
81daaffb31Sdp}
82daaffb31Sdpdiv.summary h2 {
83daaffb31Sdp    margin-bottom: 0.3em;
84daaffb31Sdp}
85daaffb31Sdpdiv.summary table th {
86daaffb31Sdp    text-align: right;
87daaffb31Sdp    vertical-align: top;
88daaffb31Sdp    white-space: nowrap;
89daaffb31Sdp}
90daaffb31Sdpspan.lineschanged {
91daaffb31Sdp    font-size: 0.7em;
92daaffb31Sdp}
93daaffb31Sdpspan.oldmarker {
94daaffb31Sdp    color: red;
95daaffb31Sdp    font-size: large;
96daaffb31Sdp    font-weight: bold;
97daaffb31Sdp}
98daaffb31Sdpspan.newmarker {
99daaffb31Sdp    color: green;
100daaffb31Sdp    font-size: large;
101daaffb31Sdp    font-weight: bold;
102daaffb31Sdp}
103daaffb31Sdpspan.removed {
104daaffb31Sdp    color: brown;
105daaffb31Sdp}
106daaffb31Sdpspan.changed {
107daaffb31Sdp    color: blue;
108daaffb31Sdp}
109daaffb31Sdpspan.new {
110daaffb31Sdp    color: blue;
111daaffb31Sdp    font-weight: bold;
112daaffb31Sdp}
113cdf0c1d5Smjnelsonspan.chmod {
114cdf0c1d5Smjnelson    font-size: 0.7em;
115cdf0c1d5Smjnelson    color: #db7800;
116cdf0c1d5Smjnelson}
117daaffb31Sdpa.print { font-size: x-small; }
118daaffb31Sdpa:hover { background-color: #ffcc99; }
119daaffb31Sdp</style>
120daaffb31Sdp
121daaffb31Sdp<style type="text/css" media="print">
122daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
123daaffb31Sdpspan.removed { color: #444; font-style: italic }
124daaffb31Sdpspan.changed { font-weight: bold; }
125daaffb31Sdpspan.new { font-weight: bold; }
126daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
127daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
128daaffb31Sdpa.print {display: none}
129daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
130daaffb31Sdp</style>
131daaffb31Sdp'
132daaffb31Sdp
133daaffb31Sdp#
134daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
135daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
136daaffb31Sdp#
137daaffb31SdpUDIFFCSS='
138daaffb31Sdp<style type="text/css" media="screen">
139daaffb31Sdpspan.new {
140daaffb31Sdp    color: blue;
141daaffb31Sdp    font-weight: normal;
142daaffb31Sdp}
143daaffb31Sdp</style>
144daaffb31Sdp'
145daaffb31Sdp
146b0088928SVladimir Kotal#
147b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
148b0088928SVladimir Kotal#
149b0088928SVladimir Kotalfunction print_upload_header
150b0088928SVladimir Kotal{
151b0088928SVladimir Kotal	typeset -r prefix=$1
152b0088928SVladimir Kotal	typeset display_target
153b0088928SVladimir Kotal
154b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
155b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
156b0088928SVladimir Kotal	else
157b0088928SVladimir Kotal		display_target=${remote_target}
158b0088928SVladimir Kotal	fi
159b0088928SVladimir Kotal
160b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
161b0088928SVladimir Kotal		display_target=${display_target}/
162b0088928SVladimir Kotal	fi
163b0088928SVladimir Kotal
164b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
165b0088928SVladimir Kotal	    "     Uploading: \c"
166b0088928SVladimir Kotal}
167b0088928SVladimir Kotal
168b0088928SVladimir Kotal#
16902d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
170b0088928SVladimir Kotal#
171ba44d8a2SVladimir Kotalfunction rsync_upload
17202d26c39SVladimir Kotal{
173b0088928SVladimir Kotal	if (( $# != 2 )); then
174b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
175b0088928SVladimir Kotal		exit 1
17602d26c39SVladimir Kotal	fi
17702d26c39SVladimir Kotal
178b0088928SVladimir Kotal	typeset -r dst=$1
179b0088928SVladimir Kotal	integer -r print_err_msg=$2
18002d26c39SVladimir Kotal
181b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
182b0088928SVladimir Kotal	print "rsync ... \c"
1838a34f8dcSVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
184b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
185b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
186b0088928SVladimir Kotal		return 1
187b0088928SVladimir Kotal	fi
188b0088928SVladimir Kotal	#
189b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
190b0088928SVladimir Kotal	# directory contents, not the whole directory.
191b0088928SVladimir Kotal	#
192b0088928SVladimir Kotal	typeset src_dir=$WDIR
193b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
194b0088928SVladimir Kotal		src_dir=${src_dir}/
195b0088928SVladimir Kotal	fi
196b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
19702d26c39SVladimir Kotal	if (( $? != 0 )); then
198b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
199b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
200b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
201b0088928SVladimir Kotal			print "error messages:"
202b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
203b0088928SVladimir Kotal			rm -f $err_msg
204b0088928SVladimir Kotal		fi
20502d26c39SVladimir Kotal		return 1
20602d26c39SVladimir Kotal	fi
20702d26c39SVladimir Kotal
208b0088928SVladimir Kotal	rm -f $err_msg
20902d26c39SVladimir Kotal	print "Done."
21002d26c39SVladimir Kotal	return 0
21102d26c39SVladimir Kotal}
21202d26c39SVladimir Kotal
213b0088928SVladimir Kotal#
214b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
215b0088928SVladimir Kotal# 1 on failure.
216b0088928SVladimir Kotal#
217b0088928SVladimir Kotalfunction remote_mkdirs
218b0088928SVladimir Kotal{
219b0088928SVladimir Kotal	typeset -r dir_spec=$1
2209d3952abSVladimir Kotal	typeset -r host_spec=$2
221b0088928SVladimir Kotal
222b0088928SVladimir Kotal	#
223b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
224b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
225b0088928SVladimir Kotal	# except the last one which will be created by scp.
226b0088928SVladimir Kotal	#
227b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
228b0088928SVladimir Kotal		print "mkdirs \c"
229b0088928SVladimir Kotal		#
230b0088928SVladimir Kotal		# Remove the last directory from directory specification.
231b0088928SVladimir Kotal		#
232b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
2338a34f8dcSVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP \
2348a34f8dcSVladimir Kotal		    /tmp/webrev_mkdir.XXXXXX )
235b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
236b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
237b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
238b0088928SVladimir Kotal			return 1
239b0088928SVladimir Kotal		fi
240b0088928SVladimir Kotal                OLDIFS=$IFS
241b0088928SVladimir Kotal                IFS=/
242b0088928SVladimir Kotal		typeset dir
243b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
244b0088928SVladimir Kotal			#
245b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
246b0088928SVladimir Kotal			# to avoid an error in case the directory already
247b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
248b0088928SVladimir Kotal			# there is one.
249b0088928SVladimir Kotal			#
250b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
251b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
252b0088928SVladimir Kotal                done
253b0088928SVladimir Kotal                IFS=$OLDIFS
2548a34f8dcSVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
255b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
256b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
257b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
258b0088928SVladimir Kotal			return 1
259b0088928SVladimir Kotal		fi
260b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
261b0088928SVladimir Kotal		if (( $? != 0 )); then
262b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
263b0088928SVladimir Kotal			print "error messages:"
264b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
265b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
266b0088928SVladimir Kotal			return 1
267b0088928SVladimir Kotal		fi
268b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
269b0088928SVladimir Kotal	fi
270b0088928SVladimir Kotal
271b0088928SVladimir Kotal	return 0
272b0088928SVladimir Kotal}
273b0088928SVladimir Kotal
274b0088928SVladimir Kotal#
27502d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
276b0088928SVladimir Kotal#
277ba44d8a2SVladimir Kotalfunction ssh_upload
27802d26c39SVladimir Kotal{
27902d26c39SVladimir Kotal	if (( $# != 1 )); then
280b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
281b0088928SVladimir Kotal		exit 1
28202d26c39SVladimir Kotal	fi
28302d26c39SVladimir Kotal
28402d26c39SVladimir Kotal	typeset dst=$1
28502d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
286ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
28702d26c39SVladimir Kotal
288b0088928SVladimir Kotal	#
289b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
290b0088928SVladimir Kotal	# because it will also print its progress.
291b0088928SVladimir Kotal	#
292b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
293b0088928SVladimir Kotal
294b0088928SVladimir Kotal	#
295b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
296b0088928SVladimir Kotal	# to perform it again.
297b0088928SVladimir Kotal	#
298ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
299b0088928SVladimir Kotal		#
300b0088928SVladimir Kotal		# We do not care about return value because this might be
301b0088928SVladimir Kotal		# the first time this directory is uploaded.
302b0088928SVladimir Kotal		#
303ba44d8a2SVladimir Kotal		delete_webrev 0
30402d26c39SVladimir Kotal	fi
30502d26c39SVladimir Kotal
306b0088928SVladimir Kotal	#
307b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
308b0088928SVladimir Kotal	# in remote_mkdirs function.
309b0088928SVladimir Kotal	#
3109d3952abSVladimir Kotal	remote_mkdirs ${dir_spec} ${host_spec}
31102d26c39SVladimir Kotal	if (( $? != 0 )); then
31202d26c39SVladimir Kotal		return 1
31302d26c39SVladimir Kotal	fi
31402d26c39SVladimir Kotal
315b0088928SVladimir Kotal	print "upload ... \c"
3168a34f8dcSVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
317b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
318b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
319b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
320b0088928SVladimir Kotal		return 1
321b0088928SVladimir Kotal	fi
32202d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
323b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
32402d26c39SVladimir Kotal	if (( $? != 0 )); then
325b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
326b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
327b0088928SVladimir Kotal		print "error messages:"
328b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
329b0088928SVladimir Kotal		rm -f ${scp_err_msg}
33002d26c39SVladimir Kotal		return 1
33102d26c39SVladimir Kotal	fi
33202d26c39SVladimir Kotal
333b0088928SVladimir Kotal	rm -f ${scp_err_msg}
33402d26c39SVladimir Kotal	print "Done."
33502d26c39SVladimir Kotal	return 0
33602d26c39SVladimir Kotal}
33702d26c39SVladimir Kotal
33802d26c39SVladimir Kotal#
339ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
340b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
341b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
342b0088928SVladimir Kotal# only performs deletion.
343ba44d8a2SVladimir Kotal#
344ba44d8a2SVladimir Kotalfunction delete_webrev
345ba44d8a2SVladimir Kotal{
346b0088928SVladimir Kotal	if (( $# < 1 )); then
347b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
348b0088928SVladimir Kotal		exit 1
349ba44d8a2SVladimir Kotal	fi
350ba44d8a2SVladimir Kotal
351b0088928SVladimir Kotal	integer -r check=$1
352b0088928SVladimir Kotal	integer delete_only=0
353b0088928SVladimir Kotal	if (( $# == 2 )); then
354b0088928SVladimir Kotal		delete_only=1
355b0088928SVladimir Kotal	fi
356b0088928SVladimir Kotal
357b0088928SVladimir Kotal	#
358ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
359b0088928SVladimir Kotal	#
360ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
361ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
362ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
363ba44d8a2SVladimir Kotal	typeset dir_rm
364ba44d8a2SVladimir Kotal
365b0088928SVladimir Kotal	#
366ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
367b0088928SVladimir Kotal	#
368ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
369ba44d8a2SVladimir Kotal		return 1
370ba44d8a2SVladimir Kotal	fi
371ba44d8a2SVladimir Kotal
372b0088928SVladimir Kotal	#
373ba44d8a2SVladimir Kotal	# Strip the ending slash.
374b0088928SVladimir Kotal	#
375ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
376ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
377ba44d8a2SVladimir Kotal	else
378ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
379ba44d8a2SVladimir Kotal	fi
380ba44d8a2SVladimir Kotal
381b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
382b0088928SVladimir Kotal		print "       Removing: \c"
383b0088928SVladimir Kotal	else
384b0088928SVladimir Kotal		print "rmdir \c"
385b0088928SVladimir Kotal	fi
386ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
387b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
388ba44d8a2SVladimir Kotal		return 1
389ba44d8a2SVladimir Kotal	fi
390ba44d8a2SVladimir Kotal
391b0088928SVladimir Kotal	#
392ba44d8a2SVladimir Kotal	# Prepare batch file.
393b0088928SVladimir Kotal	#
3948a34f8dcSVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
395ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
396b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
397ba44d8a2SVladimir Kotal		return 1
398ba44d8a2SVladimir Kotal	fi
399ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
400ba44d8a2SVladimir Kotal
401b0088928SVladimir Kotal	#
402ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
403b0088928SVladimir Kotal	#
4048a34f8dcSVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
405b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
406b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
407b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
408b0088928SVladimir Kotal		return 1
409b0088928SVladimir Kotal	fi
410b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
411ba44d8a2SVladimir Kotal	integer -r ret=$?
412ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
413ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
414b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
415b0088928SVladimir Kotal		print "error messages:"
416b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
417b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
418ba44d8a2SVladimir Kotal		return $ret
419ba44d8a2SVladimir Kotal	fi
420b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
421b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
422ba44d8a2SVladimir Kotal		print "Done."
423b0088928SVladimir Kotal	fi
424ba44d8a2SVladimir Kotal
425ba44d8a2SVladimir Kotal	return 0
426ba44d8a2SVladimir Kotal}
427ba44d8a2SVladimir Kotal
428ba44d8a2SVladimir Kotal#
42902d26c39SVladimir Kotal# Upload webrev to remote site
43002d26c39SVladimir Kotal#
431ba44d8a2SVladimir Kotalfunction upload_webrev
43202d26c39SVladimir Kotal{
433b0088928SVladimir Kotal	integer ret
43402d26c39SVladimir Kotal
43502d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
436b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
43702d26c39SVladimir Kotal		return 1
43802d26c39SVladimir Kotal	fi
43902d26c39SVladimir Kotal
440b0088928SVladimir Kotal	#
44102d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
44202d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
44302d26c39SVladimir Kotal	# target he probably knows what he is doing.
444b0088928SVladimir Kotal	#
44502d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
446ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
44702d26c39SVladimir Kotal			| $GREP closed >/dev/null
44802d26c39SVladimir Kotal		if (( $? == 0 )); then
449b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
450b0088928SVladimir Kotal			    "\"closed\" directory"
45102d26c39SVladimir Kotal			return 1
45202d26c39SVladimir Kotal		fi
45302d26c39SVladimir Kotal	fi
45402d26c39SVladimir Kotal
455b0088928SVladimir Kotal
456b0088928SVladimir Kotal	#
457b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
458b0088928SVladimir Kotal	#
45902d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
46002d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
461b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
462b0088928SVladimir Kotal			ret=$?
463b0088928SVladimir Kotal			return $ret
46402d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
46502d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
466b0088928SVladimir Kotal			ret=$?
467b0088928SVladimir Kotal			return $ret
46802d26c39SVladimir Kotal		fi
46902d26c39SVladimir Kotal	else
470b0088928SVladimir Kotal		#
471b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
472b0088928SVladimir Kotal		#
473b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
474b0088928SVladimir Kotal		ret=$?
475b0088928SVladimir Kotal		if (( $ret != 0 )); then
476b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
477ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
478b0088928SVladimir Kotal			ret=$?
47902d26c39SVladimir Kotal		fi
480b0088928SVladimir Kotal		return $ret
48102d26c39SVladimir Kotal	fi
48202d26c39SVladimir Kotal}
48302d26c39SVladimir Kotal
484daaffb31Sdp#
485371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
486371d72daSLubomir Sedlacik#
487371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
488371d72daSLubomir Sedlacik#
489371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
490371d72daSLubomir Sedlacik#
491371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
492371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
493371d72daSLubomir Sedlacik# a path delimiter.
494371d72daSLubomir Sedlacik#
49525cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make
49625cc4e45SVladimir Kotal# the substitution work with GNU sed.
49725cc4e45SVladimir Kotal#
498371d72daSLubomir Sedlacikfunction url_encode
499371d72daSLubomir Sedlacik{
500b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
501371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
502371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
503371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
50425cc4e45SVladimir Kotal	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
505371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
506371d72daSLubomir Sedlacik}
507371d72daSLubomir Sedlacik
508371d72daSLubomir Sedlacik#
509daaffb31Sdp# input_cmd | html_quote | output_cmd
510daaffb31Sdp# or
511daaffb31Sdp# html_quote filename | output_cmd
5127c478bd9Sstevel@tonic-gate#
5137c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5147c478bd9Sstevel@tonic-gate#
5157c478bd9Sstevel@tonic-gatehtml_quote()
5167c478bd9Sstevel@tonic-gate{
517b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5187c478bd9Sstevel@tonic-gate}
5197c478bd9Sstevel@tonic-gate
520daaffb31Sdp#
5218bcea973SRichard Lowe# Trim a digest-style revision to a conventionally readable yet useful length
5228bcea973SRichard Lowe#
5238bcea973SRichard Lowetrim_digest()
5248bcea973SRichard Lowe{
5258bcea973SRichard Lowe	typeset digest=$1
5268bcea973SRichard Lowe
5278bcea973SRichard Lowe	echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'
5288bcea973SRichard Lowe}
5298bcea973SRichard Lowe
5308bcea973SRichard Lowe#
5310fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
532daaffb31Sdp#
5330fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
5340fd2682eSMark J. Nelson# relevant databases.
535daaffb31Sdp#
5360fd2682eSMark J. Nelsonits2url()
5377c478bd9Sstevel@tonic-gate{
5380fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
539daaffb31Sdp}
540daaffb31Sdp
5417c478bd9Sstevel@tonic-gate#
542daaffb31Sdp# strip_unchanged <infile> | output_cmd
5437c478bd9Sstevel@tonic-gate#
544daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
545daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5467c478bd9Sstevel@tonic-gate#
547daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
548daaffb31Sdp# identical lines are retained before and after the changed lines to
549daaffb31Sdp# provide some context.  The number of these lines is controlled by the
550cdf0c1d5Smjnelson# variable C in the $AWK script below.
551daaffb31Sdp#
552daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
553daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
554daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
555daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
556daaffb31Sdp#
557daaffb31Sdpstrip_unchanged()
558daaffb31Sdp{
559cdf0c1d5Smjnelson	$AWK '
560daaffb31Sdp	BEGIN	{ C = c = 20 }
561cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
562daaffb31Sdp		if (c > C) {
563daaffb31Sdp			c -= C
564daaffb31Sdp			inx = 0
565daaffb31Sdp			if (c > C) {
566cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
567daaffb31Sdp				inx = c % C
568daaffb31Sdp				c = C
569daaffb31Sdp			}
570daaffb31Sdp
571daaffb31Sdp			for (i = 0; i < c; i++)
572daaffb31Sdp				print ln[(inx + i) % C]
573daaffb31Sdp		}
574daaffb31Sdp		c = 0;
575daaffb31Sdp		print
576daaffb31Sdp		next
577daaffb31Sdp	}
578daaffb31Sdp	{	if (c >= C) {
579daaffb31Sdp			ln[c % C] = $0
580daaffb31Sdp			c++;
581daaffb31Sdp			next;
582daaffb31Sdp		}
583daaffb31Sdp		c++;
584daaffb31Sdp		print
585daaffb31Sdp	}
586cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
587daaffb31Sdp
588daaffb31Sdp	' $1
589daaffb31Sdp}
590daaffb31Sdp
591daaffb31Sdp#
592daaffb31Sdp# sdiff_to_html
593daaffb31Sdp#
594daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
595daaffb31Sdp# processes the diff output to present the files as an HTML document with
596daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
597daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
598daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
599daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
600daaffb31Sdp# e.g.
601daaffb31Sdp#
602daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
603daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
604daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
605daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
606daaffb31Sdp#          1234567</a> my bugid' > <file>.html
607daaffb31Sdp#
608daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
609daaffb31Sdp# in the webrev tree.
610daaffb31Sdp#
611daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
612daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
613daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
614daaffb31Sdp# the editing codes, e.g.
6157c478bd9Sstevel@tonic-gate#
6167c478bd9Sstevel@tonic-gate#      8c8
6177c478bd9Sstevel@tonic-gate#      57a61
6187c478bd9Sstevel@tonic-gate#      63c66,76
6197c478bd9Sstevel@tonic-gate#      68,93d80
6207c478bd9Sstevel@tonic-gate#      106d90
6217c478bd9Sstevel@tonic-gate#      108,110d91
6227c478bd9Sstevel@tonic-gate#
623daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
624daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
625daaffb31Sdp#  into something like this:
6267c478bd9Sstevel@tonic-gate#
6277c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6287c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
629daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6307c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6317c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6327c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6337c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6347c478bd9Sstevel@tonic-gate#        :               :
6357c478bd9Sstevel@tonic-gate#
636daaffb31Sdp#  This script is then run on the original source file to generate the
637daaffb31Sdp#  HTML that corresponds to the source file.
6387c478bd9Sstevel@tonic-gate#
639daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
640daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
641daaffb31Sdp#  notice that the changes are color-coded:
6427c478bd9Sstevel@tonic-gate#
6437c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6447c478bd9Sstevel@tonic-gate#   blue      - changed lines
6457c478bd9Sstevel@tonic-gate#   bold blue - new lines
6467c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6477c478bd9Sstevel@tonic-gate#
648daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
649daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
650daaffb31Sdp#  Teamware's filemerge tool.
651daaffb31Sdp#
652daaffb31Sdpsdiff_to_html()
653daaffb31Sdp{
6547c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6557c478bd9Sstevel@tonic-gate
656daaffb31Sdp	TNAME=$3
657daaffb31Sdp	TPATH=$4
658daaffb31Sdp	COMMENT=$5
659daaffb31Sdp
6607c478bd9Sstevel@tonic-gate	#
6617c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6627c478bd9Sstevel@tonic-gate	#
663cdf0c1d5Smjnelson	$AWK '
6647c478bd9Sstevel@tonic-gate	BEGIN	{
6657c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
666daaffb31Sdp		printf "function removed() "
667daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
668daaffb31Sdp		printf "function changed() "
669daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
670daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6717c478bd9Sstevel@tonic-gate}
6727c478bd9Sstevel@tonic-gate	/^</	{next}
6737c478bd9Sstevel@tonic-gate	/^>/	{next}
6747c478bd9Sstevel@tonic-gate	/^---/	{next}
675daaffb31Sdp
6767c478bd9Sstevel@tonic-gate	{
6777c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6787c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6797c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6807c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6817c478bd9Sstevel@tonic-gate			if (n == 1)
6827c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6837c478bd9Sstevel@tonic-gate			else
6847c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6857c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6867c478bd9Sstevel@tonic-gate			next
6877c478bd9Sstevel@tonic-gate		}
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6907c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6917c478bd9Sstevel@tonic-gate		s = r[1];
6927c478bd9Sstevel@tonic-gate		if (n == 1)
6937c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6947c478bd9Sstevel@tonic-gate		else {
6957c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6967c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6977c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6987c478bd9Sstevel@tonic-gate		}
6997c478bd9Sstevel@tonic-gate		next
7007c478bd9Sstevel@tonic-gate	}
7017c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7027c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7037c478bd9Sstevel@tonic-gate		n1 = r[1]
7047c478bd9Sstevel@tonic-gate		n2 = r[2]
7057c478bd9Sstevel@tonic-gate		if (n == 1)
706daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
7077c478bd9Sstevel@tonic-gate		else
708daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
7097c478bd9Sstevel@tonic-gate		next
7107c478bd9Sstevel@tonic-gate	}
7117c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7127c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7137c478bd9Sstevel@tonic-gate		n1 = r[1]
7147c478bd9Sstevel@tonic-gate		n2 = r[2]
7157c478bd9Sstevel@tonic-gate		final = n2
7167c478bd9Sstevel@tonic-gate		d1 = 0
7177c478bd9Sstevel@tonic-gate		if (n == 1)
718daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7197c478bd9Sstevel@tonic-gate		else {
7207c478bd9Sstevel@tonic-gate			d1 = n2 - n1
721daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7227c478bd9Sstevel@tonic-gate		}
7237c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7247c478bd9Sstevel@tonic-gate		n1 = r[1]
7257c478bd9Sstevel@tonic-gate		n2 = r[2]
7267c478bd9Sstevel@tonic-gate		if (m > 1) {
7277c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7287c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7297c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7307c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7317c478bd9Sstevel@tonic-gate			}
7327c478bd9Sstevel@tonic-gate		}
7337c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate		next
7367c478bd9Sstevel@tonic-gate	}
7377c478bd9Sstevel@tonic-gate	}
7387c478bd9Sstevel@tonic-gate
739daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
740daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate	#
7437c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7447c478bd9Sstevel@tonic-gate	#
745cdf0c1d5Smjnelson	$AWK '
7467c478bd9Sstevel@tonic-gate	BEGIN	{
7477c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
748daaffb31Sdp		printf "function new() "
749daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
750daaffb31Sdp		printf "function changed() "
751daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
752daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7537c478bd9Sstevel@tonic-gate	}
754daaffb31Sdp
7557c478bd9Sstevel@tonic-gate	/^</	{next}
7567c478bd9Sstevel@tonic-gate	/^>/	{next}
7577c478bd9Sstevel@tonic-gate	/^---/	{next}
758daaffb31Sdp
7597c478bd9Sstevel@tonic-gate	{
7607c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7617c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7627c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7637c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7647c478bd9Sstevel@tonic-gate			if (n == 1)
7657c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7667c478bd9Sstevel@tonic-gate			else
7677c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7687c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7697c478bd9Sstevel@tonic-gate			next
7707c478bd9Sstevel@tonic-gate		}
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7737c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7747c478bd9Sstevel@tonic-gate		s = r[1];
7757c478bd9Sstevel@tonic-gate		if (n == 1)
7767c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7777c478bd9Sstevel@tonic-gate		else {
7787c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7797c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7807c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7817c478bd9Sstevel@tonic-gate		}
7827c478bd9Sstevel@tonic-gate		next
7837c478bd9Sstevel@tonic-gate	}
7847c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7857c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7867c478bd9Sstevel@tonic-gate		n1 = r[1]
7877c478bd9Sstevel@tonic-gate		n2 = r[2]
7887c478bd9Sstevel@tonic-gate		if (n == 1)
789daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7907c478bd9Sstevel@tonic-gate		else
791daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7927c478bd9Sstevel@tonic-gate		next
7937c478bd9Sstevel@tonic-gate	}
7947c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7957c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7967c478bd9Sstevel@tonic-gate		n1 = r[1]
7977c478bd9Sstevel@tonic-gate		n2 = r[2]
7987c478bd9Sstevel@tonic-gate		final = n2
7997c478bd9Sstevel@tonic-gate		d2 = 0;
8007c478bd9Sstevel@tonic-gate		if (n == 1) {
8017c478bd9Sstevel@tonic-gate			final = n1
802daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
8037c478bd9Sstevel@tonic-gate		} else {
8047c478bd9Sstevel@tonic-gate			d2 = n2 - n1
805daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
8067c478bd9Sstevel@tonic-gate		}
8077c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
8087c478bd9Sstevel@tonic-gate		n1 = r[1]
8097c478bd9Sstevel@tonic-gate		n2 = r[2]
8107c478bd9Sstevel@tonic-gate		if (m > 1) {
8117c478bd9Sstevel@tonic-gate			d1  = n2 - n1
8127c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8137c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8147c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8157c478bd9Sstevel@tonic-gate			}
8167c478bd9Sstevel@tonic-gate		}
8177c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8187c478bd9Sstevel@tonic-gate		next
8197c478bd9Sstevel@tonic-gate	}
8207c478bd9Sstevel@tonic-gate	}
821daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8227c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8237c478bd9Sstevel@tonic-gate
824daaffb31Sdp	#
825cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
826daaffb31Sdp	#
827cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8287c478bd9Sstevel@tonic-gate
829cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8307c478bd9Sstevel@tonic-gate
831daaffb31Sdp	#
832daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
833daaffb31Sdp	#
834daaffb31Sdp	print "$HTML<head>$STDHEAD"
835cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
836daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
837daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
838daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
839daaffb31Sdp	print "<table><tr valign=\"top\">"
840daaffb31Sdp	print "<td><pre>"
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8437c478bd9Sstevel@tonic-gate
844daaffb31Sdp	print "</pre></td><td><pre>"
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8477c478bd9Sstevel@tonic-gate
848daaffb31Sdp	print "</pre></td>"
849daaffb31Sdp	print "</tr></table>"
850daaffb31Sdp	print "</body></html>"
8517c478bd9Sstevel@tonic-gate
852daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
853daaffb31Sdp	    "$COMMENT"
8547c478bd9Sstevel@tonic-gate}
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate
857daaffb31Sdp#
858daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
859daaffb31Sdp#
860daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
861daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
862daaffb31Sdp# and then emit the main frame.  Content is placed into:
863daaffb31Sdp#
864daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
865daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
866daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
867daaffb31Sdp#
868daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
869daaffb31Sdp#
8707c478bd9Sstevel@tonic-gatefunction framed_sdiff
8717c478bd9Sstevel@tonic-gate{
8727c478bd9Sstevel@tonic-gate	typeset TNAME=$1
873daaffb31Sdp	typeset TPATH=$2
874daaffb31Sdp	typeset lhsfile=$3
875daaffb31Sdp	typeset rhsfile=$4
876daaffb31Sdp	typeset comments=$5
8777c478bd9Sstevel@tonic-gate	typeset RTOP
878daaffb31Sdp
8797c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
880daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
881daaffb31Sdp
882daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
883daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
884daaffb31Sdp
885daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8868b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8877c478bd9Sstevel@tonic-gate	    </head>
888daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
889cac38512Smjnelson	    <a name="0"></a>
890cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
891daaffb31Sdp	EOF
892daaffb31Sdp
893daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
894daaffb31Sdp
895daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
896daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
897daaffb31Sdp
898daaffb31Sdp	close='</body></html>'
899daaffb31Sdp
900daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
901daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
902daaffb31Sdp
903daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
904daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
905daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
906daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
907daaffb31Sdp	  <frameset rows="*,60">
908daaffb31Sdp	    <frameset cols="50%,50%">
909cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
910cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
911daaffb31Sdp	    </frameset>
9128b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
913cac38512Smjnelson	   marginheight="0" name="nav"></frame>
914daaffb31Sdp	  <noframes>
915daaffb31Sdp            <body id="SUNWwebrev">
916daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9177c478bd9Sstevel@tonic-gate	      and has the feature enabled.
918daaffb31Sdp            </body>
919daaffb31Sdp	  </noframes>
920daaffb31Sdp	  </frameset>
9217c478bd9Sstevel@tonic-gate	</html>
9227c478bd9Sstevel@tonic-gate	EOF
9237c478bd9Sstevel@tonic-gate}
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate
926daaffb31Sdp#
927daaffb31Sdp# fix_postscript
928daaffb31Sdp#
929daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
930daaffb31Sdp#	- removing all extraneous headers/trailers
931daaffb31Sdp#	- making the page numbers right
932daaffb31Sdp#	- removing pages devoid of contents which confuse some
933daaffb31Sdp#	  postscript readers.
934daaffb31Sdp#
935daaffb31Sdp# From Casper.
936daaffb31Sdp#
937daaffb31Sdpfunction fix_postscript
9387c478bd9Sstevel@tonic-gate{
939daaffb31Sdp	infile=$1
9407c478bd9Sstevel@tonic-gate
941daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9427c478bd9Sstevel@tonic-gate
943daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
944daaffb31Sdp	print "%%Orientation: Landscape\n";
9457c478bd9Sstevel@tonic-gate
946daaffb31Sdp	$pno = 0;
947daaffb31Sdp	$doprint = 1;
948daaffb31Sdp
949daaffb31Sdp	$page = "";
950daaffb31Sdp
951daaffb31Sdp	while (<>) {
952daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
953daaffb31Sdp
954daaffb31Sdp		if (/^%%Page:/) {
955daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
956daaffb31Sdp				# Header or single page containing text
957daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
958daaffb31Sdp				print $page;
959daaffb31Sdp				$pno++;
960daaffb31Sdp			} else {
961daaffb31Sdp				# Empty page, skip it.
9627c478bd9Sstevel@tonic-gate			}
963daaffb31Sdp			$page = "";
964daaffb31Sdp			$doprint = 1;
9657c478bd9Sstevel@tonic-gate			next;
9667c478bd9Sstevel@tonic-gate		}
9677c478bd9Sstevel@tonic-gate
968daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
969daaffb31Sdp		# %%Page of the next
970daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
971daaffb31Sdp		$page .= $_ if ($doprint);
9727c478bd9Sstevel@tonic-gate	}
9737c478bd9Sstevel@tonic-gate
974daaffb31Sdp	if ($page =~ /\)S/) {
975daaffb31Sdp		print "%%Page: ? $pno\n";
976daaffb31Sdp		print $page;
977daaffb31Sdp	} else {
978daaffb31Sdp		$pno--;
979daaffb31Sdp	}
980daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
981daaffb31SdpEOF
982daaffb31Sdp
98314983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
984daaffb31Sdp}
985daaffb31Sdp
986daaffb31Sdp
987daaffb31Sdp#
988daaffb31Sdp# input_cmd | insert_anchors | output_cmd
989daaffb31Sdp#
9907c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
991daaffb31Sdp# anchors.  These are used to drive the frames version of the
9927c478bd9Sstevel@tonic-gate# sdiffs output.
9937c478bd9Sstevel@tonic-gate#
9947c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9957c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9967c478bd9Sstevel@tonic-gate#
997daaffb31Sdp# The script detects changed lines as any line that has a "<span
998daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
999daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
10007c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
10017c478bd9Sstevel@tonic-gate# deleted.
10027c478bd9Sstevel@tonic-gate#
1003daaffb31Sdpfunction insert_anchors
1004daaffb31Sdp{
1005cdf0c1d5Smjnelson	$AWK '
10067c478bd9Sstevel@tonic-gate	function ia() {
1007daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
10087c478bd9Sstevel@tonic-gate	}
1009daaffb31Sdp
10107c478bd9Sstevel@tonic-gate	BEGIN {
1011daaffb31Sdp		anc=1;
10127c478bd9Sstevel@tonic-gate		inblock=1;
1013daaffb31Sdp		printf "<pre>\n";
10147c478bd9Sstevel@tonic-gate	}
1015daaffb31Sdp	NF == 0 || /^<span class=/ {
10167c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10177c478bd9Sstevel@tonic-gate			ia();
10187c478bd9Sstevel@tonic-gate			inblock=1;
10197c478bd9Sstevel@tonic-gate		}
10207c478bd9Sstevel@tonic-gate		print;
10217c478bd9Sstevel@tonic-gate		next;
10227c478bd9Sstevel@tonic-gate	}
10237c478bd9Sstevel@tonic-gate	{
10247c478bd9Sstevel@tonic-gate		inblock=0;
10257c478bd9Sstevel@tonic-gate		print;
10267c478bd9Sstevel@tonic-gate	}
10277c478bd9Sstevel@tonic-gate	END {
10287c478bd9Sstevel@tonic-gate		ia();
1029daaffb31Sdp
1030daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1031daaffb31Sdp		printf "--- EOF ---</b>"
10327c478bd9Sstevel@tonic-gate		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1033daaffb31Sdp		printf "</pre>"
1034daaffb31Sdp		printf "<form name=\"eof\">";
1035cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1036cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1037daaffb31Sdp		printf "</form>";
10387c478bd9Sstevel@tonic-gate	}
10397c478bd9Sstevel@tonic-gate	' $1
10407c478bd9Sstevel@tonic-gate}
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate
1043daaffb31Sdp#
1044daaffb31Sdp# relative_dir
1045daaffb31Sdp#
1046daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1047daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1048daaffb31Sdp# this function would print "../../../../".
1049daaffb31Sdp#
1050daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1051daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1052daaffb31Sdp# is not relocatable.
1053daaffb31Sdp#
1054daaffb31Sdpfunction relative_dir
10557c478bd9Sstevel@tonic-gate{
1056daaffb31Sdp        typeset cur="${1##$2?(/)}"
10578b3b7b16SMark J. Nelson
10588b3b7b16SMark J. Nelson        #
10598b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
10608b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
10618b3b7b16SMark J. Nelson        #
10620fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1063daaffb31Sdp                # Should never happen.
106414983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1065daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1066daaffb31Sdp                print -u2 "will not be relocatable!"
1067daaffb31Sdp                print $2
1068daaffb31Sdp                return
1069daaffb31Sdp        fi
1070daaffb31Sdp
10718b3b7b16SMark J. Nelson	#
10728b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
10738b3b7b16SMark J. Nelson	#
10748b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
10758b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
10768b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
10778b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
10788b3b7b16SMark J. Nelson	#    the end of a relative path.
10798b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
10808b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
10818b3b7b16SMark J. Nelson	#    level of relative separation.
10828b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
10838b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
10848b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
10858b3b7b16SMark J. Nelson	#
10860fd2682eSMark J. Nelson	print $cur | $SED -e '{
10878b3b7b16SMark J. Nelson		s:^\./*::
10888b3b7b16SMark J. Nelson		s:/$::
10898b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
10900fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
10910fd2682eSMark J. Nelson	}'
10927c478bd9Sstevel@tonic-gate}
10937c478bd9Sstevel@tonic-gate
1094daaffb31Sdp#
1095daaffb31Sdp# frame_nav_js
1096daaffb31Sdp#
1097daaffb31Sdp# Emit javascript for frame navigation
1098daaffb31Sdp#
1099daaffb31Sdpfunction frame_nav_js
11007c478bd9Sstevel@tonic-gate{
11017c478bd9Sstevel@tonic-gatecat << \EOF
11027c478bd9Sstevel@tonic-gatevar myInt;
11037c478bd9Sstevel@tonic-gatevar scrolling=0;
1104daaffb31Sdpvar sfactor = 3;
11057c478bd9Sstevel@tonic-gatevar scount=10;
11067c478bd9Sstevel@tonic-gate
11077c478bd9Sstevel@tonic-gatefunction scrollByPix() {
11087c478bd9Sstevel@tonic-gate	if (scount<=0) {
11097c478bd9Sstevel@tonic-gate		sfactor*=1.2;
11107c478bd9Sstevel@tonic-gate		scount=10;
11117c478bd9Sstevel@tonic-gate	}
11127c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11137c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11147c478bd9Sstevel@tonic-gate	scount--;
11157c478bd9Sstevel@tonic-gate}
11167c478bd9Sstevel@tonic-gate
1117daaffb31Sdpfunction scrollToAnc(num) {
1118daaffb31Sdp
1119daaffb31Sdp	// Update the value of the anchor in the form which we use as
1120daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1121daaffb31Sdp	// correcting for overflow and underflow of the value and return
1122daaffb31Sdp	// us the new value.
1123daaffb31Sdp	num = setAncValue(num);
1124daaffb31Sdp
1125daaffb31Sdp	// Set location and scroll back a little to expose previous
1126daaffb31Sdp	// lines.
1127daaffb31Sdp	//
1128daaffb31Sdp	// Note that this could be improved: it is possible although
1129daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1130daaffb31Sdp	// scroll to that location directly.
1131daaffb31Sdp	//
11327c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11337c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1134daaffb31Sdp
11357c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11367c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11377c478bd9Sstevel@tonic-gate}
11387c478bd9Sstevel@tonic-gate
1139daaffb31Sdpfunction getAncValue()
1140daaffb31Sdp{
1141daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1142daaffb31Sdp}
1143daaffb31Sdp
1144daaffb31Sdpfunction setAncValue(val)
1145daaffb31Sdp{
1146daaffb31Sdp	if (val <= 0) {
1147daaffb31Sdp		val = 0;
1148daaffb31Sdp		parent.nav.document.diff.real.value = val;
1149daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1150daaffb31Sdp		return (val);
1151daaffb31Sdp	}
1152daaffb31Sdp
1153daaffb31Sdp	//
1154daaffb31Sdp	// The way we compute the max anchor value is to stash it
1155daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1156daaffb31Sdp	// on each side, so we pluck from the left.
1157daaffb31Sdp	//
1158daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1159daaffb31Sdp	if (val < maxval) {
1160daaffb31Sdp		parent.nav.document.diff.real.value = val;
1161daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1162daaffb31Sdp		return (val);
1163daaffb31Sdp	}
1164daaffb31Sdp
1165daaffb31Sdp	// this must be: val >= maxval
1166daaffb31Sdp	val = maxval;
1167daaffb31Sdp	parent.nav.document.diff.real.value = val;
1168daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1169daaffb31Sdp	return (val);
1170daaffb31Sdp}
1171daaffb31Sdp
11727c478bd9Sstevel@tonic-gatefunction stopScroll() {
11737c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11747c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11757c478bd9Sstevel@tonic-gate		scrolling=0;
11767c478bd9Sstevel@tonic-gate	}
11777c478bd9Sstevel@tonic-gate}
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gatefunction startScroll() {
11807c478bd9Sstevel@tonic-gate	stopScroll();
11817c478bd9Sstevel@tonic-gate	scrolling=1;
11827c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11837c478bd9Sstevel@tonic-gate}
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1186daaffb31Sdp
11877c478bd9Sstevel@tonic-gate	switch (b) {
11887c478bd9Sstevel@tonic-gate	    case 1 :
1189daaffb31Sdp		scrollToAnc(-1);
11907c478bd9Sstevel@tonic-gate		break;
11917c478bd9Sstevel@tonic-gate	    case 2 :
1192daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11937c478bd9Sstevel@tonic-gate		break;
11947c478bd9Sstevel@tonic-gate	    case 3 :
11957c478bd9Sstevel@tonic-gate		sfactor=-3;
11967c478bd9Sstevel@tonic-gate		startScroll();
11977c478bd9Sstevel@tonic-gate		break;
11987c478bd9Sstevel@tonic-gate	    case 4 :
11997c478bd9Sstevel@tonic-gate		sfactor=3;
12007c478bd9Sstevel@tonic-gate		startScroll();
12017c478bd9Sstevel@tonic-gate		break;
12027c478bd9Sstevel@tonic-gate	    case 5 :
1203daaffb31Sdp		scrollToAnc(getAncValue() + 1);
12047c478bd9Sstevel@tonic-gate		break;
12057c478bd9Sstevel@tonic-gate	    case 6 :
1206daaffb31Sdp		scrollToAnc(999999);
12077c478bd9Sstevel@tonic-gate		break;
12087c478bd9Sstevel@tonic-gate	}
12097c478bd9Sstevel@tonic-gate}
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
12127c478bd9Sstevel@tonic-gate	stopScroll();
12137c478bd9Sstevel@tonic-gate}
12147c478bd9Sstevel@tonic-gate
1215daaffb31Sdpfunction keypress(ev) {
1216daaffb31Sdp	var keynum;
1217daaffb31Sdp	var keychar;
1218daaffb31Sdp
1219daaffb31Sdp	if (window.event) { // IE
1220daaffb31Sdp		keynum = ev.keyCode;
1221daaffb31Sdp	} else if (ev.which) { // non-IE
1222daaffb31Sdp		keynum = ev.which;
1223daaffb31Sdp	}
1224daaffb31Sdp
1225daaffb31Sdp	keychar = String.fromCharCode(keynum);
1226daaffb31Sdp
1227daaffb31Sdp	if (keychar == "k") {
1228daaffb31Sdp		handlePress(2);
1229daaffb31Sdp		return (0);
1230daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1231daaffb31Sdp		handlePress(5);
1232daaffb31Sdp		return (0);
1233daaffb31Sdp	}
1234daaffb31Sdp	return (1);
1235daaffb31Sdp}
1236daaffb31Sdp
12377c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1238daaffb31Sdp	val = parent.nav.document.diff.display.value;
1239daaffb31Sdp	if (val == "EOF") {
1240daaffb31Sdp		scrollToAnc(999999);
1241daaffb31Sdp		return;
1242daaffb31Sdp	}
1243daaffb31Sdp
1244daaffb31Sdp	if (val == "BOF") {
1245daaffb31Sdp		scrollToAnc(0);
1246daaffb31Sdp		return;
1247daaffb31Sdp	}
1248daaffb31Sdp
1249daaffb31Sdp        i=parseInt(val);
12507c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1251daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12527c478bd9Sstevel@tonic-gate        } else {
1253daaffb31Sdp                scrollToAnc(i);
12547c478bd9Sstevel@tonic-gate        }
12557c478bd9Sstevel@tonic-gate        return false;
12567c478bd9Sstevel@tonic-gate}
12577c478bd9Sstevel@tonic-gate
1258daaffb31SdpEOF
1259daaffb31Sdp}
1260daaffb31Sdp
1261daaffb31Sdp#
1262daaffb31Sdp# frame_navigation
1263daaffb31Sdp#
1264daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1265daaffb31Sdp#
1266daaffb31Sdpfunction frame_navigation
1267daaffb31Sdp{
1268daaffb31Sdp	print "$HTML<head>$STDHEAD"
1269daaffb31Sdp
1270daaffb31Sdp	cat << \EOF
1271daaffb31Sdp<title>Anchor Navigation</title>
1272daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1273daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1274daaffb31Sdp
1275daaffb31Sdp<style type="text/css">
1276daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1277daaffb31Sdp		    background-color: #eee; text-align: center;
1278daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1279daaffb31Sdp    div.button a { font-weight: bold; color: black }
1280daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1281daaffb31Sdp</style>
1282daaffb31SdpEOF
1283daaffb31Sdp
1284cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1285daaffb31Sdp
1286daaffb31Sdp	cat << \EOF
12877c478bd9Sstevel@tonic-gate</head>
1288daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1289daaffb31Sdp	onkeypress="keypress(event);">
12907c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12917c478bd9Sstevel@tonic-gate      <center>
1292cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12937c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12947c478bd9Sstevel@tonic-gate      </center>
12957c478bd9Sstevel@tonic-gate    </noscript>
12967c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1297daaffb31Sdp	<tr>
1298daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1299daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1300daaffb31Sdp          at right</td>
1301daaffb31Sdp	  <td align="center" valign="top" width="50%">
13027c478bd9Sstevel@tonic-gate	    <div class="button">
1303daaffb31Sdp	      <table border="0" align="center">
1304daaffb31Sdp                  <tr>
1305daaffb31Sdp		    <td>
13067c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
13077c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
13087c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
13097c478bd9Sstevel@tonic-gate			 onClick="return false;"
13107c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1311daaffb31Sdp		    <td>
13127c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13137c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13147c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13157c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1316daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1317daaffb31Sdp		    <td>
13187c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13197c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13207c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13217c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13227c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13237c478bd9Sstevel@tonic-gate		    </td></tr>
1324daaffb31Sdp
13257c478bd9Sstevel@tonic-gate		  <tr>
1326daaffb31Sdp		    <td>
13277c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13287c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13297c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13307c478bd9Sstevel@tonic-gate			 onClick="return false;"
13317c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1332daaffb31Sdp		    <td>
13337c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13347c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13357c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13367c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1337daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1338daaffb31Sdp		    <td>
13397c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13407c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13417c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13427c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13437c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1344daaffb31Sdp		  </tr>
1345daaffb31Sdp              </table>
1346daaffb31Sdp	    </div>
1347daaffb31Sdp	  </td>
13487c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1349daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1350cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1351cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13527c478bd9Sstevel@tonic-gate	    </form>
13537c478bd9Sstevel@tonic-gate	  </th>
1354daaffb31Sdp	</tr>
13557c478bd9Sstevel@tonic-gate    </table>
13567c478bd9Sstevel@tonic-gate  </body>
13577c478bd9Sstevel@tonic-gate</html>
13587c478bd9Sstevel@tonic-gateEOF
13597c478bd9Sstevel@tonic-gate}
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate
1362daaffb31Sdp
1363daaffb31Sdp#
1364daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1365daaffb31Sdp#
1366daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1367daaffb31Sdp# context or unified diffs.
1368daaffb31Sdp#
13697c478bd9Sstevel@tonic-gatediff_to_html()
13707c478bd9Sstevel@tonic-gate{
13717c478bd9Sstevel@tonic-gate	TNAME=$1
1372daaffb31Sdp	TPATH=$2
1373daaffb31Sdp	DIFFTYPE=$3
1374daaffb31Sdp	COMMENT=$4
1375daaffb31Sdp
1376daaffb31Sdp	print "$HTML<head>$STDHEAD"
1377daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1378daaffb31Sdp
1379daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1380daaffb31Sdp		print "$UDIFFCSS"
1381daaffb31Sdp	fi
1382daaffb31Sdp
1383daaffb31Sdp	cat <<-EOF
1384daaffb31Sdp	</head>
1385daaffb31Sdp	<body id="SUNWwebrev">
1386daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1387daaffb31Sdp	<pre>$COMMENT</pre>
1388daaffb31Sdp        <pre>
1389daaffb31Sdp	EOF
13907c478bd9Sstevel@tonic-gate
1391cdf0c1d5Smjnelson	html_quote | $AWK '
1392daaffb31Sdp	/^--- new/	{ next }
1393daaffb31Sdp	/^\+\+\+ new/	{ next }
1394daaffb31Sdp	/^--- old/	{ next }
1395daaffb31Sdp	/^\*\*\* old/	{ next }
1396daaffb31Sdp	/^\*\*\*\*/	{ next }
13977c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1398cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1399daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1400daaffb31Sdp			  next}
1401daaffb31Sdp
1402cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1403daaffb31Sdp			  next}
1404daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1405daaffb31Sdp			  next}
1406daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1407daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1408daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1409daaffb31Sdp			{printf "%s\n", $0; next}
14107c478bd9Sstevel@tonic-gate	'
1411daaffb31Sdp
1412daaffb31Sdp	print "</pre></body></html>\n"
14137c478bd9Sstevel@tonic-gate}
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate
1416daaffb31Sdp#
1417daaffb31Sdp# source_to_html { new | old } <filename>
1418daaffb31Sdp#
1419daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1420daaffb31Sdp#
14217c478bd9Sstevel@tonic-gatesource_to_html()
14227c478bd9Sstevel@tonic-gate{
14237c478bd9Sstevel@tonic-gate	WHICH=$1
14247c478bd9Sstevel@tonic-gate	TNAME=$2
14257c478bd9Sstevel@tonic-gate
1426daaffb31Sdp	print "$HTML<head>$STDHEAD"
1427cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1428daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1429daaffb31Sdp	print "<pre>"
1430cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1431daaffb31Sdp	print "</pre></body></html>"
14327c478bd9Sstevel@tonic-gate}
14337c478bd9Sstevel@tonic-gate
1434daaffb31Sdp#
1435cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1436daaffb31Sdp#
1437daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1438daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1439daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1440daaffb31Sdp# delta in that list (the first delta unique to the child).
14417c478bd9Sstevel@tonic-gate#
14427c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1443daaffb31Sdp#
1444daaffb31Sdpcomments_from_teamware()
14457c478bd9Sstevel@tonic-gate{
1446daaffb31Sdp	fmt=$1
1447daaffb31Sdp	pfile=$PWS/$2
1448daaffb31Sdp	cfile=$CWS/$3
14497c478bd9Sstevel@tonic-gate
1450cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1451cdf0c1d5Smjnelson		pfile=$RWS/$2
1452cdf0c1d5Smjnelson	fi
1453cdf0c1d5Smjnelson
1454daaffb31Sdp	if [[ -f $pfile ]]; then
1455cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14567c478bd9Sstevel@tonic-gate	else
14577c478bd9Sstevel@tonic-gate		psid=1.1
14587c478bd9Sstevel@tonic-gate	fi
14597c478bd9Sstevel@tonic-gate
1460cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14617c478bd9Sstevel@tonic-gate	N=${#sids[@]}
14627c478bd9Sstevel@tonic-gate
1463daaffb31Sdp	nawkprg='
1464daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1465daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1466daaffb31Sdp		NF == 0u	{ continue }
1467daaffb31Sdp		{if (p==0) continue; print $0 }'
1468daaffb31Sdp
14697c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
14707c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14717c478bd9Sstevel@tonic-gate
1472daaffb31Sdp		if [[ $fmt == "text" ]]; then
1473cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1474cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1475daaffb31Sdp			return
1476daaffb31Sdp		fi
1477daaffb31Sdp
1478cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
14790fd2682eSMark J. Nelson		    html_quote | its2url | $AWK "$nawkprg"
14807c478bd9Sstevel@tonic-gate	fi
14817c478bd9Sstevel@tonic-gate}
14827c478bd9Sstevel@tonic-gate
1483daaffb31Sdp#
1484cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1485daaffb31Sdp#
1486cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1487cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1488cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1489cdf0c1d5Smjnelson# are turned into URLs.
1490cdf0c1d5Smjnelson#
1491cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1492daaffb31Sdp#
1493daaffb31Sdpcomments_from_wx()
14947c478bd9Sstevel@tonic-gate{
1495daaffb31Sdp	typeset fmt=$1
1496daaffb31Sdp	typeset p=$2
14977c478bd9Sstevel@tonic-gate
1498cdf0c1d5Smjnelson	comm=`$AWK '
1499daaffb31Sdp	$1 == "'$p'" {
15007c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
15017c478bd9Sstevel@tonic-gate		getline
15027c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
15037c478bd9Sstevel@tonic-gate		exit
1504daaffb31Sdp	}' < $wxfile`
1505daaffb31Sdp
1506cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1507cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1508cdf0c1d5Smjnelson	fi
1509cdf0c1d5Smjnelson
1510daaffb31Sdp	if [[ $fmt == "text" ]]; then
1511cdf0c1d5Smjnelson		print -- "$comm"
1512daaffb31Sdp		return
1513daaffb31Sdp	fi
1514daaffb31Sdp
15150fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1516cdf0c1d5Smjnelson
15177c478bd9Sstevel@tonic-gate}
15187c478bd9Sstevel@tonic-gate
15197c478bd9Sstevel@tonic-gate#
1520daaffb31Sdp# getcomments {text|html} filepath parentpath
1521daaffb31Sdp#
1522daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1523daaffb31Sdp#
1524daaffb31Sdpgetcomments()
1525daaffb31Sdp{
1526daaffb31Sdp	typeset fmt=$1
1527daaffb31Sdp	typeset p=$2
1528daaffb31Sdp	typeset pp=$3
15297c478bd9Sstevel@tonic-gate
15303df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15313df69ef3SDarren Moffat		return
15323df69ef3SDarren Moffat	fi
1533cdf0c1d5Smjnelson	#
1534cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1535cdf0c1d5Smjnelson	# will be used there, too
1536cdf0c1d5Smjnelson	#
1537daaffb31Sdp	if [[ -n $wxfile ]]; then
1538daaffb31Sdp		comments_from_wx $fmt $p
1539daaffb31Sdp	else
1540daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1541daaffb31Sdp			comments_from_teamware $fmt $pp $p
1542daaffb31Sdp		fi
1543daaffb31Sdp	fi
1544daaffb31Sdp}
1545daaffb31Sdp
1546daaffb31Sdp#
1547daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1548daaffb31Sdp#
1549daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1550daaffb31Sdp#
1551daaffb31Sdpfunction printCI
1552daaffb31Sdp{
1553daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1554daaffb31Sdp	typeset str
1555daaffb31Sdp	if (( tot == 1 )); then
1556daaffb31Sdp		str="line"
1557daaffb31Sdp	else
1558daaffb31Sdp		str="lines"
1559daaffb31Sdp	fi
1560daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1561daaffb31Sdp	    $tot $str $ins $del $mod $unc
1562daaffb31Sdp}
1563daaffb31Sdp
1564daaffb31Sdp
1565daaffb31Sdp#
1566daaffb31Sdp# difflines <oldfile> <newfile>
1567daaffb31Sdp#
1568daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1569daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1570daaffb31Sdp#
15717c478bd9Sstevel@tonic-gatefunction difflines
15727c478bd9Sstevel@tonic-gate{
1573daaffb31Sdp	integer tot mod del ins unc err
15747c478bd9Sstevel@tonic-gate	typeset filename
15757c478bd9Sstevel@tonic-gate
1576cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1577daaffb31Sdp	# Change range of lines: N,Nc
15787c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15797c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15807c478bd9Sstevel@tonic-gate		if (n != 2) {
15817c478bd9Sstevel@tonic-gate		    error=2
15827c478bd9Sstevel@tonic-gate		    exit;
15837c478bd9Sstevel@tonic-gate		}
1584daaffb31Sdp		#
1585daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1586daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1587daaffb31Sdp		#
15887c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1589daaffb31Sdp
1590daaffb31Sdp		#
1591daaffb31Sdp		# Now count replacement lines: each represents a change instead
1592daaffb31Sdp		# of a delete, so increment c and decrement r.
1593daaffb31Sdp		#
15947c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15957c478bd9Sstevel@tonic-gate			c++;
15967c478bd9Sstevel@tonic-gate			r--;
15977c478bd9Sstevel@tonic-gate		}
1598daaffb31Sdp		#
1599daaffb31Sdp		# If there were more replacement lines than original lines,
1600daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1601daaffb31Sdp		# but there are r changes that should be counted as adds, and
1602daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1603daaffb31Sdp		#
16047c478bd9Sstevel@tonic-gate		if (r < 0) {
16057c478bd9Sstevel@tonic-gate			a-=r;
16067c478bd9Sstevel@tonic-gate			c+=r;
16077c478bd9Sstevel@tonic-gate		}
1608daaffb31Sdp
1609daaffb31Sdp		#
1610daaffb31Sdp		# If there were more original lines than replacement lines, then
1611daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1612daaffb31Sdp		#
16137c478bd9Sstevel@tonic-gate		if (r > 0) {
16147c478bd9Sstevel@tonic-gate			d+=r;
16157c478bd9Sstevel@tonic-gate		}
16167c478bd9Sstevel@tonic-gate		next;
16177c478bd9Sstevel@tonic-gate	}
16187c478bd9Sstevel@tonic-gate
1619daaffb31Sdp	# Change lines: Nc
16207c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1621daaffb31Sdp		# The first line is a replacement; any more are additions.
16227c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16237c478bd9Sstevel@tonic-gate			c++;
16247c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16257c478bd9Sstevel@tonic-gate		}
16267c478bd9Sstevel@tonic-gate		next;
16277c478bd9Sstevel@tonic-gate	}
16287c478bd9Sstevel@tonic-gate
1629daaffb31Sdp	# Add lines: both Na and N,Na
16307c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16317c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16327c478bd9Sstevel@tonic-gate		next;
16337c478bd9Sstevel@tonic-gate	}
16347c478bd9Sstevel@tonic-gate
1635daaffb31Sdp	# Delete range of lines: N,Nd
16367c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16377c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16387c478bd9Sstevel@tonic-gate		if (n != 2) {
16397c478bd9Sstevel@tonic-gate			error=2
16407c478bd9Sstevel@tonic-gate			exit;
16417c478bd9Sstevel@tonic-gate		}
1642daaffb31Sdp		#
1643daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1644daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1645daaffb31Sdp		#
16467c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16477c478bd9Sstevel@tonic-gate		d+=r;
16487c478bd9Sstevel@tonic-gate		next;
16497c478bd9Sstevel@tonic-gate	}
16507c478bd9Sstevel@tonic-gate
1651daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16527c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16537c478bd9Sstevel@tonic-gate
1654daaffb31Sdp	# Should not get here!
16557c478bd9Sstevel@tonic-gate	{
16567c478bd9Sstevel@tonic-gate		error=1;
16577c478bd9Sstevel@tonic-gate		exit;
16587c478bd9Sstevel@tonic-gate	}
16597c478bd9Sstevel@tonic-gate
1660daaffb31Sdp	# Finish off - print results
16617c478bd9Sstevel@tonic-gate	END {
1662daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16637c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16647c478bd9Sstevel@tonic-gate	}' )
16657c478bd9Sstevel@tonic-gate
1666cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16677c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1668daaffb31Sdp		print "Unexpected Error occurred reading" \
1669daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1670daaffb31Sdp		return
1671daaffb31Sdp	fi
1672daaffb31Sdp
16737c478bd9Sstevel@tonic-gate	# Accumulate totals
16747c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1675daaffb31Sdp	(( TMOD += mod ))
16767c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16777c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16787c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1679cdf0c1d5Smjnelson	unc=`wc -l < $1`
16807c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1681daaffb31Sdp		(( unc -= del + mod ))
16827c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16837c478bd9Sstevel@tonic-gate	fi
16847c478bd9Sstevel@tonic-gate	# print summary
1685daaffb31Sdp	print "<span class=\"lineschanged\">"
1686daaffb31Sdp	printCI $tot $ins $del $mod $unc
1687daaffb31Sdp	print "</span>"
16887c478bd9Sstevel@tonic-gate}
16897c478bd9Sstevel@tonic-gate
1690daaffb31Sdp
16917c478bd9Sstevel@tonic-gate#
1692daaffb31Sdp# flist_from_wx
1693daaffb31Sdp#
1694daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1695daaffb31Sdp# Sets the global 'wxfile' variable.
1696daaffb31Sdp#
1697daaffb31Sdpfunction flist_from_wx
16987c478bd9Sstevel@tonic-gate{
1699daaffb31Sdp	typeset argfile=$1
1700daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1701daaffb31Sdp		#
1702daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1703daaffb31Sdp		# because the webrev does a "cd" later on.
1704daaffb31Sdp		#
1705daaffb31Sdp		wxfile=$PWD/$argfile
17067c478bd9Sstevel@tonic-gate	else
1707daaffb31Sdp		wxfile=$argfile
17087c478bd9Sstevel@tonic-gate	fi
17097c478bd9Sstevel@tonic-gate
1710cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
17117c478bd9Sstevel@tonic-gate	  while (getline) {
17127c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
17137c478bd9Sstevel@tonic-gate		if (c > 0) print
17147c478bd9Sstevel@tonic-gate	  }
1715daaffb31Sdp	}' $wxfile > $FLIST
17167c478bd9Sstevel@tonic-gate
1717daaffb31Sdp	print " Done."
1718daaffb31Sdp}
17197c478bd9Sstevel@tonic-gate
1720daaffb31Sdp#
1721daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1722daaffb31Sdp#
1723daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1724daaffb31Sdp# names may come from the "update/create" messages and others from the
1725daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1726daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1727daaffb31Sdp# -n as well, but remove them if they are already defined.
1728daaffb31Sdp#
1729daaffb31Sdpfunction flist_from_teamware
1730daaffb31Sdp{
1731cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1732daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1733daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1734daaffb31Sdp			    "valid teamware workspace"
17357c478bd9Sstevel@tonic-gate			exit 1
17367c478bd9Sstevel@tonic-gate		fi
1737daaffb31Sdp		parent_args="-p $codemgr_parent"
17387c478bd9Sstevel@tonic-gate	fi
17397c478bd9Sstevel@tonic-gate
1740daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17417c478bd9Sstevel@tonic-gate
1742daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1743cdf0c1d5Smjnelson	    $AWK '
1744daaffb31Sdp		/^update:|^create:/	{print $2}
1745daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1746daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1747daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1748daaffb31Sdp		NF == 0			{p=0 ; continue}
1749daaffb31Sdp		/^rename/		{old=$3}
1750daaffb31Sdp		$1 == "to:"		{print $2, old}
1751daaffb31Sdp		/^"/			{continue}
1752daaffb31Sdp		p == 1			{print $1}' |
1753daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17547c478bd9Sstevel@tonic-gate
1755daaffb31Sdp	print " Done."
1756daaffb31Sdp}
1757daaffb31Sdp
1758cdf0c1d5Smjnelson#
1759cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1760cdf0c1d5Smjnelson#
1761cdf0c1d5Smjnelsonfunction hg_active_wxfile
1762cdf0c1d5Smjnelson{
1763cdf0c1d5Smjnelson	typeset child=$1
1764cdf0c1d5Smjnelson	typeset parent=$2
1765cdf0c1d5Smjnelson
1766cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17679a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1768cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1769cdf0c1d5Smjnelson}
1770cdf0c1d5Smjnelson
1771cdf0c1d5Smjnelson#
1772cdf0c1d5Smjnelson# flist_from_mercurial
1773cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1774cdf0c1d5Smjnelson# flist_from_wx
1775cdf0c1d5Smjnelson#
1776cdf0c1d5Smjnelsonfunction flist_from_mercurial
1777cdf0c1d5Smjnelson{
1778cdf0c1d5Smjnelson	typeset child=$1
1779cdf0c1d5Smjnelson	typeset parent=$2
1780cdf0c1d5Smjnelson
1781cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1782cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1783cdf0c1d5Smjnelson		print		# Blank line for the \c above
1784cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1785cdf0c1d5Smjnelson		exit 1
1786cdf0c1d5Smjnelson	fi
1787cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1788cdf0c1d5Smjnelson
1789cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1790cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1791cdf0c1d5Smjnelson}
1792cdf0c1d5Smjnelson
1793cdf0c1d5Smjnelson#
17948bcea973SRichard Lowe# Transform a specified 'git log' output format into a wx-like active list.
17958bcea973SRichard Lowe#
17968bcea973SRichard Lowefunction git_wxfile
17978bcea973SRichard Lowe{
17988bcea973SRichard Lowe	typeset child="$1"
17998bcea973SRichard Lowe	typeset parent="$2"
18008bcea973SRichard Lowe
18018bcea973SRichard Lowe	TMPFLIST=/tmp/$$.active
18028bcea973SRichard Lowe	$PERL -e 'my (%files, %realfiles, $msg);
18038bcea973SRichard Lowe	my $branch = $ARGV[0];
18048bcea973SRichard Lowe
18058bcea973SRichard Lowe	open(F, "git diff -M --name-status $branch |");
18068bcea973SRichard Lowe	while (<F>) {
18078bcea973SRichard Lowe	    chomp;
18088bcea973SRichard Lowe	    if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
18098bcea973SRichard Lowe		if ($1 >= 75) {			 # Probably worth treating as a rename
18103cb02613SRichard Lowe		    $realfiles{$3} = $2;
18118bcea973SRichard Lowe		} else {
18128bcea973SRichard Lowe		    $realfiles{$3} = $3;
18138bcea973SRichard Lowe		    $realfiles{$2} = $2;
18148bcea973SRichard Lowe	        }
18158bcea973SRichard Lowe	    } else {
18168bcea973SRichard Lowe		my $f = (split /\s+/, $_)[1];
18178bcea973SRichard Lowe		$realfiles{$f} = $f;
18188bcea973SRichard Lowe	    }
18198bcea973SRichard Lowe	}
18208bcea973SRichard Lowe	close(F);
18218bcea973SRichard Lowe
18228bcea973SRichard Lowe	my $state = 1;		    # 0|comments, 1|files
18238bcea973SRichard Lowe	open(F, "git whatchanged --pretty=format:%B $branch.. |");
18248bcea973SRichard Lowe	while (<F>) {
18258bcea973SRichard Lowe	    chomp;
18268bcea973SRichard Lowe	    if (/^:[0-9]{6}/) {
18278bcea973SRichard Lowe		my $fname = (split /\t/, $_)[1];
18288bcea973SRichard Lowe		next if !defined($realfiles{$fname}); # No real change
18298bcea973SRichard Lowe		$state = 1;
18303cb02613SRichard Lowe		chomp $msg;
18313cb02613SRichard Lowe		$files{$fname} .= $msg;
18328bcea973SRichard Lowe	    } else {
18338bcea973SRichard Lowe		if ($state == 1) {
18348bcea973SRichard Lowe		    $state = 0;
18358bcea973SRichard Lowe		    $msg = /^\n/ ? "" : "\n";
18368bcea973SRichard Lowe		}
18378bcea973SRichard Lowe		$msg .= "$_\n" if ($_);
18388bcea973SRichard Lowe	    }
18398bcea973SRichard Lowe	}
18408bcea973SRichard Lowe	close(F);
18418bcea973SRichard Lowe
18428bcea973SRichard Lowe	for (sort keys %files) {
18438bcea973SRichard Lowe	    if ($realfiles{$_} ne $_) {
18443cb02613SRichard Lowe		print "$_ $realfiles{$_}\n$files{$_}\n\n";
18458bcea973SRichard Lowe	    } else {
18463cb02613SRichard Lowe		print "$_\n$files{$_}\n\n"
18478bcea973SRichard Lowe	    }
18488bcea973SRichard Lowe	}' ${parent} > $TMPFLIST
18498bcea973SRichard Lowe
18508bcea973SRichard Lowe	wxfile=$TMPFLIST
18518bcea973SRichard Lowe}
18528bcea973SRichard Lowe
18538bcea973SRichard Lowe#
18548bcea973SRichard Lowe# flist_from_git
18558bcea973SRichard Lowe# Build a wx-style active list, and hand it off to flist_from_wx
18568bcea973SRichard Lowe#
18578bcea973SRichard Lowefunction flist_from_git
18588bcea973SRichard Lowe{
18598bcea973SRichard Lowe	typeset child=$1
18608bcea973SRichard Lowe	typeset parent=$2
18618bcea973SRichard Lowe
18628bcea973SRichard Lowe	print " File list from: git ...\c"
18638bcea973SRichard Lowe	git_wxfile "$child" "$parent";
18648bcea973SRichard Lowe
18658bcea973SRichard Lowe	# flist_from_wx prints the Done, so we don't have to.
18668bcea973SRichard Lowe	flist_from_wx $TMPFLIST
18678bcea973SRichard Lowe}
18688bcea973SRichard Lowe
18698bcea973SRichard Lowe#
1870cdf0c1d5Smjnelson# flist_from_subversion
1871cdf0c1d5Smjnelson#
1872cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1873cdf0c1d5Smjnelson#
1874cdf0c1d5Smjnelsonfunction flist_from_subversion
1875cdf0c1d5Smjnelson{
1876cdf0c1d5Smjnelson	CWS=$1
1877cdf0c1d5Smjnelson	OLDPWD=$2
1878cdf0c1d5Smjnelson
1879cdf0c1d5Smjnelson	cd $CWS
1880cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1881cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1882cdf0c1d5Smjnelson	print -u2 " Done."
1883cdf0c1d5Smjnelson	cd $OLDPWD
1884cdf0c1d5Smjnelson}
1885cdf0c1d5Smjnelson
1886daaffb31Sdpfunction env_from_flist
1887daaffb31Sdp{
1888daaffb31Sdp	[[ -r $FLIST ]] || return
1889daaffb31Sdp
1890daaffb31Sdp	#
1891daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1892daaffb31Sdp	# list.  Then copy those into our local versions of those
1893daaffb31Sdp	# variables if they have not been set already.
1894daaffb31Sdp	#
1895b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18967c478bd9Sstevel@tonic-gate
1897cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1898cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1899cdf0c1d5Smjnelson		export CODEMGR_WS
1900cdf0c1d5Smjnelson	fi
19017c478bd9Sstevel@tonic-gate
1902daaffb31Sdp	#
1903daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1904daaffb31Sdp	#
1905cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1906daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1907cdf0c1d5Smjnelson		export CODEMGR_PARENT
1908daaffb31Sdp	fi
1909daaffb31Sdp}
1910daaffb31Sdp
191114983201Sdpfunction look_for_prog
191214983201Sdp{
191314983201Sdp	typeset path
191414983201Sdp	typeset ppath
191514983201Sdp	typeset progname=$1
191614983201Sdp
191714983201Sdp	ppath=$PATH
191814983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
191914983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1920cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
192114983201Sdp
192214983201Sdp	PATH=$ppath prog=`whence $progname`
192314983201Sdp	if [[ -n $prog ]]; then
192414983201Sdp		print $prog
192514983201Sdp	fi
192614983201Sdp}
192714983201Sdp
1928cdf0c1d5Smjnelsonfunction get_file_mode
1929cdf0c1d5Smjnelson{
1930cdf0c1d5Smjnelson	$PERL -e '
1931cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1932cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1933cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1934cdf0c1d5Smjnelson			exit 0;
1935cdf0c1d5Smjnelson		} else {
1936cdf0c1d5Smjnelson			exit 1;
1937cdf0c1d5Smjnelson		}
1938cdf0c1d5Smjnelson	    ' $1
1939cdf0c1d5Smjnelson}
1940cdf0c1d5Smjnelson
1941cdf0c1d5Smjnelsonfunction build_old_new_teamware
1942cdf0c1d5Smjnelson{
1943cdf0c1d5Smjnelson	typeset olddir="$1"
1944cdf0c1d5Smjnelson	typeset newdir="$2"
1945cdf0c1d5Smjnelson
1946cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1947cdf0c1d5Smjnelson	# get a readonly copy.
1948cdf0c1d5Smjnelson
1949cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1950cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1951cdf0c1d5Smjnelson	fi
1952cdf0c1d5Smjnelson
1953cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1954cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1955cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1956cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1957cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1958cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1959cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1960cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1961cdf0c1d5Smjnelson	# permissions that would result after check in.
1962cdf0c1d5Smjnelson
1963cdf0c1d5Smjnelson	#
1964cdf0c1d5Smjnelson	# Snag new version of file.
1965cdf0c1d5Smjnelson	#
1966cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1967cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1968cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1969cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1970cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1971cdf0c1d5Smjnelson	fi
1972cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1973cdf0c1d5Smjnelson
1974cdf0c1d5Smjnelson	#
1975cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1976cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1977cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1978cdf0c1d5Smjnelson	#
1979cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1980cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1981cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1982cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1983cdf0c1d5Smjnelson		# the old file.
1984cdf0c1d5Smjnelson
1985cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1986cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1987cdf0c1d5Smjnelson	else
1988cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1989cdf0c1d5Smjnelson			real_parent=$PWS
1990cdf0c1d5Smjnelson		else
1991cdf0c1d5Smjnelson			real_parent=$RWS
1992cdf0c1d5Smjnelson		fi
1993cdf0c1d5Smjnelson
1994cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1995cdf0c1d5Smjnelson
1996cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1997cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1998cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1999cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
2000cdf0c1d5Smjnelson			else
2001cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
2002cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
2003cdf0c1d5Smjnelson			fi
2004cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
2005cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
2006cdf0c1d5Smjnelson		fi
2007cdf0c1d5Smjnelson	fi
2008cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
2009cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
2010cdf0c1d5Smjnelson	fi
2011cdf0c1d5Smjnelson}
2012cdf0c1d5Smjnelson
2013cdf0c1d5Smjnelsonfunction build_old_new_mercurial
2014cdf0c1d5Smjnelson{
2015cdf0c1d5Smjnelson	typeset olddir="$1"
2016cdf0c1d5Smjnelson	typeset newdir="$2"
2017cdf0c1d5Smjnelson	typeset old_mode=
2018cdf0c1d5Smjnelson	typeset new_mode=
2019cdf0c1d5Smjnelson	typeset file
2020cdf0c1d5Smjnelson
2021cdf0c1d5Smjnelson	#
2022cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
2023cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
2024cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
2025cdf0c1d5Smjnelson	#
2026cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
2027cdf0c1d5Smjnelson		file="$PF"
2028cdf0c1d5Smjnelson	else
2029cdf0c1d5Smjnelson		file="$PDIR/$PF"
2030cdf0c1d5Smjnelson	fi
2031b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
2032cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
2033b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
2034cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
2035cdf0c1d5Smjnelson
2036cdf0c1d5Smjnelson	#
2037cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
2038cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
2039cdf0c1d5Smjnelson	#
2040cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
2041cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
2042cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
2043cdf0c1d5Smjnelson			new_mode=755
2044cdf0c1d5Smjnelson		else
2045cdf0c1d5Smjnelson			new_mode=644
2046cdf0c1d5Smjnelson		fi
2047cdf0c1d5Smjnelson	fi
2048cdf0c1d5Smjnelson
2049cdf0c1d5Smjnelson	#
2050cdf0c1d5Smjnelson	# new version of the file.
2051cdf0c1d5Smjnelson	#
2052cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
2053cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
2054cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
2055cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
2056cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
2057cdf0c1d5Smjnelson		else
2058cdf0c1d5Smjnelson			# should never happen
2059cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
2060cdf0c1d5Smjnelson		fi
2061cdf0c1d5Smjnelson	fi
2062cdf0c1d5Smjnelson
2063cdf0c1d5Smjnelson	#
2064cdf0c1d5Smjnelson	# parent's version of the file
2065cdf0c1d5Smjnelson	#
2066cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
2067cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
2068cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
2069cdf0c1d5Smjnelson	#
2070cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
2071cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2072cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
2073cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
2074cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
2075cdf0c1d5Smjnelson
207602d26c39SVladimir Kotal		if (( $? != 0 )); then
2077cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
2078cdf0c1d5Smjnelson		else
2079cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
2080cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
2081cdf0c1d5Smjnelson			else
2082cdf0c1d5Smjnelson				# should never happen
2083cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
2084cdf0c1d5Smjnelson			fi
2085cdf0c1d5Smjnelson		fi
2086cdf0c1d5Smjnelson	fi
2087cdf0c1d5Smjnelson}
2088cdf0c1d5Smjnelson
20898bcea973SRichard Lowefunction build_old_new_git
20908bcea973SRichard Lowe{
20918bcea973SRichard Lowe	typeset olddir="$1"
20928bcea973SRichard Lowe	typeset newdir="$2"
20938bcea973SRichard Lowe	typeset o_mode=
20948bcea973SRichard Lowe	typeset n_mode=
20958bcea973SRichard Lowe	typeset o_object=
20968bcea973SRichard Lowe	typeset n_object=
20978bcea973SRichard Lowe	typeset OWD=$PWD
20988bcea973SRichard Lowe	typeset file
20998bcea973SRichard Lowe	typeset type
21008bcea973SRichard Lowe
21018bcea973SRichard Lowe	cd $CWS
21028bcea973SRichard Lowe
21038bcea973SRichard Lowe	#
21048bcea973SRichard Lowe	# Get old file and its mode from the git object tree
21058bcea973SRichard Lowe	#
21068bcea973SRichard Lowe	if [[ "$PDIR" == "." ]]; then
21078bcea973SRichard Lowe		file="$PF"
21088bcea973SRichard Lowe	else
21098bcea973SRichard Lowe	       file="$PDIR/$PF"
21108bcea973SRichard Lowe	fi
21118bcea973SRichard Lowe
21128bcea973SRichard Lowe	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
21138bcea973SRichard Lowe		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
21148bcea973SRichard Lowe	else
21158bcea973SRichard Lowe                $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk
21168bcea973SRichard Lowe                $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null
21178bcea973SRichard Lowe
21188bcea973SRichard Lowe                if (( $? != 0 )); then
21198bcea973SRichard Lowe                        rm -f $olddir/$file
21208bcea973SRichard Lowe                elif [[ -n $o_mode ]]; then
21218bcea973SRichard Lowe                        # Strip the first 3 digits, to get a regular octal mode
21228bcea973SRichard Lowe                        o_mode=${o_mode/???/}
21238bcea973SRichard Lowe                        chmod $o_mode $olddir/$file
21248bcea973SRichard Lowe                else
21258bcea973SRichard Lowe                        # should never happen
21268bcea973SRichard Lowe                        print -u2 "ERROR: set mode of $olddir/$file"
21278bcea973SRichard Lowe                fi
21288bcea973SRichard Lowe	fi
21298bcea973SRichard Lowe
21308bcea973SRichard Lowe	#
21318bcea973SRichard Lowe	# new version of the file.
21328bcea973SRichard Lowe	#
21338bcea973SRichard Lowe	if [[ "$DIR" == "." ]]; then
21348bcea973SRichard Lowe		file="$F"
21358bcea973SRichard Lowe	else
21368bcea973SRichard Lowe		file="$DIR/$F"
21378bcea973SRichard Lowe	fi
21388bcea973SRichard Lowe	rm -rf $newdir/$file
21398bcea973SRichard Lowe
21408bcea973SRichard Lowe        if [[ -e $CWS/$DIR/$F ]]; then
21418bcea973SRichard Lowe            cp $CWS/$DIR/$F $newdir/$DIR/$F
21428bcea973SRichard Lowe            chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F
21438bcea973SRichard Lowe        fi
21448bcea973SRichard Lowe	cd $OWD
21458bcea973SRichard Lowe}
21468bcea973SRichard Lowe
2147cdf0c1d5Smjnelsonfunction build_old_new_subversion
2148cdf0c1d5Smjnelson{
2149cdf0c1d5Smjnelson	typeset olddir="$1"
2150cdf0c1d5Smjnelson	typeset newdir="$2"
2151cdf0c1d5Smjnelson
2152cdf0c1d5Smjnelson	# Snag new version of file.
2153cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2154cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2155cdf0c1d5Smjnelson
2156cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2157cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2158cdf0c1d5Smjnelson	else
2159cdf0c1d5Smjnelson		# Get the parent's version of the file.
2160cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2161cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2162cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2163cdf0c1d5Smjnelson		fi
2164cdf0c1d5Smjnelson	fi
2165cdf0c1d5Smjnelson}
2166cdf0c1d5Smjnelson
2167cdf0c1d5Smjnelsonfunction build_old_new_unknown
2168cdf0c1d5Smjnelson{
2169cdf0c1d5Smjnelson	typeset olddir="$1"
2170cdf0c1d5Smjnelson	typeset newdir="$2"
2171cdf0c1d5Smjnelson
2172cdf0c1d5Smjnelson	#
2173cdf0c1d5Smjnelson	# Snag new version of file.
2174cdf0c1d5Smjnelson	#
2175cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2176cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2177cdf0c1d5Smjnelson
2178cdf0c1d5Smjnelson	#
2179cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2180cdf0c1d5Smjnelson	#
2181cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2182cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2183cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2184cdf0c1d5Smjnelson	fi
2185cdf0c1d5Smjnelson}
2186cdf0c1d5Smjnelson
2187cdf0c1d5Smjnelsonfunction build_old_new
2188cdf0c1d5Smjnelson{
2189cdf0c1d5Smjnelson	typeset WDIR=$1
2190cdf0c1d5Smjnelson	typeset PWS=$2
2191cdf0c1d5Smjnelson	typeset PDIR=$3
2192cdf0c1d5Smjnelson	typeset PF=$4
2193cdf0c1d5Smjnelson	typeset CWS=$5
2194cdf0c1d5Smjnelson	typeset DIR=$6
2195cdf0c1d5Smjnelson	typeset F=$7
2196cdf0c1d5Smjnelson
2197cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2198cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2199cdf0c1d5Smjnelson
2200cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2201cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2202cdf0c1d5Smjnelson
2203cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2204cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
2205cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
2206cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
22078bcea973SRichard Lowe	elif [[ $SCM_MODE == "git" ]]; then
22088bcea973SRichard Lowe		build_old_new_git "$olddir" "$newdir"
2209cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2210cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2211cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2212cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2213cdf0c1d5Smjnelson	fi
2214cdf0c1d5Smjnelson
2215cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2216cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2217cdf0c1d5Smjnelson		return 1
2218cdf0c1d5Smjnelson	fi
2219cdf0c1d5Smjnelson	return 0
2220cdf0c1d5Smjnelson}
2221cdf0c1d5Smjnelson
2222cdf0c1d5Smjnelson
2223daaffb31Sdp#
2224daaffb31Sdp# Usage message.
2225daaffb31Sdp#
2226daaffb31Sdpfunction usage
2227daaffb31Sdp{
2228daaffb31Sdp	print 'Usage:\twebrev [common-options]
2229daaffb31Sdp	webrev [common-options] ( <file> | - )
2230daaffb31Sdp	webrev [common-options] -w <wx file>
2231daaffb31Sdp
2232daaffb31SdpOptions:
22330fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2234ba44d8a2SVladimir Kotal	-D: delete remote webrev
2235daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
22360fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2237ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2238ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2239daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2240daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
224102d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
224202d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2243daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2244daaffb31Sdp
2245daaffb31SdpEnvironment:
2246daaffb31Sdp	WDIR: Control the output directory.
2247ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2248daaffb31Sdp
2249cdf0c1d5SmjnelsonSCM Specific Options:
2250cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
2251cdf0c1d5Smjnelson
2252daaffb31SdpSCM Environment:
2253cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2254cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2255daaffb31Sdp'
2256daaffb31Sdp
2257daaffb31Sdp	exit 2
2258daaffb31Sdp}
2259daaffb31Sdp
2260daaffb31Sdp#
2261daaffb31Sdp#
2262daaffb31Sdp# Main program starts here
2263daaffb31Sdp#
2264daaffb31Sdp#
2265daaffb31Sdp
2266daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2267daaffb31Sdp
2268daaffb31Sdpset +o noclobber
2269daaffb31Sdp
22708bcea973SRichard LowePATH=$(/bin/dirname "$(whence $0)"):$PATH
2271cdf0c1d5Smjnelson
227214983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
227314983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2274cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
22758bcea973SRichard Lowe[[ -z $GIT ]] && GIT=`look_for_prog git`
2276cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
227714983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
227814983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
227914983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
228002d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2281cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2282cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2283cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2284cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
228502d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2286b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
228702d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2288e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort`
228902d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
229002d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2291ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2292cdf0c1d5Smjnelson
2293ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2294ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2295ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
229614983201Sdp
229714983201Sdpif [[ ! -x $PERL ]]; then
229814983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
229914983201Sdp	exit 1
2300daaffb31Sdpfi
230114983201Sdp
2302cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2303cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2304cdf0c1d5Smjnelson	exit 1
2305cdf0c1d5Smjnelsonfi
2306cdf0c1d5Smjnelson
230714983201Sdp#
230814983201Sdp# These aren't fatal, but we want to note them to the user.
230914983201Sdp# We don't warn on the absence of 'wx' until later when we've
231014983201Sdp# determined that we actually need to try to invoke it.
231114983201Sdp#
231214983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
231314983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
231414983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2315daaffb31Sdp
2316daaffb31Sdp# Declare global total counters.
2317daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2318daaffb31Sdp
2319ba44d8a2SVladimir Kotal# default remote host for upload/delete
2320ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2321b0088928SVladimir Kotal# prefixes for upload targets
2322b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2323b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2324ba44d8a2SVladimir Kotal
23250fd2682eSMark J. NelsonCflag=
2326ba44d8a2SVladimir KotalDflag=
232714983201Sdpflist_mode=
232814983201Sdpflist_file=
2329daaffb31Sdpiflag=
23300fd2682eSMark J. NelsonIflag=
233102d26c39SVladimir Kotallflag=
233202d26c39SVladimir KotalNflag=
233302d26c39SVladimir Kotalnflag=
233402d26c39SVladimir KotalOflag=
2335daaffb31Sdpoflag=
2336daaffb31Sdppflag=
233702d26c39SVladimir Kotaltflag=
233802d26c39SVladimir Kotaluflag=
233902d26c39SVladimir KotalUflag=
2340daaffb31Sdpwflag=
234102d26c39SVladimir Kotalremote_target=
2342ba44d8a2SVladimir Kotal
2343ba44d8a2SVladimir Kotal#
2344ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2345ba44d8a2SVladimir Kotal#	with usr/src/tools/onbld/hgext/cdm.py
2346ba44d8a2SVladimir Kotal#
234725cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
2348daaffb31Sdpdo
2349daaffb31Sdp	case $opt in
23500fd2682eSMark J. Nelson	C)	Cflag=1
23510fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
23520fd2682eSMark J. Nelson
2353ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2354ba44d8a2SVladimir Kotal
2355daaffb31Sdp	i)	iflag=1
2356daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2357daaffb31Sdp
23580fd2682eSMark J. Nelson	I)	Iflag=1
23590fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
23600fd2682eSMark J. Nelson
2361daaffb31Sdp	#
2362daaffb31Sdp	# If -l has been specified, we need to abort further options
2363daaffb31Sdp	# processing, because subsequent arguments are going to be
2364daaffb31Sdp	# arguments to 'putback -n'.
2365daaffb31Sdp	#
2366daaffb31Sdp	l)	lflag=1
2367daaffb31Sdp		break;;
2368daaffb31Sdp
236902d26c39SVladimir Kotal	N)	Nflag=1;;
237002d26c39SVladimir Kotal
237102d26c39SVladimir Kotal	n)	nflag=1;;
2372daaffb31Sdp
2373daaffb31Sdp	O)	Oflag=1;;
2374daaffb31Sdp
237502d26c39SVladimir Kotal	o)	oflag=1
23769d3952abSVladimir Kotal		# Strip the trailing slash to correctly form remote target.
23779d3952abSVladimir Kotal		WDIR=${OPTARG%/};;
237802d26c39SVladimir Kotal
237902d26c39SVladimir Kotal	p)	pflag=1
238002d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
238102d26c39SVladimir Kotal
238202d26c39SVladimir Kotal	t)	tflag=1
238302d26c39SVladimir Kotal		remote_target=$OPTARG;;
238402d26c39SVladimir Kotal
238502d26c39SVladimir Kotal	U)	Uflag=1;;
238602d26c39SVladimir Kotal
238702d26c39SVladimir Kotal	w)	wflag=1;;
23883df69ef3SDarren Moffat
2389daaffb31Sdp	?)	usage;;
2390daaffb31Sdp	esac
2391daaffb31Sdpdone
2392daaffb31Sdp
2393daaffb31SdpFLIST=/tmp/$$.flist
2394daaffb31Sdp
2395daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2396daaffb31Sdp	usage
2397daaffb31Sdpfi
2398daaffb31Sdp
239902d26c39SVladimir Kotal# more sanity checking
240002d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2401ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2402ba44d8a2SVladimir Kotal	    "without -U"
240302d26c39SVladimir Kotal	exit 1
240402d26c39SVladimir Kotalfi
240502d26c39SVladimir Kotal
2406ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2407ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
240802d26c39SVladimir Kotal	exit 1
240902d26c39SVladimir Kotalfi
241002d26c39SVladimir Kotal
2411daaffb31Sdp#
24122d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume
24132d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name
24142d9224a3SMark J. Nelson# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
24152d9224a3SMark J. Nelson# logic.
24162d9224a3SMark J. Nelson#
24172d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1
24182d9224a3SMark J. Nelsonif [[ $SCM_MODE == "teamware" ]]; then
24192d9224a3SMark J. Nelson	#
24202d9224a3SMark J. Nelson	# Teamware priorities:
24212d9224a3SMark J. Nelson	# 1. CODEMGR_WS from the environment
24222d9224a3SMark J. Nelson	# 2. workspace name
24232d9224a3SMark J. Nelson	#
24242d9224a3SMark J. Nelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
24252d9224a3SMark J. Nelson	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
24262d9224a3SMark J. Nelson		print -u2 "$codemgr_ws: no such workspace"
24272d9224a3SMark J. Nelson		exit 1
24282d9224a3SMark J. Nelson	fi
24292d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
24302d9224a3SMark J. Nelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
24312d9224a3SMark J. Nelson	CODEMGR_WS=$codemgr_ws
24322d9224a3SMark J. Nelson	CWS=$codemgr_ws
24332d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "mercurial" ]]; then
24342d9224a3SMark J. Nelson	#
24352d9224a3SMark J. Nelson	# Mercurial priorities:
24362d9224a3SMark J. Nelson	# 1. hg root from CODEMGR_WS environment variable
243778add226Sjmcp	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
243878add226Sjmcp	#    usr/closed when we run webrev
24392d9224a3SMark J. Nelson	# 2. hg root from directory of invocation
24402d9224a3SMark J. Nelson	#
244178add226Sjmcp	if [[ ${PWD} =~ "usr/closed" ]]; then
244278add226Sjmcp		testparent=${CODEMGR_WS}/usr/closed
244378add226Sjmcp		# If we're in OpenSolaris mode, we enforce a minor policy:
244478add226Sjmcp		# help to make sure the reviewer doesn't accidentally publish
244578add226Sjmcp		# source which is under usr/closed
244678add226Sjmcp		if [[ -n "$Oflag" ]]; then
244778add226Sjmcp			print -u2 "OpenSolaris output not permitted with" \
244878add226Sjmcp			    "usr/closed changes"
244978add226Sjmcp			exit 1
245078add226Sjmcp		fi
245178add226Sjmcp	else
245278add226Sjmcp	        testparent=${CODEMGR_WS}
245378add226Sjmcp	fi
245478add226Sjmcp	[[ -z $codemgr_ws && -n $testparent ]] && \
245578add226Sjmcp	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
24562d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
24572d9224a3SMark J. Nelson	CWS=$codemgr_ws
24588bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
24598bcea973SRichard Lowe	#
24608bcea973SRichard Lowe	# Git priorities:
24618bcea973SRichard Lowe	# 1. git rev-parse --git-dir from CODEMGR_WS environment variable
24628bcea973SRichard Lowe	# 2. git rev-parse --git-dir from directory of invocation
24638bcea973SRichard Lowe	#
24648bcea973SRichard Lowe	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
24658bcea973SRichard Lowe	    codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
24668bcea973SRichard Lowe                2>/dev/null)
24678bcea973SRichard Lowe	[[ -z $codemgr_ws ]] && \
24688bcea973SRichard Lowe	    codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
24698bcea973SRichard Lowe
24708bcea973SRichard Lowe	if [[ "$codemgr_ws" == ".git" ]]; then
24718bcea973SRichard Lowe		codemgr_ws="${PWD}/${codemgr_ws}"
24728bcea973SRichard Lowe	fi
24738bcea973SRichard Lowe
24748bcea973SRichard Lowe	codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
24758bcea973SRichard Lowe	CWS="$codemgr_ws"
24762d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then
24772d9224a3SMark J. Nelson	#
24782d9224a3SMark J. Nelson	# Subversion priorities:
24792d9224a3SMark J. Nelson	# 1. CODEMGR_WS from environment
24802d9224a3SMark J. Nelson	# 2. Relative path from current directory to SVN repository root
24812d9224a3SMark J. Nelson	#
24822d9224a3SMark J. Nelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
24832d9224a3SMark J. Nelson		CWS=$CODEMGR_WS
24842d9224a3SMark J. Nelson	else
24852d9224a3SMark J. Nelson		svn info | while read line; do
24862d9224a3SMark J. Nelson			if [[ $line == "URL: "* ]]; then
24872d9224a3SMark J. Nelson				url=${line#URL: }
24882d9224a3SMark J. Nelson			elif [[ $line == "Repository Root: "* ]]; then
24892d9224a3SMark J. Nelson				repo=${line#Repository Root: }
24902d9224a3SMark J. Nelson			fi
24912d9224a3SMark J. Nelson		done
24922d9224a3SMark J. Nelson
24932d9224a3SMark J. Nelson		rel=${url#$repo}
24942d9224a3SMark J. Nelson		CWS=${PWD%$rel}
24952d9224a3SMark J. Nelson	fi
24962d9224a3SMark J. Nelsonfi
24972d9224a3SMark J. Nelson
24982d9224a3SMark J. Nelson#
24992d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting
25002d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set.
25012d9224a3SMark J. Nelson#
25022d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then
25032d9224a3SMark J. Nelson	CWS=${CODEMGR_WS:-.}
25042d9224a3SMark J. Nelsonfi
25052d9224a3SMark J. Nelson
25062d9224a3SMark J. Nelson#
25070fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
25080fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
25090fd2682eSMark J. Nelson# ton of logic we can skip.
25100fd2682eSMark J. Nelson#
25110fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
25120fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
25130fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
25140fd2682eSMark J. Nelson#
25150fd2682eSMark J. Nelsonfor do_everything in 1; do
25160fd2682eSMark J. Nelson
25170fd2682eSMark J. Nelson# DO_EVERYTHING: break point
25180fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
25190fd2682eSMark J. Nelson	break
25200fd2682eSMark J. Nelsonfi
25210fd2682eSMark J. Nelson
25220fd2682eSMark J. Nelson#
2523daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2524daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2525daaffb31Sdp#
2526daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
25278bcea973SRichard Lowe	parent_webrev=$(readlink -f "$codemgr_parent")
25288bcea973SRichard Lowe	codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new")
2529daaffb31Sdpfi
2530daaffb31Sdp
2531daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2532daaffb31Sdp	shift $(($OPTIND - 1))
2533daaffb31Sdp
2534daaffb31Sdp	if [[ $1 == "-" ]]; then
2535daaffb31Sdp		cat > $FLIST
253614983201Sdp		flist_mode="stdin"
253714983201Sdp		flist_done=1
253814983201Sdp		shift
2539daaffb31Sdp	elif [[ -n $1 ]]; then
254014983201Sdp		if [[ ! -r $1 ]]; then
2541daaffb31Sdp			print -u2 "$1: no such file or not readable"
2542daaffb31Sdp			usage
2543daaffb31Sdp		fi
2544daaffb31Sdp		cat $1 > $FLIST
254514983201Sdp		flist_mode="file"
254614983201Sdp		flist_file=$1
254714983201Sdp		flist_done=1
254814983201Sdp		shift
2549daaffb31Sdp	else
255014983201Sdp		flist_mode="auto"
2551daaffb31Sdp	fi
2552daaffb31Sdpfi
2553daaffb31Sdp
2554daaffb31Sdp#
2555daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2556daaffb31Sdp# is in use.
2557daaffb31Sdp#
2558cdf0c1d5Smjnelsoncase "$SCM_MODE" in
25598bcea973SRichard Loweteamware|mercurial|git|subversion)
2560cdf0c1d5Smjnelson	;;
2561cdf0c1d5Smjnelsonunknown)
2562cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2563cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2564cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
25657c478bd9Sstevel@tonic-gate		exit 1
25667c478bd9Sstevel@tonic-gate	fi
2567cdf0c1d5Smjnelson	;;
2568cdf0c1d5Smjnelson*)
2569cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2570cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2571cdf0c1d5Smjnelson		exit 1
2572cdf0c1d5Smjnelson	fi
2573cdf0c1d5Smjnelson	;;
2574cdf0c1d5Smjnelsonesac
25757c478bd9Sstevel@tonic-gate
2576daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2577daaffb31Sdp
2578daaffb31Sdpif [[ -n $lflag ]]; then
2579daaffb31Sdp	#
2580daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2581daaffb31Sdp	# then generate the file list by extracting file names from a
2582daaffb31Sdp	# putback -n.
2583daaffb31Sdp	#
2584daaffb31Sdp	shift $(($OPTIND - 1))
2585cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2586daaffb31Sdp		flist_from_teamware "$*"
2587cdf0c1d5Smjnelson	else
2588cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2589cdf0c1d5Smjnelson		exit 1
2590cdf0c1d5Smjnelson	fi
2591daaffb31Sdp	flist_done=1
2592daaffb31Sdp	shift $#
2593daaffb31Sdpelif [[ -n $wflag ]]; then
2594daaffb31Sdp	#
2595daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2596daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2597daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2598daaffb31Sdp	# in building the index.html file.
2599daaffb31Sdp	#
2600daaffb31Sdp	shift $(($OPTIND - 1))
2601daaffb31Sdp	wxfile=$1
2602daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2603daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2604daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2605daaffb31Sdp		fi
2606daaffb31Sdp	fi
2607daaffb31Sdp
2608daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2609daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2610daaffb31Sdp
2611cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2612cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2613cdf0c1d5Smjnelson		usage
2614cdf0c1d5Smjnelson	fi
2615cdf0c1d5Smjnelson
2616daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2617daaffb31Sdp	flist_from_wx $wxfile
2618daaffb31Sdp	flist_done=1
2619daaffb31Sdp	if [[ -n "$*" ]]; then
2620daaffb31Sdp		shift
2621daaffb31Sdp	fi
262214983201Sdpelif [[ $flist_mode == "stdin" ]]; then
262314983201Sdp	print -u2 " File list from: standard input"
262414983201Sdpelif [[ $flist_mode == "file" ]]; then
262514983201Sdp	print -u2 " File list from: $flist_file"
2626daaffb31Sdpfi
2627daaffb31Sdp
2628daaffb31Sdpif [[ $# -gt 0 ]]; then
262914983201Sdp	print -u2 "WARNING: unused arguments: $*"
2630daaffb31Sdpfi
2631daaffb31Sdp
26322d9224a3SMark J. Nelson#
26332d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS
26342d9224a3SMark J. Nelson# and CODEMGR_WS as needed.  Here, we set the parent workspace.
26352d9224a3SMark J. Nelson#
26362d9224a3SMark J. Nelson
2637daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
26382d9224a3SMark J. Nelson
2639daaffb31Sdp	#
26402d9224a3SMark J. Nelson	# Teamware priorities:
2641daaffb31Sdp	#
26422d9224a3SMark J. Nelson	#      1) via -p command line option
2643daaffb31Sdp	#      2) in the user environment
2644daaffb31Sdp	#      3) in the flist
26452d9224a3SMark J. Nelson	#      4) automatically based on the workspace
2646daaffb31Sdp	#
2647daaffb31Sdp
2648daaffb31Sdp	#
26492d9224a3SMark J. Nelson	# For 1, codemgr_parent will already be set.  Here's 2:
2650daaffb31Sdp	#
2651daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2652daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2653daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2654daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
26557c478bd9Sstevel@tonic-gate		exit 1
26567c478bd9Sstevel@tonic-gate	fi
26577c478bd9Sstevel@tonic-gate
2658daaffb31Sdp	#
2659daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2660daaffb31Sdp	# list, then see if we can get it by probing for wx.
2661daaffb31Sdp	#
266214983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
266314983201Sdp		if [[ ! -x $WX ]]; then
266414983201Sdp			print -u2 "WARNING: wx not found!"
2665daaffb31Sdp		fi
26667c478bd9Sstevel@tonic-gate
2667daaffb31Sdp		#
2668daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2669daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2670daaffb31Sdp		# hang asking us to initialize our wx information.
2671daaffb31Sdp		#
267214983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2673daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2674daaffb31Sdp			$WX list -w > $FLIST
2675daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2676daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2677daaffb31Sdp			print -u2 "done"
2678daaffb31Sdp			flist_done=1
2679daaffb31Sdp		fi
2680daaffb31Sdp	fi
2681daaffb31Sdp
2682daaffb31Sdp	#
2683daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2684daaffb31Sdp	# from the command line), eval it to extract environment variables from
26852d9224a3SMark J. Nelson	# it: This is method 3 for finding the parent.
2686daaffb31Sdp	#
2687daaffb31Sdp	if [[ -z $flist_done ]]; then
2688daaffb31Sdp		flist_from_teamware
2689daaffb31Sdp	fi
26902d9224a3SMark J. Nelson	env_from_flist
2691daaffb31Sdp
2692daaffb31Sdp	#
2693daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2694daaffb31Sdp	# from workspace.
2695daaffb31Sdp	#
2696daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2697daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2698daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2699daaffb31Sdp		exit 1
2700daaffb31Sdp	fi
2701daaffb31Sdp
2702daaffb31Sdp	PWS=$codemgr_parent
2703cdf0c1d5Smjnelson
2704cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2705cdf0c1d5Smjnelson
2706cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2707cdf0c1d5Smjnelson	#
2708cdf0c1d5Smjnelson	# Parent can either be specified with -p
2709cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2710cdf0c1d5Smjnelson	# or taken from hg's default path.
2711cdf0c1d5Smjnelson	#
2712cdf0c1d5Smjnelson
2713cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2714cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2715cdf0c1d5Smjnelson	fi
2716cdf0c1d5Smjnelson
2717cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2718cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2719cdf0c1d5Smjnelson	fi
2720cdf0c1d5Smjnelson
2721cdf0c1d5Smjnelson	PWS=$codemgr_parent
2722cdf0c1d5Smjnelson
2723cdf0c1d5Smjnelson	#
2724cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2725cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2726cdf0c1d5Smjnelson	#
2727cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2728cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2729cdf0c1d5Smjnelson	else
2730cdf0c1d5Smjnelson		real_parent=$PWS
2731cdf0c1d5Smjnelson	fi
2732cdf0c1d5Smjnelson
2733cdf0c1d5Smjnelson	#
2734cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2735cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2736cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2737cdf0c1d5Smjnelson	# files mentioned in the flist.
2738cdf0c1d5Smjnelson	#
2739cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2740cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2741cdf0c1d5Smjnelson		flist_done=1
2742cdf0c1d5Smjnelson	fi
2743cdf0c1d5Smjnelson
2744cdf0c1d5Smjnelson	#
2745cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2746cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2747cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2748cdf0c1d5Smjnelson	# in the user-specified flist.
2749cdf0c1d5Smjnelson	#
2750cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2751cdf0c1d5Smjnelson		env_from_flist
2752cdf0c1d5Smjnelson	fi
2753cdf0c1d5Smjnelson
2754cdf0c1d5Smjnelson	#
2755cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2756cdf0c1d5Smjnelson	#
2757cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2758cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2759cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2760cdf0c1d5Smjnelson		print " Done."
2761cdf0c1d5Smjnelson	fi
2762cdf0c1d5Smjnelson
2763cdf0c1d5Smjnelson	#
2764cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2765cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2766cdf0c1d5Smjnelson	# if we don't have one.
2767cdf0c1d5Smjnelson	#
2768cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2769b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2770cdf0c1d5Smjnelson	fi
2771cdf0c1d5Smjnelson
2772cdf0c1d5Smjnelson	#
2773cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2774cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2775cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2776cdf0c1d5Smjnelson	#
2777cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2778cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2779b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2780cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2781cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2782cdf0c1d5Smjnelson		exit 1
2783cdf0c1d5Smjnelson	fi
27848bcea973SRichard Lowe
27858bcea973SRichard Lowe	pnode=$(trim_digest $HG_PARENT)
27868bcea973SRichard Lowe	PRETTY_PWS="${PWS} (at ${pnode})"
27878bcea973SRichard Lowe	cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
27888bcea973SRichard Lowe	    2>/dev/null)
27898bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"}
27908bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
27918bcea973SRichard Lowe	#
27928bcea973SRichard Lowe	# Parent can either be specified with -p, or specified with
27938bcea973SRichard Lowe	# CODEMGR_PARENT in the environment.
27948bcea973SRichard Lowe	#
27958bcea973SRichard Lowe
27968bcea973SRichard Lowe	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
27978bcea973SRichard Lowe		codemgr_parent=$CODEMGR_PARENT
27988bcea973SRichard Lowe	fi
27998bcea973SRichard Lowe
28008bcea973SRichard Lowe	# Try to figure out the parent based on the branch the current
28018bcea973SRichard Lowe	# branch is tracking, if we fail, use origin/master
28028bcea973SRichard Lowe	this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }')
28038bcea973SRichard Lowe	par_branch="origin/master"
28048bcea973SRichard Lowe
28058bcea973SRichard Lowe        # If we're not on a branch there's nothing we can do
28068bcea973SRichard Lowe        if [[ $this_branch != "(no branch)" ]]; then
28078bcea973SRichard Lowe                $GIT for-each-ref                                                 \
28088bcea973SRichard Lowe                    --format='%(refname:short) %(upstream:short)' refs/heads/ |   \
28098bcea973SRichard Lowe                    while read local remote; do                                   \
28108bcea973SRichard Lowe                	[[ "$local" == "$this_branch" ]] && par_branch="$remote"; \
28118bcea973SRichard Lowe                    done
28128bcea973SRichard Lowe	fi
28138bcea973SRichard Lowe
28148bcea973SRichard Lowe	if [[ -z $codemgr_parent ]]; then
28158bcea973SRichard Lowe		codemgr_parent=$par_branch
28168bcea973SRichard Lowe	fi
28178bcea973SRichard Lowe	PWS=$codemgr_parent
28188bcea973SRichard Lowe
28198bcea973SRichard Lowe	#
28208bcea973SRichard Lowe	# If the parent is a webrev, we want to do some things against
28218bcea973SRichard Lowe	# the natural workspace parent (file list, comments, etc)
28228bcea973SRichard Lowe	#
28238bcea973SRichard Lowe	if [[ -n $parent_webrev ]]; then
28248bcea973SRichard Lowe		real_parent=$par_branch
28258bcea973SRichard Lowe	else
28268bcea973SRichard Lowe		real_parent=$PWS
28278bcea973SRichard Lowe	fi
28288bcea973SRichard Lowe
28298bcea973SRichard Lowe	if [[ -z $flist_done ]]; then
28308bcea973SRichard Lowe		flist_from_git "$CWS" "$real_parent"
28318bcea973SRichard Lowe		flist_done=1
28328bcea973SRichard Lowe	fi
28338bcea973SRichard Lowe
28348bcea973SRichard Lowe	#
28358bcea973SRichard Lowe	# If we have a file list now, pull out any variables set
28368bcea973SRichard Lowe	# therein.
28378bcea973SRichard Lowe	#
28388bcea973SRichard Lowe	if [[ -n $flist_done ]]; then
28398bcea973SRichard Lowe		env_from_flist
28408bcea973SRichard Lowe	fi
28418bcea973SRichard Lowe
28428bcea973SRichard Lowe	#
28438bcea973SRichard Lowe	# If we don't have a wx-format file list, build one we can pull change
28448bcea973SRichard Lowe	# comments from.
28458bcea973SRichard Lowe	#
28468bcea973SRichard Lowe	if [[ -z $wxfile ]]; then
28478bcea973SRichard Lowe		print "  Comments from: git...\c"
28488bcea973SRichard Lowe		git_wxfile "$CWS" "$real_parent"
28498bcea973SRichard Lowe		print " Done."
28508bcea973SRichard Lowe	fi
28518bcea973SRichard Lowe
28528bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
28538bcea973SRichard Lowe		GIT_PARENT=$($GIT merge-base "$real_parent" HEAD)
28548bcea973SRichard Lowe	fi
28558bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
28568bcea973SRichard Lowe		print -u2 "Error: Cannot discover parent revision"
28578bcea973SRichard Lowe		exit 1
28588bcea973SRichard Lowe	fi
28598bcea973SRichard Lowe
28608bcea973SRichard Lowe	pnode=$(trim_digest $GIT_PARENT)
28618bcea973SRichard Lowe
28628bcea973SRichard Lowe	if [[ $real_parent == */* ]]; then
28638bcea973SRichard Lowe		origin=$(echo $real_parent | cut -d/ -f1)
28648bcea973SRichard Lowe		origin=$($GIT remote -v | \
28658bcea973SRichard Lowe		    $AWK '$1 == "'$origin'" { print $2; exit }')
28668bcea973SRichard Lowe		PRETTY_PWS="${PWS} (${origin} at ${pnode})"
28678bcea973SRichard Lowe	else
28688bcea973SRichard Lowe		PRETTY_PWS="${PWS} (at ${pnode})"
28698bcea973SRichard Lowe	fi
28708bcea973SRichard Lowe
28718bcea973SRichard Lowe	cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \
28728bcea973SRichard Lowe	    2>/dev/null)
28738bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"
2874cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2875cdf0c1d5Smjnelson
2876cdf0c1d5Smjnelson	#
2877cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2878cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2879cdf0c1d5Smjnelson	#
2880cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2881cdf0c1d5Smjnelson
2882cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2883cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2884cdf0c1d5Smjnelson	fi
2885cdf0c1d5Smjnelsonelse
2886cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2887cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2888cdf0c1d5Smjnelson    else
2889cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2890cdf0c1d5Smjnelson    fi
2891cdf0c1d5Smjnelson
2892cdf0c1d5Smjnelson    env_from_flist
2893cdf0c1d5Smjnelson
2894cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2895cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2896cdf0c1d5Smjnelson	exit 1
2897cdf0c1d5Smjnelson    fi
2898cdf0c1d5Smjnelson
2899cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2900cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2901cdf0c1d5Smjnelson	exit 1
2902cdf0c1d5Smjnelson    fi
2903cdf0c1d5Smjnelson
2904cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2905cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2906daaffb31Sdpfi
2907daaffb31Sdp
2908daaffb31Sdp#
2909daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2910daaffb31Sdp# webrev-info file in the workspace directory.
2911daaffb31Sdp#
2912daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2913daaffb31Sdp	iflag=1
2914daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2915daaffb31Sdpfi
2916daaffb31Sdp
2917daaffb31Sdpif [[ -n $iflag ]]; then
2918daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2919daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2920daaffb31Sdp		    "not readable."
2921daaffb31Sdp		exit 1
2922daaffb31Sdp	else
2923daaffb31Sdp		#
2924daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2925daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2926daaffb31Sdp		#
2927daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2928daaffb31Sdp	fi
2929daaffb31Sdpfi
2930daaffb31Sdp
29310fd2682eSMark J. Nelson# DO_EVERYTHING: break point
29320fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
29330fd2682eSMark J. Nelson	break
29340fd2682eSMark J. Nelsonfi
29350fd2682eSMark J. Nelson
29360fd2682eSMark J. Nelsontypeset -A itsinfo
29370fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
29380fd2682eSMark J. Nelsonvalid_prefixes=
29390fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
29408bcea973SRichard Lowe	DEFREGFILE="$(/bin/dirname "$(whence $0)")/../etc/its.reg"
29410fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
29420fd2682eSMark J. Nelson		REGFILE=$ITSREG
29430fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
29440fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
29450fd2682eSMark J. Nelson	else
29460fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
29470fd2682eSMark J. Nelson	fi
29480fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
29490fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
29500fd2682eSMark J. Nelson		exit 1
29510fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
29520fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
29530fd2682eSMark J. Nelson	fi
29540fd2682eSMark J. Nelson
29550fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
29560fd2682eSMark J. Nelson
29570fd2682eSMark J. Nelson		name=${LINE%%=*}
29580fd2682eSMark J. Nelson		value="${LINE#*=}"
29590fd2682eSMark J. Nelson
29600fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
29610fd2682eSMark J. Nelson			p=${value}
29620fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
29630fd2682eSMark J. Nelson		else
29640fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
29650fd2682eSMark J. Nelson		fi
29660fd2682eSMark J. Nelson	done
29670fd2682eSMark J. Nelson
29680fd2682eSMark J. Nelson
29698bcea973SRichard Lowe	DEFCONFFILE="$(/bin/dirname "$(whence $0)")/../etc/its.conf"
29700fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
29710fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
29720fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
29730fd2682eSMark J. Nelson	fi
29740fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
29750fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
29760fd2682eSMark J. Nelson	fi
29770fd2682eSMark J. Nelson	its_domain=
29780fd2682eSMark J. Nelson	its_priority=
29790fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
29800fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
29810fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
29820fd2682eSMark J. Nelson			exit 1
29830fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
29840fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
29850fd2682eSMark J. Nelson		fi
29860fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
29870fd2682eSMark J. Nelson		    eval "${LINE}"
29880fd2682eSMark J. Nelson		done
29890fd2682eSMark J. Nelson	done
29900fd2682eSMark J. Nelson
29910fd2682eSMark J. Nelson	#
29920fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
29930fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
29940fd2682eSMark J. Nelson	#
29950fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
29960fd2682eSMark J. Nelson	#
29970fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
29980fd2682eSMark J. Nelson		#
29990fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
30000fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
30010fd2682eSMark J. Nelson		#
30020fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
30030fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
30040fd2682eSMark J. Nelson		else
30050fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
30060fd2682eSMark J. Nelson		fi
30070fd2682eSMark J. Nelson
30080fd2682eSMark J. Nelson		#
30090fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
30100fd2682eSMark J. Nelson		# to this information tracking system should resolve through
30110fd2682eSMark J. Nelson		# the same URL.
30120fd2682eSMark J. Nelson		#
30130fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
30140fd2682eSMark J. Nelson		#
30150fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
30160fd2682eSMark J. Nelson		# INTERNAL_URL.
30170fd2682eSMark J. Nelson		#
30180fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
30190fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
30200fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
30210fd2682eSMark J. Nelson				break
30220fd2682eSMark J. Nelson			fi
30230fd2682eSMark J. Nelson		done
30240fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
30250fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
30260fd2682eSMark J. Nelson		fi
30270fd2682eSMark J. Nelson
30280fd2682eSMark J. Nelson		#
30290fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
30300fd2682eSMark J. Nelson		#
30310fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
30320fd2682eSMark J. Nelson
30332f54b716SRichard Lowe		# The character class below contains a literal tab
30342f54b716SRichard Lowe		print "/^${p}[: 	]/ {
30350fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
30360fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
30370fd2682eSMark J. Nelson			}" >> ${its_sed_script}
30380fd2682eSMark J. Nelson	done
30390fd2682eSMark J. Nelson
30400fd2682eSMark J. Nelson	#
30410fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
30420fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
30430fd2682eSMark J. Nelson	#
30440fd2682eSMark J. Nelson	for p in ${its_priority}; do
30450fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
30462f54b716SRichard Lowe				s;^${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
30470fd2682eSMark J. Nelson			}" >> ${its_sed_script}
30480fd2682eSMark J. Nelson	done
30490fd2682eSMark J. Nelsonfi
30500fd2682eSMark J. Nelson
30510fd2682eSMark J. Nelson#
30520fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
30530fd2682eSMark J. Nelson# and explanation of this terminator.
30540fd2682eSMark J. Nelson#
30550fd2682eSMark J. Nelsondone
30560fd2682eSMark J. Nelson
3057daaffb31Sdp#
3058daaffb31Sdp# Output directory.
3059daaffb31Sdp#
3060daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
3061daaffb31Sdp
3062daaffb31Sdp#
306302d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
306402d26c39SVladimir Kotal# in the future this could potentially be an option.
3065daaffb31Sdp#
306602d26c39SVladimir Kotalif [[ -n $oflag ]]; then
306702d26c39SVladimir Kotal	WNAME=${WDIR##*/}
306802d26c39SVladimir Kotalelse
3069daaffb31Sdp	WNAME=${CWS##*/}
307002d26c39SVladimir Kotalfi
307102d26c39SVladimir Kotal
3072ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
3073ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
3074b0088928SVladimir Kotal	#
3075ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
3076ba44d8a2SVladimir Kotal	# the default values.
3077b0088928SVladimir Kotal	#
3078ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
3079ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
3080ba44d8a2SVladimir Kotal	else
3081b0088928SVladimir Kotal		#
3082b0088928SVladimir Kotal		# Check upload target prefix first.
3083b0088928SVladimir Kotal		#
3084b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
3085b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
3086b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
3087b0088928SVladimir Kotal			    "($remote_target)"
3088b0088928SVladimir Kotal			exit 1
3089b0088928SVladimir Kotal		fi
3090b0088928SVladimir Kotal		#
3091ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
3092ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
3093ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
3094ba44d8a2SVladimir Kotal		# local webrev directory name.
3095b0088928SVladimir Kotal		#
3096b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
3097b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
3098ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
3099b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
3100ba44d8a2SVladimir Kotal			fi
3101b0088928SVladimir Kotal		else
3102b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
3103b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
3104b0088928SVladimir Kotal					"($remote_target)"
3105b0088928SVladimir Kotal				exit 1
3106b0088928SVladimir Kotal			else
3107b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
3108ba44d8a2SVladimir Kotal			fi
3109ba44d8a2SVladimir Kotal		fi
3110ba44d8a2SVladimir Kotal	fi
3111ba44d8a2SVladimir Kotal
3112b0088928SVladimir Kotal	#
3113b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
3114b0088928SVladimir Kotal	# specification separately.
3115b0088928SVladimir Kotal	#
3116b0088928SVladimir Kotal	remote_target=${remote_target%/}
3117b0088928SVladimir Kotalfi
3118b0088928SVladimir Kotal
3119b0088928SVladimir Kotal#
3120ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
3121b0088928SVladimir Kotal#
3122ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
3123b0088928SVladimir Kotal	delete_webrev 1 1
3124ba44d8a2SVladimir Kotal	exit $?
3125ba44d8a2SVladimir Kotalfi
3126ba44d8a2SVladimir Kotal
3127b0088928SVladimir Kotal#
3128ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
3129b0088928SVladimir Kotal#
3130ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
3131ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
3132b0088928SVladimir Kotal		delete_webrev 1 1
3133ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
3134ba44d8a2SVladimir Kotal	fi
3135ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
313602d26c39SVladimir Kotal		upload_webrev
313702d26c39SVladimir Kotal		exit $?
313802d26c39SVladimir Kotal	fi
3139ba44d8a2SVladimir Kotalfi
3140daaffb31Sdp
3141e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
31427c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
31437c478bd9Sstevel@tonic-gatefi
3144daaffb31Sdp
3145daaffb31Sdpif [[ ! -d $WDIR ]]; then
3146daaffb31Sdp	mkdir -p $WDIR
3147ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
31487c478bd9Sstevel@tonic-gatefi
31497c478bd9Sstevel@tonic-gate
3150daaffb31Sdp#
3151daaffb31Sdp# Summarize what we're going to do.
3152daaffb31Sdp#
31538bcea973SRichard Loweprint "      Workspace: ${PRETTY_CWS:-$CWS}"
3154daaffb31Sdpif [[ -n $parent_webrev ]]; then
3155daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
3156daaffb31Sdpelse
31578bcea973SRichard Lowe	print "Compare against: ${PRETTY_PWS:-$PWS}"
3158cdf0c1d5Smjnelsonfi
3159daaffb31Sdp
3160daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
3161daaffb31Sdpprint "      Output to: $WDIR"
3162daaffb31Sdp
3163daaffb31Sdp#
31647c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
3165daaffb31Sdp#
3166daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
31677c478bd9Sstevel@tonic-gate
3168daaffb31Sdprm -f $WDIR/$WNAME.patch
3169daaffb31Sdprm -f $WDIR/$WNAME.ps
3170daaffb31Sdprm -f $WDIR/$WNAME.pdf
31717c478bd9Sstevel@tonic-gate
3172daaffb31Sdptouch $WDIR/$WNAME.patch
31737c478bd9Sstevel@tonic-gate
3174daaffb31Sdpprint "   Output Files:"
3175daaffb31Sdp
3176daaffb31Sdp#
3177daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
3178daaffb31Sdp#
3179b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
3180daaffb31SdpFLIST=/tmp/$$.flist.clean
3181daaffb31Sdp
3182daaffb31Sdp#
3183cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
3184cdf0c1d5Smjnelson#
3185cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
3186cdf0c1d5Smjnelson	#
3187cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
3188cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
3189cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
3190cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
3191cdf0c1d5Smjnelson	#    keep only the old name.
3192cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
3193cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
3194cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
3195cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
3196cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
3197e6ccc173SEdward Pilatowicz	# 4) Eliminate any duplicate entries.  (This can occur if a
3198e6ccc173SEdward Pilatowicz	#    file has been used as the source of an hg cp and it's
3199e6ccc173SEdward Pilatowicz	#    also been modified in the same changeset.)
3200cdf0c1d5Smjnelson	#
3201cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
3202b0088928SVladimir Kotal	$SED '
3203cdf0c1d5Smjnelson		s#^[^ ]* ##
3204cdf0c1d5Smjnelson		s#/#\\\/#g
3205cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
3206e6ccc173SEdward Pilatowicz	' < $FLIST | $SORT -u > $SEDFILE
3207cdf0c1d5Smjnelson
3208cdf0c1d5Smjnelson	#
3209cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
3210cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
3211cdf0c1d5Smjnelson	#
3212cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
3213cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
3214b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
3215cdf0c1d5Smjnelsonfi
3216cdf0c1d5Smjnelson
3217cdf0c1d5Smjnelson#
3218daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
3219daaffb31Sdp#
3220daaffb31Sdpcat $FLIST | while read LINE
32217c478bd9Sstevel@tonic-gatedo
32227c478bd9Sstevel@tonic-gate	set - $LINE
32237c478bd9Sstevel@tonic-gate	P=$1
32247c478bd9Sstevel@tonic-gate
3225daaffb31Sdp	#
3226daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
3227daaffb31Sdp	# file that has been modified or created in the child.  A file
3228daaffb31Sdp	# that is renamed in the child workspace has two names on the
3229daaffb31Sdp	# line: new name followed by the old name.
3230daaffb31Sdp	#
3231daaffb31Sdp	oldname=""
3232daaffb31Sdp	oldpath=""
3233daaffb31Sdp	rename=
3234daaffb31Sdp	if [[ $# -eq 2 ]]; then
32357c478bd9Sstevel@tonic-gate		PP=$2			# old filename
3236e6ccc173SEdward Pilatowicz		if [[ -f $PP ]]; then
3237e6ccc173SEdward Pilatowicz			oldname=" (copied from $PP)"
3238e6ccc173SEdward Pilatowicz		else
3239e6ccc173SEdward Pilatowicz			oldname=" (renamed from $PP)"
3240e6ccc173SEdward Pilatowicz		fi
3241daaffb31Sdp		oldpath="$PP"
3242daaffb31Sdp		rename=1
32437c478bd9Sstevel@tonic-gate		PDIR=${PP%/*}
3244daaffb31Sdp		if [[ $PDIR == $PP ]]; then
32457c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
32467c478bd9Sstevel@tonic-gate		fi
32477c478bd9Sstevel@tonic-gate
32487c478bd9Sstevel@tonic-gate		PF=${PP##*/}
32497c478bd9Sstevel@tonic-gate
32507c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3251daaffb31Sdp		if [[ $DIR == $P ]]; then
32527c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
32537c478bd9Sstevel@tonic-gate		fi
32547c478bd9Sstevel@tonic-gate
32557c478bd9Sstevel@tonic-gate		F=${P##*/}
3256daaffb31Sdp
32577c478bd9Sstevel@tonic-gate        else
32587c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3259daaffb31Sdp		if [[ "$DIR" == "$P" ]]; then
32607c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
32617c478bd9Sstevel@tonic-gate		fi
32627c478bd9Sstevel@tonic-gate
32637c478bd9Sstevel@tonic-gate		F=${P##*/}
32647c478bd9Sstevel@tonic-gate
32657c478bd9Sstevel@tonic-gate		PP=$P
32667c478bd9Sstevel@tonic-gate		PDIR=$DIR
32677c478bd9Sstevel@tonic-gate		PF=$F
32687c478bd9Sstevel@tonic-gate	fi
32697c478bd9Sstevel@tonic-gate
3270daaffb31Sdp	COMM=`getcomments html $P $PP`
32717c478bd9Sstevel@tonic-gate
3272daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
32737c478bd9Sstevel@tonic-gate
32747c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
32757c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
32767c478bd9Sstevel@tonic-gate
3277daaffb31Sdp	#
3278cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
3279daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
3280daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
3281daaffb31Sdp	#
3282daaffb31Sdp
3283cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
32847c478bd9Sstevel@tonic-gate	    continue
32857c478bd9Sstevel@tonic-gate
3286cdf0c1d5Smjnelson	#
3287cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3288cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3289cdf0c1d5Smjnelson	# consistent environment.
3290cdf0c1d5Smjnelson	#
3291cdf0c1d5Smjnelson	OWD=$PWD
3292daaffb31Sdp	cd $WDIR/raw_files
3293daaffb31Sdp	ofile=old/$PDIR/$PF
3294daaffb31Sdp	nfile=new/$DIR/$F
32957c478bd9Sstevel@tonic-gate
3296daaffb31Sdp	mv_but_nodiff=
3297daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3298daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3299daaffb31Sdp		mv_but_nodiff=1
3300daaffb31Sdp	fi
3301daaffb31Sdp
3302daaffb31Sdp	#
3303daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3304daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3305daaffb31Sdp	#
3306daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3307daaffb31Sdp	#	  diff and an 'add' diff
3308daaffb31Sdp	#	- new files and deleted files must be handled specially
3309daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
3310daaffb31Sdp	#	  (and hence renames) as of this writing.
3311daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
3312daaffb31Sdp	#	  output of Solaris diff properly when it comes to
3313daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
3314daaffb31Sdp	#         transformations:
3315daaffb31Sdp	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3316daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3317daaffb31Sdp	#
3318b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3319b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3320daaffb31Sdp
3321daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3322daaffb31Sdp	if [[ -z $rename ]]; then
3323e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3324daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3325daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3326e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3327daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3328daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3329daaffb31Sdp		else
3330daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3331daaffb31Sdp		fi
3332daaffb31Sdp	else
3333daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3334daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3335daaffb31Sdp
3336daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3337daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3338daaffb31Sdp	fi
3339daaffb31Sdp
3340daaffb31Sdp	#
3341daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3342daaffb31Sdp	# whole wad.
3343daaffb31Sdp	#
3344daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3345daaffb31Sdp
3346daaffb31Sdp	print " patch\c"
3347daaffb31Sdp
3348daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3349daaffb31Sdp
3350daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3351daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3352daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
33537c478bd9Sstevel@tonic-gate		print " cdiffs\c"
33547c478bd9Sstevel@tonic-gate
3355daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3356daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3357daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
3358daaffb31Sdp
33597c478bd9Sstevel@tonic-gate		print " udiffs\c"
33607c478bd9Sstevel@tonic-gate
33617c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3362daaffb31Sdp			$WDIFF -c "$COMM" \
3363daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3364daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3365daaffb31Sdp			if [[ $? -eq 0 ]]; then
33667c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3367daaffb31Sdp			else
3368daaffb31Sdp				print " wdiffs[fail]\c"
3369daaffb31Sdp			fi
33707c478bd9Sstevel@tonic-gate		fi
33717c478bd9Sstevel@tonic-gate
3372daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3373daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
33747c478bd9Sstevel@tonic-gate		print " sdiffs\c"
33757c478bd9Sstevel@tonic-gate
33767c478bd9Sstevel@tonic-gate		print " frames\c"
33777c478bd9Sstevel@tonic-gate
33787c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
33797c478bd9Sstevel@tonic-gate
3380daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3381daaffb31Sdp
3382daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3383daaffb31Sdp		# renamed file: may also have differences
3384daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3385daaffb31Sdp	elif [[ -f $nfile ]]; then
33867c478bd9Sstevel@tonic-gate		# new file: count added lines
3387daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3388daaffb31Sdp	elif [[ -f $ofile ]]; then
33897c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3390daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
33917c478bd9Sstevel@tonic-gate	fi
33927c478bd9Sstevel@tonic-gate
3393daaffb31Sdp	#
3394daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3395daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3396daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3397daaffb31Sdp	#
3398daaffb31Sdp	if [[ -f $nfile ]]; then
3399daaffb31Sdp		ocr=$ofile
3400daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3401daaffb31Sdp
3402daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3403daaffb31Sdp			textcomm=`getcomments text $P $PP`
340414983201Sdp			if [[ -x $CODEREVIEW ]]; then
340514983201Sdp				$CODEREVIEW -y "$textcomm" \
340614983201Sdp				    -e $ocr $nfile \
340714983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
340814983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3409daaffb31Sdp				if [[ $? -eq 0 ]]; then
3410daaffb31Sdp					print " ps\c"
3411daaffb31Sdp				else
3412daaffb31Sdp					print " ps[fail]\c"
3413daaffb31Sdp				fi
3414daaffb31Sdp			fi
3415daaffb31Sdp		fi
341614983201Sdp	fi
3417daaffb31Sdp
3418cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3419cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
34207c478bd9Sstevel@tonic-gate		print " old\c"
34217c478bd9Sstevel@tonic-gate	fi
34227c478bd9Sstevel@tonic-gate
3423daaffb31Sdp	if [[ -f $nfile ]]; then
3424daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
34257c478bd9Sstevel@tonic-gate		print " new\c"
34267c478bd9Sstevel@tonic-gate	fi
34277c478bd9Sstevel@tonic-gate
3428cdf0c1d5Smjnelson	cd $OWD
3429cdf0c1d5Smjnelson
3430daaffb31Sdp	print
34317c478bd9Sstevel@tonic-gatedone
34327c478bd9Sstevel@tonic-gate
3433daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
34347c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3435daaffb31Sdp
343614983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
343714983201Sdp	print " Generating PDF: Skipped: no output available"
343814983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
343914983201Sdp	print " Generating PDF: \c"
344014983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3441daaffb31Sdp	print "Done."
344214983201Sdpelse
344314983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
344414983201Sdpfi
34457c478bd9Sstevel@tonic-gate
3446e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3447e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3448e0e0293aSjmcp
3449e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3450ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3451e0e0293aSjmcpfi
3452e0e0293aSjmcp
34537c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
34547c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
34557c478bd9Sstevel@tonic-gate
34567c478bd9Sstevel@tonic-gatecd $CWS
34577c478bd9Sstevel@tonic-gate
34587c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3459daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
34607c478bd9Sstevel@tonic-gate
3461daaffb31Sdpprint "     index.html: \c"
34627c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
34637c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
34647c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
34657c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
34667c478bd9Sstevel@tonic-gate
3467daaffb31Sdpprint "$HTML<head>$STDHEAD"
3468daaffb31Sdpprint "<title>$WNAME</title>"
3469daaffb31Sdpprint "</head>"
3470daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3471daaffb31Sdpprint "<div class=\"summary\">"
3472daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
34737c478bd9Sstevel@tonic-gate
3474daaffb31Sdpprint "<table>"
34757c478bd9Sstevel@tonic-gate
3476daaffb31Sdp#
3477cdf0c1d5Smjnelson# Get the preparer's name:
3478daaffb31Sdp#
3479cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3480cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3481cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3482cdf0c1d5Smjnelson#
3483cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3484cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3485cdf0c1d5Smjnelson#
3486cdf0c1d5Smjnelsonpreparer=
3487cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3488cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3489cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3490cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3491cdf0c1d5Smjnelson	fi
3492cdf0c1d5Smjnelsonfi
3493cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3494cdf0c1d5Smjnelson	preparer=$(
3495cdf0c1d5Smjnelson	    $PERL -e '
3496cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3497cdf0c1d5Smjnelson	        if ($login) {
3498cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3499cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3500cdf0c1d5Smjnelson	        } else {
3501cdf0c1d5Smjnelson	            printf "(unknown)\n";
3502cdf0c1d5Smjnelson	        }
3503cdf0c1d5Smjnelson	')
3504daaffb31Sdpfi
3505daaffb31Sdp
350648bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
350748bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
35088bcea973SRichard Loweprint "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3509cdf0c1d5Smjnelsonprint "</td></tr>"
3510daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3511daaffb31Sdpif [[ -n $parent_webrev ]]; then
3512daaffb31Sdp	print "webrev at $parent_webrev"
3513daaffb31Sdpelse
35148bcea973SRichard Lowe	print "${PRETTY_PWS:-$PWS}"
3515daaffb31Sdpfi
3516daaffb31Sdpprint "</td></tr>"
3517daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3518daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3519daaffb31Sdpprint "</td></tr>"
3520daaffb31Sdp
3521daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3522371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3523daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3524371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3525daaffb31Sdpfi
3526daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3527371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3528daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3529371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3530daaffb31Sdpfi
3531daaffb31Sdp
3532daaffb31Sdpif [[ -n "$iflag" ]]; then
3533daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3534daaffb31Sdp	cat /tmp/$$.include
3535daaffb31Sdp	print "</div></td></tr>"
3536daaffb31Sdpfi
3537daaffb31Sdpprint "</table>"
3538daaffb31Sdpprint "</div>"
3539daaffb31Sdp
3540daaffb31Sdp#
3541daaffb31Sdp# Second pass through the files: generate the rest of the index file
3542daaffb31Sdp#
3543daaffb31Sdpcat $FLIST | while read LINE
35447c478bd9Sstevel@tonic-gatedo
35457c478bd9Sstevel@tonic-gate	set - $LINE
35467c478bd9Sstevel@tonic-gate	P=$1
35477c478bd9Sstevel@tonic-gate
3548daaffb31Sdp	if [[ $# == 2 ]]; then
35497c478bd9Sstevel@tonic-gate		PP=$2
3550cdf0c1d5Smjnelson		oldname="$PP"
35517c478bd9Sstevel@tonic-gate	else
35527c478bd9Sstevel@tonic-gate		PP=$P
3553daaffb31Sdp		oldname=""
3554daaffb31Sdp	fi
3555daaffb31Sdp
3556cdf0c1d5Smjnelson	mv_but_nodiff=
3557cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3558cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3559cdf0c1d5Smjnelson		mv_but_nodiff=1
3560cdf0c1d5Smjnelson	fi
3561cdf0c1d5Smjnelson
3562daaffb31Sdp	DIR=${P%/*}
3563daaffb31Sdp	if [[ $DIR == $P ]]; then
3564daaffb31Sdp		DIR="."   # File at root of workspace
35657c478bd9Sstevel@tonic-gate	fi
35667c478bd9Sstevel@tonic-gate
35677c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
35687c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
35697c478bd9Sstevel@tonic-gate	# appear twice in the file list
35707c478bd9Sstevel@tonic-gate
35717c478bd9Sstevel@tonic-gate	F=$WDIR/$P
35727c478bd9Sstevel@tonic-gate
3573daaffb31Sdp	print "<p>"
35747c478bd9Sstevel@tonic-gate
35757c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
35767c478bd9Sstevel@tonic-gate
3577daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3578371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3579371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3580371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3581371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
35827c478bd9Sstevel@tonic-gate
3583daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3584371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3585371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
35867c478bd9Sstevel@tonic-gate		fi
35877c478bd9Sstevel@tonic-gate
3588371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3589371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
35907c478bd9Sstevel@tonic-gate
3591371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3592371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
35937c478bd9Sstevel@tonic-gate	else
3594daaffb31Sdp		print " ------ ------ ------"
35957c478bd9Sstevel@tonic-gate
3596daaffb31Sdp		if [[ -x $WDIFF ]]; then
35977c478bd9Sstevel@tonic-gate			print " ------"
35987c478bd9Sstevel@tonic-gate		fi
3599daaffb31Sdp
3600daaffb31Sdp		print " ------"
36017c478bd9Sstevel@tonic-gate	fi
36027c478bd9Sstevel@tonic-gate
36037c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
36047c478bd9Sstevel@tonic-gate
3605daaffb31Sdp	if [[ -f $F-.html ]]; then
3606371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3607371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
36087c478bd9Sstevel@tonic-gate	else
3609daaffb31Sdp		print " ---"
36107c478bd9Sstevel@tonic-gate	fi
36117c478bd9Sstevel@tonic-gate
36127c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
36137c478bd9Sstevel@tonic-gate
3614daaffb31Sdp	if [[ -f $F.html ]]; then
3615371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3616371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
36177c478bd9Sstevel@tonic-gate	else
3618daaffb31Sdp		print " ---"
36197c478bd9Sstevel@tonic-gate	fi
36207c478bd9Sstevel@tonic-gate
3621daaffb31Sdp	if [[ -f $F.patch ]]; then
3622371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3623371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3624daaffb31Sdp	else
3625daaffb31Sdp		print " -----"
3626daaffb31Sdp	fi
3627daaffb31Sdp
3628daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3629371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3630371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3631daaffb31Sdp	else
3632daaffb31Sdp		print " ---"
3633daaffb31Sdp	fi
3634daaffb31Sdp
3635cdf0c1d5Smjnelson	print "<b>$P</b>"
3636cdf0c1d5Smjnelson
3637cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3638e6ccc173SEdward Pilatowicz	if [[ -f "$oldname" ]]; then
3639cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3640e6ccc173SEdward Pilatowicz			print "<i>(copied from $oldname)</i>"
3641cdf0c1d5Smjnelson		else
3642e6ccc173SEdward Pilatowicz			print "<i>(copied and modified from $oldname)</i>"
3643e6ccc173SEdward Pilatowicz		fi
3644e6ccc173SEdward Pilatowicz	elif [[ -n "$oldname" ]]; then
3645e6ccc173SEdward Pilatowicz		if [[ -n "$mv_but_nodiff" ]]; then
3646e6ccc173SEdward Pilatowicz			print "<i>(renamed from $oldname)</i>"
3647e6ccc173SEdward Pilatowicz		else
3648e6ccc173SEdward Pilatowicz			print "<i>(renamed and modified from $oldname)</i>"
3649cdf0c1d5Smjnelson		fi
3650cdf0c1d5Smjnelson	fi
3651cdf0c1d5Smjnelson
3652cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3653cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3654cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3655cdf0c1d5Smjnelson	fi
3656daaffb31Sdp
3657daaffb31Sdp	#
3658e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3659daaffb31Sdp	#
3660daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3661e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3662e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3663daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3664daaffb31Sdp			    "this review</i>"
3665daaffb31Sdp		fi
3666daaffb31Sdp	fi
3667daaffb31Sdp
3668daaffb31Sdp	print "</p>"
36697c478bd9Sstevel@tonic-gate	# Insert delta comments
36707c478bd9Sstevel@tonic-gate
3671daaffb31Sdp	print "<blockquote><pre>"
3672daaffb31Sdp	getcomments html $P $PP
3673daaffb31Sdp	print "</pre>"
36747c478bd9Sstevel@tonic-gate
36757c478bd9Sstevel@tonic-gate	# Add additional comments comment
36767c478bd9Sstevel@tonic-gate
3677daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
36787c478bd9Sstevel@tonic-gate
36797c478bd9Sstevel@tonic-gate	# Add count of changes.
36807c478bd9Sstevel@tonic-gate
3681daaffb31Sdp	if [[ -f $F.count ]]; then
36827c478bd9Sstevel@tonic-gate	    cat $F.count
36837c478bd9Sstevel@tonic-gate	    rm $F.count
36847c478bd9Sstevel@tonic-gate	fi
3685cdf0c1d5Smjnelson
3686cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3687cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3688cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3689cdf0c1d5Smjnelson
3690cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3691cdf0c1d5Smjnelson		# 1) New executable files
3692cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3693cdf0c1d5Smjnelson		# 3) Existing executable files
3694cdf0c1d5Smjnelson
3695cdf0c1d5Smjnelson		old_mode=
3696cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3697cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3698cdf0c1d5Smjnelson		fi
3699cdf0c1d5Smjnelson
3700cdf0c1d5Smjnelson		new_mode=
3701cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3702cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3703cdf0c1d5Smjnelson		fi
3704cdf0c1d5Smjnelson
3705cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3706cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3707cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3708cdf0c1d5Smjnelson			print "</span>"
3709cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3710cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3711cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3712cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3713cdf0c1d5Smjnelson			print "</span>"
3714cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3715cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3716cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3717cdf0c1d5Smjnelson			print "</span>"
3718cdf0c1d5Smjnelson		fi
3719cdf0c1d5Smjnelson	fi
3720cdf0c1d5Smjnelson
3721daaffb31Sdp	print "</blockquote>"
37227c478bd9Sstevel@tonic-gatedone
37237c478bd9Sstevel@tonic-gate
3724daaffb31Sdpprint
3725daaffb31Sdpprint
3726cac38512Smjnelsonprint "<hr></hr>"
3727daaffb31Sdpprint "<p style=\"font-size: small\">"
37289a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
372987a4464eSChris Loveprint "Webrev is maintained by the <a href=\"http://www.illumos.org\">"
373087a4464eSChris Loveprint "illumos</a> project.  The latest version may be obtained"
3731*7646c8f3SMarcel Telkaprint "<a href=\"http://src.illumos.org/source/xref/illumos-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3732daaffb31Sdpprint "</body>"
3733daaffb31Sdpprint "</html>"
37347c478bd9Sstevel@tonic-gate
37357c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
37367c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
37377c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
37387c478bd9Sstevel@tonic-gate
3739daaffb31Sdpprint "Done."
374002d26c39SVladimir Kotal
3741b0088928SVladimir Kotal#
3742ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3743b0088928SVladimir Kotal#
3744ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3745b0088928SVladimir Kotal	delete_webrev 1 1
3746ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3747ba44d8a2SVladimir Kotalfi
3748ba44d8a2SVladimir Kotal
374902d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
375002d26c39SVladimir Kotal	upload_webrev
375102d26c39SVladimir Kotal	exit $?
375202d26c39SVladimir Kotalfi
3753