wx.sh revision daaffb314aae330855b7faea7a653244767ed744
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "@(#)wx 1.12 98/11/09 SMI" (from bonwick)
#ident "@(#)wxx 1.26 03/01/23 SMI" (from fiveash)
#ident "%Z%%M% %I% %E% SMI"
#
# wx -- workspace extensions. Jeff Bonwick, December 1992.
# The bugster cat/subcat = consolidation/os-net-tools
version() {
echo "%Z%%M% %I% %E% SMI"
}
ring_bell() {
# Sound bell to stderr, no newline
print -u2 "\007\c"
}
fail() {
ring_bell
# output error message to stderr
print -u2 "$@ Aborting $command."
exit 1
}
ask() {
typeset question=$1 default_answer=$2
if [ -z "$default_answer" ]; then
echo "$question \c"
else
echo "$question [$default_answer]: \c"
fi
read answer
[ -z "$answer" ] && answer="$default_answer"
}
yesno() {
typeset question="$1"
answer=
while [ -z "$answer" ]; do
ask "$question" y/n
case $answer in
y|yes) answer=yes;;
n|no) answer=no;;
*) answer=;;
esac
done
}
ok_to_proceed() {
yesno "$*"
if [[ "$answer" == no ]]; then
echo "Exiting, no action performed"
exit 1
fi
}
escape_re() {
# Escape the . so they are treated as literals in greps.
echo "$1"|sed 's{\.{\\.{g'
}
remove_local_nt_entry() {
# remove entries in local nt cache
grep -v "^$(escape_re $1) " $wxdir/local_nametable > \
$wxtmp/local_nametable
[[ ! -f $wxtmp/local_nametable ]] && \
fail "Error: cannot create $wxtmp/local_nametable"
mv -f $wxtmp/local_nametable $wxdir/local_nametable ||
fail "Error: cannot create $wxdir/local_nametable."
}
remove_renamed_entry() {
# remove entries in renamed list
# assuming arg is the new filename to remove
grep -v "^$(escape_re $1) " $wxdir/renamed > \
$wxtmp/renamed
[[ ! -f $wxtmp/renamed ]] && fail "Error: cannot create $wxtmp/renamed"
mv -f $wxtmp/renamed $wxdir/renamed ||
fail "Error: mv -f $wxtmp/renamed $wxdir/renamed failed"
}
add_local_nt_entry() {
# Add workspace nametable entry to local nt cache for better perf.
[[ -r $wsdata/nametable ]] || return 0
if ! grep -q "^$(escape_re $1) " $wxdir/local_nametable; then
# add entries from workspace nt to local nt cache
grep "^$(escape_re $1) " $wsdata/nametable >> \
$wxdir/local_nametable
[[ ! -f $wxdir/local_nametable ]] && \
fail "Error: cannot create $wxdir/local_nametable"
fi
return 0
}
remove_active_entry() {
# Remove entry from active list
# $1 is the filepath to remove
nawk '
$1 == target {
# Get past filepath line
while(NF > 0)
getline;
# Get past blank lines
while(NF == 0)
getline;
# Get past comments
while(NF > 0)
getline;
# Get past ending blank lines
while(NF == 0) {
if (getline) {
continue;
} else {
next;
}
}
}
# print the other active list entries
{ print $0; } ' target=$1 $wxdir/active >$wxtmp/tmp_active ||
fail "Error: cannot create $wxtmp/tmp_active."
if mv -f $wxtmp/tmp_active $wxdir/active; then
echo "$1 removed from active list."
remove_local_nt_entry $1
else
cat >&2 <<-EOF
An error occured trying to remove $1 from the active list.
The active list may be corrupt. You should check it out and
possibly run '$ME update' to fix.
EOF
fail
fi
}
rename_active_entry() {
# renamed $1 to $2 filepath in active list
sed "s|^$(escape_re $1)$|$2|" $wxdir/active >\
$wxtmp/active || fail "Error: cannot create $wxtmp/active."
mv -f $wxtmp/active $wxdir/active || \
fail "Error: mv $wxtmp/active $wxdir/active failed."
}
is_active() {
# Return 0 if filepath arg is found in active list.
wx_active|grep -q "^$(escape_re $1)$"
}
#
# ask user if s/he wants to remove an entry from the active list.
# Will not remove entries that differ from parent or are new.
#
ask_remove_active_entry() {
# if an arg is passed in then this is assumed to be the filepath
# otherwise we assume the variables were set properly by the caller
if [[ $# -eq 1 ]]; then
dir=$(dirname $1)
file=$(basename $1)
filepath=$1
if [[ ! -f $file ]]; then
echo "Cannot find $file"
return 1
fi
fi
if is_active $filepath; then
if wx_pnt_filepath $filepath; then
if ! cmp -s $file $parentfilepath; then
cat <<-EOF
The file $filepath
differs from parent file:
$parentfilepath
and will remain in the active list.
EOF
return
fi
else
# New file, leave in active list.
cat <<-EOF
$filepath
is new and will remain in active list. Use:
'$ME uncreate $filepath'
to remove from active list.
EOF
return
fi
# Remove entry from active list because it is the same as
# the parent.
echo "There is no difference between $filepath and the parent"
echo "$parentfilepath"
yesno "Okay to remove $filepath from active list?"
if [[ "$answer" == 'yes' ]]; then
remove_active_entry $filepath
fi
fi
}
refresh_pnt_nt_cache() {
# Refresh the parent nametable cache if necessary.
# Note, this is a cache for the parent nametable entries that
# have the same hash as the local active and renamed files.
# no parent so nothing to update.
[[ -z $parent ]] && return 0
if [[ ! -r $parent/Codemgr_wsdata/nametable ]]; then
fail "Error: cannot read $parent/Codemgr_wsdata/nametable"
fi
if [[ ! -f $wxtmp/parent_nametable ||
$parent/Codemgr_wsdata/nametable -nt $wxtmp/parent_nametable ||
$wsdata/parent -nt $wxtmp/parent_nametable ||
$wxdir/local_nametable -nt $wxtmp/parent_nametable ]]; then
cut -f2- -d' ' $wxdir/local_nametable > $wxtmp/hash_list
if [[ ! -f $wxtmp/hash_list ]]; then
fail "Error: cannot create $wxtmp/hash_list."
fi
if [[ -s $wxtmp/hash_list ]]; then
# Use hash list to get only the parent files
# we're interested in.
fgrep -f $wxtmp/hash_list \
$parent/Codemgr_wsdata/nametable \
> $wxtmp/parent_nametable
[[ ! -f $wxtmp/parent_nametable ]] && \
fail "Error: cannot create $wxtmp/parent_nametable"
else
# There aren't any files to search for so just
# update the timestamp.
touch $wxtmp/parent_nametable
fi
fi
}
# add an active file to the new list
add_new() {
typeset efp=$(escape_re $1)
# update new file list
if [[ ! -f $wxdir/new ]]; then
touch $wxdir/new || fail "Error: cannot create $wxdir/new."
fi
if is_active $1 && ! grep -q "^$efp$" $wxdir/new; then
echo "$1" >> $wxdir/new || fail "Error: cannot update $wxdir/new."
fi
}
# remove a file from the new list
remove_new() {
# remove entries in new list
typeset efp=$(escape_re $1)
if [[ -f $wxdir/new ]] && grep -q "^$efp$" $wxdir/new; then
grep -v "^$efp$" $wxdir/new > $wxtmp/new
[[ ! -f $wxtmp/new ]] && fail "Error: cannot create $wxtmp/new"
mv -f $wxtmp/new $wxdir/new || fail "Error: cannot create $wxdir/new."
fi
}
update_active() {
# Try to add an entry to the active list
typeset efp=$(escape_re $1)
if ! is_active $1; then
if [[ -n "$comment_file" ]]; then
# Use sed to remove any empty lines from comment file.
(echo $1; echo; sed '/^[ ]*$/d' $comment_file;\
echo) >>$wxdir/active ||
fail "Could not update active list."
else
(echo $1; echo; wx_show_comment; echo) \
>> $wxdir/active ||
fail "Could not update active list."
echo "Remember to edit the comment in the active list "\
"(use '$ME ea')."
fi
add_local_nt_entry $1
fi # End if not in active list
}
sort_active() {
typeset origfp=$filepath
# Note must use filepath for wx_show_comment
wx_active | sort | while read filepath; do
(print "$filepath"; print; wx_show_comment; print)
done > $wxtmp/active_sort || \
fail "Error: cannot create $wxtmp/active_sort"
mv -f $wxtmp/active_sort $wxdir/active || \
fail "Error: cannot create $wxdir/active"
filepath=$origfp
}
sort_renamed() {
sort $wxdir/renamed > $wxtmp/renamed_sort || \
fail "Error: cannot create $wxtmp/renamed_sort"
mv -f $wxtmp/renamed_sort $wxdir/renamed || \
fail "Error: cannot create $wxdir/active"
}
update_active_comment() {
# replace comment in active list entry with contents of $comment_file
nawk '
# find active list entry to modify
$1 == filepath {
# print filepath line
while(NF > 0){
print $1;
getline;
}
#print 1 blank (delimit)
print "";
# Get past blank lines
while(NF == 0){
getline;
}
# Get past active entry comments
# append to or replace comment
if (comment_mode == "append"){
while(NF > 0) {
# output existing comments
print $0;
getline;
}
} else {
# get past existing comments
while(NF > 0) getline;
}
# output new comments
while (getline < comments){
# do not print blank lines
if (NF > 0)
print $0
}
close comments
# print delimiting blank line
printf "\n"
# Get past ending blank lines in active entry
NF=0
while(NF == 0) {
if (getline) {
continue;
} else {
next;
}
}
}
# print the other active list entries
{ print $0; } ' filepath=$1 comment_mode=$comment_mode \
comments=$comment_file $wxdir/active >$wxtmp/tmp_active && \
mv $wxtmp/tmp_active $wxdir/active
if [[ $? -eq 0 ]]; then
echo "$1 comment(s) updated in active list."
else
cat <<-EOF
An error occured trying to update comments for $1 in the active list.
The active list ($wxdir/active) may be corrupt. You should check it out
and possilbly run '$ME ea' to fix.
EOF
fail
fi
}
lookup_parent() {
# Find a local file's parent filepath.
# Returns 1 if not found (local file is new)
# Sets env var. parentfilepath and parenthash if found
# Requires a file arg.
# Updates local and parent nt caches.
typeset efp parententry localfile hash1 hash2 hash3 hash4 \
local_nt pnt_nt
parentfile=
parenthash=
if [[ -z $parent ]]; then
cat >&2 <<-EOF
Warning: there is no parent for the current workspace so local file:
$1
is assumed to be new.
EOF
return 1
fi
if [[ ! -f $wsdata/nametable ]]; then
# Nothing has been brought over so assuming new file.
cat >&2 <<-EOF
Warning: the $wsdata/nametable
doesn't exist so
$1
is assumed to be new.
EOF
return 1
fi
if [[ ! -r $parent/Codemgr_wsdata/nametable ]]; then
fail "Error: cannot read $parent/Codemgr_wsdata/nametable."
fi
if [[ ! -f $wxtmp/parent_nametable ]] || $need_pnt_refresh; then
refresh_pnt_nt_cache
need_pnt_refresh=false
fi
if [[ ! -f $wxdir/local_nametable ]]; then
touch $wxdir/local_nametable ||
fail "Error: cannot create $wxdir/local_nametable."
fi
efp=$(escape_re $1)
for local_nt in $wxdir/local_nametable $wsdata/nametable; do
# May be multiple entries in nametable, see if one
# matches parent.
grep "^$efp " $local_nt |\
while read localfile hash1 hash2 hash3 hash4; do
for pnt_nt in $wxtmp/parent_nametable \
$parent/Codemgr_wsdata/nametable; do
# get current parent nt entry
parententry=$(grep \
" $hash1 $hash2 $hash3 $hash4$" $pnt_nt)
if [[ -n "$parententry" ]]; then
# found parent entry
parentfile=$(echo "$parententry" |\
cut -f1 -d' ')
parenthash="$(echo "$parententry" |\
cut -f2- -d' ')"
if [[ "$local_nt" == \
"$wsdata/nametable" ]]; then
# Update the local nt
# hash cache if parent
# found and local
# workspace nt used.
add_local_nt_entry $localfile
fi
if [[ $pnt_nt == \
$parent/Codemgr_wsdata/nametable ]]
then
# Update the parent nt
# hash cache if actual
# parent nt used.
echo $parententry >>\
$wxtmp/parent_nametable
fi
# break out of all the loops if
# parent found
break 3
fi
done # for pnt_nt
done # while read active file
done # for local_nt
if [[ -z "$parentfile" ]]; then
# parent filepath not found.
return 1
else
# parent filepath found.
return 0
fi
}
#
# Detect if a file was locally renamed
#
renamed() {
# Return 0 if renamed, 1 if not locally renamed
# parentfile and parenthash set as side effect
# Must be used by commands that set filepath (like wx_eval)
if [[ ! -f $wxdir/renamed ]]; then
update_renamed_dir
fi
# new is the new filename in the current ws, old is the previous
# filename that should exist in parent ws.
if grep -q "^$(escape_re $filepath) " $wxdir/renamed; then
if lookup_parent $filepath; then
return 0
else
# New files aren't in $wxdir/renamed so no
# parent is a problem
fail "Error: renamed $filepath but no matching parent"\
"file in $parent"
fi
else
# not locally renamed
return 1
fi
}
wx_pnt_filepath() {
# return 0 if parent file found. Side effect: sets parentfilepath
# and parentsdot. parentfile and parenthash are set via lookup_parent.
# if an arg is passed in then this is assumed to be the filepath
# otherwise we assume the variables were set properly by the caller
if [[ $# -eq 1 ]]; then
dir=$(dirname $1)
file=$(basename $1)
filepath=$1
fi
# Find the parent filename
if lookup_parent $filepath; then
parentfilepath=$parent/$parentfile
parentsdot=$parent/$(dirname $parentfile)/SCCS/s.$(basename \
$parentfile)
if [[ -f $parentfilepath && -s $parentsdot ]]; then
# found
return 0
else
fail "Error: located parent filepath $parentfilepath"\
"but file does not exist or SCCS file is empty."
fi
fi
# wasn't found
return 1
}
get_pb_output() {
# Get output of putback -n (useful for parsing to find diffs between
# workspaces). Creates $wxtmp/putback.err and $wxtmp/putback.out
typeset -i rc=0
typeset origdir=$(pwd)
# clean up if interrupted.
trap "rm $wxtmp/putback.out;exit 1" HUP INT QUIT TERM
cat <<-EOF
Doing a '$PUTBACK -n $*' to find diffs between workspaces.
Please be patient as this can take several minutes.
EOF
cd $workspace
$PUTBACK -n $* 2>$wxtmp/putback.err >$wxtmp/putback.out
rc=$?
# Note a blocked putback returns a 2 but is not a problem.
if [[ $rc -ne 0 && $rc -ne 2 ]]; then
rm $wxtmp/putback.out
fail "Error, $PUTBACK -n $* failed. See $wxtmp/putback.err"\
"for details."
fi
trap - HUP INT QUIT TERM
cd $origdir
return 0
}
wx_usage() {
version
cat << EOF
See <http://onnv.eng/wx.html> for usage tips.
Usage: $ME command [-D] [args]
-D turn on debugging for any command (output to stderr)
===================== Initialization and Update Commands ====================
$ME init [-f(t|q|n) [-s]] [src-root-dir]
initialize workspace for $ME usage
-f(t|q|n): non-interactive mode of update. Use this
to keep init from asking questions.
-ft: thorough update (update both active and
renamed lists with all diffs between parent
and current workspace).
-fq: quick update (update active list with files
currently checked out in current workspace).
-fn: no update (just create empty active and
renamed lists if they don't exist already).
-s: keep active list sorted by default. Must
follow a -f(t|q|n) flag.
src-root-dir: optional path relative to top of
workspace where wx will search for files.
Use "." to set src-root to top of
workspace. Default is usr.
$ME update [-q|-r] [-s]
Update the active and renamed file lists by
appending names of all files that have been
checked out, changed, created or renamed as
compared to the parent workspace. This is the
most accurate way of updating but it is slow.
All files in the workspace must be under SCCS
control in order for update to find them. Note,
this operation can be sped up in some cases by
setting the PUTBACK env. variable to use
"cm_env -g -o putback". (See
http://webhome.holland.sun.com/casper/ for more
info about the turbo def.dir.flp tool).
-q: quick update (only updates active list with
files currently checked out in workspace). This
is faster but will not find renames or files that
have been checked-in/delget'ed.
-r: only update the renamed list. Does not update
the active list.
-s: sort the active list.
======================== Information Commands ===========================
$ME list [-r|-p|-w] list active files (the ones you are working on)
-r: list only renamed active files.
-p: output list of both active and renamed files
suitable for input to putback.
-w: output list of both active and renamed files
suitable for input to webrev (see $ME webrev
subcommand below).
$ME active alias for list
$ME pblist alias for list -p (see above).
$ME renamed [-a|-d|-p]
list locally renamed files. The output format is:
"new_name previous_name". Note, deleted files are
a special case of rename.
-a: list only renamed active files (same as list -r)
-d: list only deleted files
-p: show "new_name parent_name" (Note, parent_name
may not be the same as previous_name)
$ME new [-t] List new active files (files that exist in child only)
Note, should be run before reedit (see reedit below).
-t: thorough, does not use new cache (slower but more
accurate if new cache isn't current).
$ME out find all checked-out files in workspace
$ME info [file ...] show all info about active files
$ME diffs [file ...]
show sccs diffs for files (current vs previous
local version). Will show diffs for all active
files if no files given on command line. Will
use WXDIFFCMD environment variable if set. Hint,
try: export WXDIFFCMD="diff -bwU5"
$ME tdiffs [file ...]
Similar to diffs but new files are also displayed.
New files are those listed by '$ME new'.
$ME pdiffs [file ...] show diffs against parent files
Will show diffs between local file and it's
parent for all active files if no files given on
command line. Will use WXDIFFCMD environment
variable if set.
$ME tpdiffs [file ...] show diffs against parent files
Similar to pdiffs but new files are also displayed.
A file is considered new if it does not exist in
the parent.
$ME prt [-y] show sccs history for all active files
$ME comments display check-in comments for active files
$ME bugs [-u] display all bugids in check-in comments
$ME arcs [-u] display all ARC cases in check-in comments
$ME pbcom [-v] [-u] [-N] display summarized comments suitable for putback
Default is to display only bugs and arc cases. Will
display warnings about non-bug comments to stderr.
-v: display all comments verbatim including non-bug/arc
-u: prevent sorting, order determined by active list
-N: don't check bug synopsis against bug database
======================== File Manipulation Commands ======================
$ME edit [-s] [file ...]
check out either file(s) on command line or
all active files if no file args.
(Updates the active list.)
-s: silent, less sccs diagnostic output. This is
true for the other commands that accept the
-s flag.
$ME checkout Alias for edit command.
$ME co Alias for edit command.
$ME unedit [-s][-f] [file ...]
Returns file(s) to state prior to edit/checkout
Note, files will be unlocked and any changes made
when file was last checked out will be lost.
Unedit all active files if no files listed on
command line. Removes active list entry if there
are no diffs between local and parent file.
(Updates active list)
-f: force unedit, non-interactive. Will backup
if wx files newer than last backup.
$ME uncheckout Alias for unedit command.
$ME unco Alias for unedit command.
$ME delget [-(c|C) comment_file][-s][-f] [file ...]
Check in all active files or files on command
line. Check in comments will be those in active
file. See '$ME comments' for more info.
-c comment_file: use comment(s) in specified comment
file when checking in file(s). Note,
each comment should be on new line,
blank lines not allowed. Existing
comments in active list will be
replaced by contents of comment_file.
-C comment_file: Similar to -c but comments are
appended to current active list
comments.
-f: force checkin, no checks, non-interactive.
Use this if your sure the files okay to checkin
otherwise this command will check for
keyword problems. Will backup if wx files
newer than last backup.
NOTE: use redelget to reset new file's version to 1.1.
$ME checkin Alias for delget command.
$ME ci Alias for delget command.
$ME create [-(c|C) comment_file] [-f] [-o] file [file ...]
Creates one or more files in the workspace.
(Updates active list)
-(c|C) comment_file: see delget
-f: force create regardless of warnings,
(non-interactive).
-o: also check out file for further editing.
$ME uncreate [-f] [file ...]
Undoes the create of a new file. The file's
active list entry, its SCCS history and the
entry in the workspace nametable will be removed
but the file will stay in the workspace.
Will uncreate all new files in active list if
no file argument is specified.
-f: force uncreate, non-interactive. Will backup
if wx files newer than last backup.
$ME get [-k][-r #][-p] [file ...]
Get a copy of all active files or files on command
line. By default this is a read only version of
the file.
-r #: get specified version #
-p: output to stdout
-k: don't expand the sccs ID string
$ME extract Alias for get command.
$ME reedit [-m] [-s] [file ...]
Collapse the sccs delta (file history) such that
all changes made to the file in the current
workspace are now in one delta. If no files are
given on command line then all the active files
are processed. The files are left in a checked
out state so you can make further changes if a
resolve to make all your changes look like a
single delta. This eliminates the uninteresting
leaf deltas that arise from resolving conflicts,
so your putbacks do not contain a bunch of noise
about every bringover/resolve you did in the
interim. Accepts the same compression flags as
$ME backup. If [file ...] given, wx only
reedits files passed on command line. This adds
files to active list if not already there.
NOTE: reedit is appropriate for leaf workspaces
ONLY -- applying reedit to an interior-node
workspace would delete all childrens comments
and confuse Teamware tools in general.
NOTE: if files are listed as new that are not
then DO NOT use the reedit as it will destroy
the file history.
NOTE: if a file is new reedit will leave the
file checked out so in order to keep the delta
version at 1.1 redelget must be used for
checkin.
-m: only reedit files that have more that one
delta as compared to parent file. New files
will be recreated with comment found in
active list.
-s: silent checkin
$ME recheckout Alias for reedit command.
$ME reco Alias for reedit command.
$ME redelget [-m][-s] [file ...]
Similar to reedit but the file is checked in
when the command is done. This is the command to
use to collapse new files to their initial
1.1 delta (will assign comment in active list).
$ME recheckin Alias for redelget command.
$ME reci Alias for redelget command.
$ME delete [-f] [file ...]
Delete one or more files from the workspace.
Will delete all files in active list if no file
args. Note, for files brought over from parent,
this command actually moves the file under the
deleted_files/ subdir so it can be recovered.
For new files this command can remove the file
and file history completely.
(Updates active list if file is in there.)
-f : force delete regardless of warnings
(non-interactive)
Warning, this will completely remove new
files from the workspace. Will backup
if wx files newer than last backup.
$ME rm Alias for delete command.
$ME mv file newfile
Rename file to newfile
(Updates active list with new file name)
$ME mv file newdir
$ME mv dir newdir
Renames dir or file to newdir. If newdir exists
then dir will be subdir under newdir. Note,
this renames all files in dir and can take a
while if there are a lot of files affected by
the rename. (Updates active list)
$ME reset [-f] [file ...]
Resets file contents and history to that of
parent file. If the file was renamed locally it
will be renamed to that of the parent. It does not
work on new files (see uncreate or delete).
NOTE: use with care. If something goes wrong,
do a wx restore from the last backup and copy
wx/tmp/nametable.orig to Codemgr_wsdata/nametable.
======================== Teamware Commands ======================
$ME putback [-v][-f][-N][Teamware putback flags, see below][file ...]
Use Teamware putback command to putback either
file(s) specified or *all* active and renamed
files if no file(s) specified. Will use pbcom
output as the putback comments.
-f: force non-interactive mode (will not prompt)
-v: pass comments verbatim to putback(see pbcom)
-N: don't check bug synopsis against bug database
Accepts -n, -p pws, -q putback flags ('man putback'
for more info).
$ME pb alias for putback.
$ME resolve [Teamware resolve args]
resolve bringover conflicts and reedit merged
files. See 'man resolve' for args.
======================== ON Rules checking Commands ======================
$ME cstyle run cstyle over all active .c and .h files
skips files in wx/cstyle.NOT
$ME jstyle run jstyle over all active .java files
skips files in wx/jstyle.NOT
$ME hdrchk run 'hdrchk -a' over all active .h files
skips files in wx/hdrchk.NOT
$ME makestyle run makestyle over all active Makefiles
$ME keywords run keywords over all active files
skips files in wx/keywords.NOT
$ME copyright make sure there is a correct copyright message
that contains the current year
skips files in wx/copyright.NOT
$ME cddlchk make sure there is a current CDDL block in
active files
skips files in wx/cddlchk.NOT
$ME rmdelchk make sure sccs rmdel was not run on active files
(This causes Teamware problems.)
$ME deltachk make sure only 1 sccs delta in active files
(more than 1 breaks gate putback rules unless > 1
bug in putback.)
$ME comchk make sure comments are okay
$ME rtichk make sure RTI is approved for bugs/rfe's listed
in active list comments. Will skip rtichk if
wx/rtichk.NOT exists.
$ME outchk warn if there are files checked out that aren't in
active list.
$ME nits [file ...]
nits checking. Run cstyle, jstyle, hdrchk, copyright,
cddlchk, and keywords over files to which they are
applicable (makestyle is not currently run
because it seems to be quite broken -- more
noise than data). This is a subset of pbchk checks
suitable for checking files during development.
Use pbchk before doing the final putback.
Will run checks on all active files if no file args.
Will skip checks for files listed in wx/nits.NOT.
$ME pbchk [file ...]
putback check. Run cstyle, jstyle, hdrchk, copyright,
cddlchk, keywords, rmdelchk, deltachk, comchk, rtichk
and outchk over files to which they are
applicable (makestyle is not currently run
because it seems to be quite broken -- more
noise than data). Good command to run before
doing a putback.
Will run checks on all active files if no file args.
Will skip checks for files listed in wx/pbchk.NOT.
======================== Code Review Commands ======================
$ME webrev [webrev-args]
generate webrev for active and renamed/deleted files.
Note, uses comments in the active list. This is the
preferred way of reviewing code. Arguments to webrev
may also be specified.
Will skip files listed in wx/webrev.NOT
$ME codereview [-N] [codereview options]
generate environmentally friendly codereview diffs
for all active files. -N indicates that delta
comments should not be included.
$ME fullreview [-N] [codereview options]
generate full codereview diffs for all active files.
-N indicates that delta comments should not be
included.
======================== Backup and Restore Commands ======================
$ME backup [-i|-n|-z|-b|-t]
make backup copies of all active and renamed files.
-i: info about backups (backup dir and contents)
-n: no compression
-z: use gzip, faster than bzip2 but less compression.
-b: use bzip2, slower but better compression.
-t: backup if wx files are newer than last backup.
Defaults to the compression of the previous backup.
$ME bu Alias for backup command.
$ME restore [-f] [backup_dir]
restore a backup in a workspace (restores both
active files and performs file renames). A path
to the directory containing the backup to
restore from can be optionally specified.
-f: non-interactive. Will restore from last backup.
======================== Misc Commands ============================
$ME apply <cmd> apply cmd to all active files; for example,
"$ME apply cat" cats every file
$ME eval <cmd> like apply, but more general. In fact,
"$ME apply cmd" is implemented internally as
"$ME eval 'cmd \$file'". When using eval,
you can refer to \$dir, \$file, \$filepath,
\$parent, and \$workspace. For example:
$ME eval 'echo \$dir; sccs prt \$file | more'
will show the sccs history for each active file,
preceded by its directory.
$ME grep search all active files for pattern; equivalent to
"$ME eval 'echo \$filepath; grep pattern \$file'"
$ME egrep see $ME grep
$ME sed see $ME grep
$ME nawk see $ME grep
$ME dir echo the $ME directory path (\$workspace/$ME)
$ME e <file> edit the named $ME control file, e.g. "$ME e active".
The editor is \$EDITOR if set, else vi.
$ME ea shorthand for "$ME e active" (edit active list).
Note, the format for each entry in the active
list is:
filepath
<empty line> # no spaces allowed
one or more comment lines # no blank lines between.
<empty line> # no spaces allowed, ends the entry.
In general, it is best to only edit the active
list to update comments. Use the other $ME
commands like edit or create to update the
active list when possible.
$ME ws <file> cat the named workspace control file, i.e.
\$workspace/Codemgr_wsdata/file
$ME args shorthand for "$ME ws args"
$ME access shorthand for "$ME ws access_control"
$ME help print this usage message
$ME version print current version of this program
EOF
exit 1
}
list_putback() {
(wx_active; list_renamed -n)|nawk '!seen[$0]++'
}
list_new() {
# list new files (not found in parent ws)
typeset new
if [[ $1 == '-t' ]]; then
wx_active|
while read new; do
# thorough, skip new cache
if ! lookup_parent $new; then
# no parent, new file
echo "$new"
fi
done
else
while read new; do
# use new cache
if ! lookup_parent $new; then
# no parent, new file
echo "$new"
fi
done < $wxdir/new
fi
}
list_renamed() {
typeset active current old
if [[ $# -eq 0 ]]; then
cat $wxdir/renamed
elif [[ $1 == '-d' ]]; then
# Only list only deleted file renames
grep '^deleted_files/' $wxdir/renamed
elif [[ $1 == '-n' ]]; then
# Only list only current filenames
cut -f1 -d' ' $wxdir/renamed
elif [[ $1 == '-p' ]]; then
# list parent for current instead of local previous name
while read current old; do
if lookup_parent $current; then
print "$current $parentfile"
else
ring_bell
print -u2 "Warning: cannot find parent file"\
"for $current"
fi
done < $wxdir/renamed
elif [[ $1 == '-a' ]]; then
# Just list active renamed files
for active in $(wx_active); do
grep "^$(escape_re $active) " $wxdir/renamed
done
elif [[ $1 == '-r' ]]; then
wx_active > $wxtmp/alist || fail "Error: cannot create $wxtmp/alist"
# Just list non-active renamed files (just current name)
while read current old; do
grep -q "^$(escape_re $current)$" $wxtmp/alist ||
echo $current
done < $wxdir/renamed
rm -f $wxtmp/alist
else
fail "Invalid flag $i. Run 'wx help' for info."
fi
}
list_webrev() {
# Output a list of active and renamed files suitable for webrev
for filepath in $( (wx_active; list_renamed -n)|nawk '!seen[$0]++'); do
if renamed; then
echo "$filepath $parentfile"
else
echo "$filepath"
fi
done
}
wx_webrev() {
typeset origdir=$PWD
cd $workspace
# skip files listed in .NOT files
cat -s $wxdir/$command.NOT >$wxtmp/NOT
( # do the loops in a subshell so there is only one file open
for filepath in $(wx_active); do
if grep -q "^$(escape_re $filepath)$" $wxtmp/NOT; then
print -u2 "$filepath (skipping)"
continue
fi
if renamed; then
echo "$filepath $parentfile"
else
echo "$filepath"
fi
echo "\n$(wx_show_comment)\n"
done
# Do non-active renamed files
for filepath in $(list_renamed -r); do
if grep -q "^$(escape_re $filepath)$" $wxtmp/NOT; then
print -u2 "renamed $filepath (skipping)"
continue
fi
lookup_parent $filepath ||
fail "Error: cannot find parent for $filepath."
if [[ $filepath != $parentfile ]]; then
echo "$filepath $parentfile"
# output empty line, comment, empty line
echo "\nRenamed only (webrev comment generated by "\
"$ME, not an sccs comment)\n"
else
echo "$filepath"
echo "\nWarning, file in renamed list but has same "\
"name as parent (not an sccs comment)\n"
fi
done
# End of subshell
) > $wxdir/tmp/webrev.list
# Note that the file list must come last.
${WXWEBREV:-webrev} -w "$@" $(basename $wxdir)/tmp/webrev.list
cd $origdir
}
#
# list all active files
#
wx_active() {
# do not print hash by default
typeset rc hash=0
case $1 in
# list only renamed active files
-r) list_renamed -a; return 0;;
# list suitable for putback (both active and renamed)
-p) list_putback; return 0;;
# list suitable for webrev (both active and renamed)
-w) list_webrev; return 0;;
-*) fail "Invalid flag $1. See 'wx help' for more info.";;
esac
if [[ ! -r $wxdir/active ]]; then
fail "Error: cannot read $wxdir/active"
fi
nawk '
{
# skip blank lines
while (NF == 0) {
if (getline == 0)
next;
}
if (NF > 0){
# print the active filepath
print $1;
getline;
}
# skip blank lines
while (NF == 0) {
if (getline == 0){
# Error, corrupt active list (missing comment)
exit 1
}
}
# skip comment
while (NF > 0) {
if (getline == 0){
# Error, blank line after comment missing
exit 2
}
}
}' $wxdir/active
rc=$?
if [[ $rc -eq 1 ]];then
fail "Corrupt active list (missing comment)."
elif [[ $rc -eq 2 ]];then
fail "Corrupt active list (blank line needed after comment)."
fi
}
#
# show the comment for $filepath
#
wx_show_comment() {
if [[ -f $wxdir/active ]]; then
nawk '
{
filename=$1
getline
while (getline) {
if (length == 0)
next
if (filename == target) {
if ($0 == "NO_COMMENT") {
found = 0
exit 1
}
found = 1
print
}
}
}
END {
if (found == 0)
print "NO_COMMENT"
exit 1 - found
}' target=$filepath $wxdir/active
return $?
else
echo "NO_COMMENT"
fi
}
bugdb_lookup_monaco() {
typeset buglist=$1
typeset monaco=/net/monaco.sfbay/export/bin/monaco
if [[ ! -x $monaco ]]; then
return 1
fi
$monaco -text <<-EOF
set What =
substr(cr.cr_number, 1, 7), synopsis
set Which =
cr.cr_number in ($buglist)
set FinalClauses =
order by cr.cr_number
do query/CR
EOF
}
bugdb_compare() {
nawk -v bugdb=$1 -v active=$2 -f - <<-"EOF"
BEGIN {
file = bugdb
while (getline < file) {
synbugdb[$1] = substr($0, length($1) + 1)
}
file = active
while (getline < file) {
synactive = substr($0, length($1) + 1)
# If the synopsis doesn't match the bug database
# and the synopsis isn't what's in the database
# with " (something)" appended, spew a warning.
if (!($1 in synbugdb)) {
print "Bug " $1 " is not in the database"
} else if (synbugdb[$1] != synactive &&
!(index(synactive, synbugdb[$1]) == 1 &&
substr(synactive, length(synbugdb[$1])) ~ \
/ \([^)]*\)$/)) {
print "Synopsis of " $1 " is wrong:"
print " should be:" synbugdb[$1]
print " is:" synactive
}
}
}
EOF
}
#
# Summarize all comments listing, in order:
# - free-form comments
# - ARC case comments
# - Bug comments
#
# -a will suppress ARC case comments
# -b will suppress bug comments
# -n will do pbchk processing (give all warnings, no error exit)
# -o will suppress free-form (other) comments
# -p will do pbcom checking and exit if it finds problems unless -v is given
# -u will prevent sorting of the ARC case comments and bug comments
# -v will output all comments verbatim (no sorting)
# -N will prevent bug lookup, which may take a while.
#
# Note, be careful when modifying this function as sometimes the output
# should go to stdout, as in the case of being called via pbchk and
# sometimes the output should go to stderr. Think about this when
# making changes in here.
#
wx_summary() {
typeset i comment arc bug bugnospc bugid buglist synopsis \
show_arcs=true \
show_bugs=true \
show_others=true \
verbatim=false \
pbchk=false \
pbcom=false \
cmd=sort \
nolookup=false
while getopts :abnopuvN i; do
case $i in
a) show_arcs=false;;
b) show_bugs=false;;
n) pbchk=true;;
o) show_others=false;;
p) pbcom=true;;
v) verbatim=true;;
u) cmd=cat;;
N) nolookup=true;;
*) fail "Invalid flag -$OPTARG. See 'wx help' for more"\
"info.";;
esac
done
# Store all the comments in a tmp file
for filepath in $file_list; do
wx_show_comment
done | nawk '!seen[$0]++' > $wxtmp/comments
if grep -q "^NO_COMMENT$" $wxtmp/comments; then
print -u2 "Warning, found NO_COMMENT. Run '$ME ea' to edit the "\
"comments."
if $pbcom; then
# Don't want to output anything to stdout for a pbcom
# if there is an error.
return 1
fi
fi
if $pbcom && $verbatim; then
# All comments output verbatim. Note, is hacky because
# of the wx_summary interface. pbcom calls wx_summary
# with -po assuming other comments shouldn't be output.
show_others=true
fi
# Note, hard tab in the arc R.E.
arc='[A-Z][A-Z]*ARC[/ ][12][0-9][0-9][0-9]/[0-9][0-9][0-9][^0-9]'
# bug ID must followed by single space
bug='[0-9][0-9][0-9][0-9][0-9][0-9][0-9] '
bugnospc='[0-9][0-9][0-9][0-9][0-9][0-9][0-9][^ ]'
if $show_arcs; then
# Note must use /usr/bin/sort.
if ! egrep "^$arc" $wxtmp/comments |
sed 's#\([A-Z][A-Z]*ARC\)[/ ]#\1 #' | sort |
/usr/bin/sort -cu -k 2,2 2>$wxtmp/error >/dev/null
then
if $pbchk; then
print -n "Inconsistent ARC summaries for: "
sed 's#^[^A-Z]*\('"${arc}"'\).*#\1#' \
$wxtmp/error
else
print -nu2 "Inconsistent ARC summaries for: "
sed 's#^[^A-Z]*\('"${arc}"'\).*#\1#' \
$wxtmp/error >&2
fi
if $pbcom && ! $verbatim; then
# Don't want to output anything to
# stdout for a pbcom if there is an
# error.
return 1
fi
fi
fi
if $show_bugs; then
# Treating bug comments with "(nit comment)" at the end as the
# same as the original bug hence the sed and nawk below
# Note hard tabs in sed arg.
# Must use /usr/bin/sort.
if ! grep "^$bug" $wxtmp/comments |sort|
sed 's/[ ][ ]*([^)]*) *$//' |
nawk '!seen[$0]++'|
/usr/bin/sort -cnu 2>$wxtmp/error >/dev/null; then
if $pbchk; then
print -n "Inconsistent bug summaries for: "
sed 's#^[^0-9]*\('"${bug}"'\).*#\1#' \
$wxtmp/error
else
print -nu2 "Inconsistent bug summaries for: "
sed 's#^[^0-9]*\('"${bug}"'\).*#\1#' \
$wxtmp/error >&2
fi
if $pbcom && ! $verbatim; then
# Don't want to output anything to
# stdout for a pbcom if there is an
# error.
return 1
fi
fi
# Compare bug synopsis in active comments with the bug database.
# If we've been passed -N, then we just never set buglist, thus
# skipping the lookup.
if ! $nolookup; then
grep "^$bug" $wxtmp/comments | sort > $wxtmp/buglist.active
cat $wxtmp/buglist.active | while read bugid synopsis; do
buglist=$buglist,$bugid
done
buglist=${buglist#,}
else
if $pbchk; then
print "Not performing bug synopsis check (be careful)"
else
print -u2 "Not performing bug synopsis check (be careful)"
fi
fi
if [[ -n $buglist ]]; then
bugdb_lookup_monaco $buglist > $wxtmp/buglist.bugdb
if [[ -s $wxtmp/buglist.bugdb && $? -eq 0 ]]; then
bugdb_compare $wxtmp/buglist.bugdb \
$wxtmp/buglist.active > $wxtmp/error
if [[ -s $wxtmp/error ]]; then
if $pbchk; then
cat $wxtmp/error
else
cat $wxtmp/error >&2
fi
if $pbcom && ! $verbatim; then
# Don't want to output anything
# to stdout for a pbcom if there
# is an error.
return 1
fi
fi
else
if $pbchk; then
print "Could not perform bug synopsis check"
else
print -u2 "Could not perform bug synopsis check"
if $pbcom; then
print -u2 "Use -N to skip bug synopsis check (be careful)"
fi
fi
if $pbcom && ! $verbatim; then
# Don't want to output anything
# to stdout for a pbcom if there
# is an error.
return 1
fi
fi
fi
if egrep "^$bugnospc" $wxtmp/comments >$wxtmp/error; then
# must have single space following bug ID
if $pbchk; then
print "\nThese bugs are missing single space following the bug ID"
print "(output prefaced by active file line number ':'):"
while read comment
do
grep -n "^$comment" $wxdir/active
done < $wxtmp/error
else
print -u2 "\nThese bugs are missing single space following the bug ID"
print -u2 "(output prefaced by active file line number ':'):"
while read comment
do
grep -n "^$comment" $wxdir/active >&2
done < $wxtmp/error
fi
if $pbcom && ! $verbatim; then
# Don't want to output anything to
# stdout for a pbcom if there is an
# error.
return 1
fi
fi
fi
# Create warning for pbchk or pbcom.
if $pbchk || ($pbcom && ! $verbatim) &&
egrep -v "^($bug|$bugnospc|$arc|NO_COMMENT$)" $wxtmp/comments\
> $wxtmp/other_comments; then
cat <<-EOF
Warning, the following comments are found in your active list
that are neither bug or arc cases:
EOF
cat $wxtmp/other_comments
print -- "\n---- End of active list comment warnings ----"
fi > $wxtmp/comment_warning
if [[ -s $wxtmp/comment_warning ]]; then
if $pbchk; then
# output to stdout, don't exist in case there are more
# warnings.
cat $wxtmp/comment_warning
elif $pbcom && ! $verbatim ; then
# Don't want to output anything to stdout for a pbcom
# if there is an error.
cat $wxtmp/comment_warning >&2
return 1
fi
fi
if $pbchk; then
cd $workspace
# See if sccs delta comment is the same as active list comment
for filepath in $file_list; do
# extract most recent delta comment
sccs prs -d ':C:' $filepath | sort > $wxtmp/com1 ||
fail "sccs prs -d ':C:' $filepath failed."
# Add blank line to active comments so following cmp will
# work properly.
(wx_show_comment; print) | sort > $wxtmp/com2
if ! cmp -s $wxtmp/com1 $wxtmp/com2; then
print "\n$filepath"
print "Warning: current sccs comment does not"\
"match active list comment"
print "(< sccs comment, > active list comment):"
diff $wxtmp/com1 $wxtmp/com2
fi
done
# Just output warnings for pbchk
return 0
fi
if $show_others; then
if ! $verbatim; then
# The non-verbatim check should have produced the
# other_comments file.
cat $wxtmp/other_comments| $cmd
else
# just output comments verbatim then return
cat $wxtmp/comments
return 0
fi
fi
if $show_arcs; then
egrep "^$arc" $wxtmp/comments | $cmd
fi
if $show_bugs; then
egrep "^$bug" $wxtmp/comments | $cmd
fi
return 0
}
update_renamed_file() {
# Try to add a entry to the renamed list. Note, this stores the new
# name and previous name, not the parent name as this is more useful in
# detecting cyclic renames.
# ofp: old filepath, nfp: new filepath
typeset ofp=$1 nfp=$2
# remove old and new entries from renamed
egrep -v "^($(escape_re $ofp)|$(escape_re $nfp)) " $wxdir/renamed \
>$wxtmp/renamed
[[ ! -f $wxtmp/renamed ]] && fail "Error: cannot create $wxtmp/renamed"
mv -f $wxtmp/renamed $wxdir/renamed || \
fail "Error: cannot create $wxdir/renamed."
# remove old entries from local nt cache
remove_local_nt_entry $ofp
# Do not update renamed list if the filepath is the same as
# the parent or the file is new.
if lookup_parent $nfp; then
if [[ $parentfile != $nfp ]]; then
print "$nfp $ofp" >> $wxdir/renamed || \
fail "Error: cannot append $wxdir/renamed."
[[ $ACTSORT == sort ]] && do_renamed_sort=true
fi
fi
return 0
}
update_renamed_dir() {
typeset append pb_files new orig
typeset -i rc
if [[ $# -eq 0 ]]; then
# No args so we need to create the renamed list from
# the source root.
append=false
if [ -r $wxdir/srcroot_dir ]; then
pb_files=$(cat $wxdir/srcroot_dir)
else
pb_files=$DEFAULT_SRCDIR
fi
else
# Assuming one or more filepaths as args
append=true
pb_files="$*"
fi
echo "Updating $ME renamed list... this may take several minutes."
# Get output of putback -n to detect renames elsewhere in
# this script.
get_pb_output $pb_files
nawk '
/^rename from:/{orig_file=$3}
$1 == "to:" {print $2 " " orig_file}' \
$wxtmp/putback.out >$wxtmp/pb_renames || \
fail "Error, creation of $wxtmp/pb_renames failed."
cp $wxdir/renamed $wxdir/renamed.old ||
fail "Error: cannot create $wxdir/renamed.old."
if $append; then
nawk '!seen[$0]++' $wxtmp/pb_renames $wxdir/renamed \
> $wxtmp/renamed || \
fail "Error: cannot create $wxtmp/renamed."
mv -f $wxtmp/renamed $wxdir/renamed || \
fail "Error: cannot create $wxdir/renamed."
else
mv -f $wxtmp/pb_renames $wxdir/renamed ||
fail "Error: cannot create $wxdir/renamed."
fi
[[ $ACTSORT == sort ]] && do_renamed_sort=true
}
# returns 0 if a pattern in patternfile matches input path arg
pathcheck() {
typeset pattern path=$1 patternfile=$2
while read pattern; do
if [[ $path == $pattern ]]; then
return 0 # pattern matched path
fi
done < $patternfile
return 1 # file path not matched by pattern
}
#
# Evaluate a command for all listed files. This is the basic building
# block for most wx functionality.
#
wx_eval() {
typeset -i changedir=1
if [[ $# -gt 1 && "$1" == "-r" ]]; then
changedir=0
shift
fi
pre_eval=$*
# skip files listed in .NOT files
cat -s $wxdir/$command.NOT >$wxtmp/NOT
for filepath in $file_list; do
if pathcheck $filepath $wxtmp/NOT; then
print "$filepath (skipping)"
else
cd $workspace
dir=`dirname $filepath`
file=`basename $filepath`
[[ $changedir -eq 1 ]] && cd $dir
eval $pre_eval
fi
done
}
#
# Initialize a workspace for wx.
#
wx_init() {
typeset srcroot_dir force=false
# check that srcroot is relative to top of workspace
if cd $workspace/$1; then
# normalize the srcroot dir for test below
srcroot_dir=$(/bin/pwd)
srcroot_dir="${srcroot_dir#$workspace/}"
if [[ $srcroot_dir == $workspace ]]; then
# Special case need to set srcroot_dir to
# a relative path but we're at the top of the
# workspace.
srcroot_dir="."
fi
else
fail "Source root '$1' does not exist in workspace"\
"($workspace)."
fi
if [ -d $wxtmp ]; then
if [[ $2 != -f[nqt] ]]; then
echo "This workspace has already been initialized."
ok_to_proceed 'Do you really want to re-initialize?'
fi
else
mkdir -p $wxtmp
fi
#
# Make sure to save $srcroot_dir as a path relative to the workspace
# root; an absolute path would break if the workspace name changed.
#
rm -f $wxdir/srcroot_dir
echo $srcroot_dir >$wxdir/srcroot_dir
backup_dir=$HOME/$ME.backup/$workspace_basename
[[ -d $backup_dir ]] || mkdir -p $backup_dir ||
fail "mkdir -p $backup_dir failed."
cd $backup_dir
rm -f $wxdir/backup_dir
pwd >$wxdir/backup_dir || fail "Creation of $wxdir/backup_dir failed."
touch $wxdir/renamed
touch $wxdir/active
touch $wxdir/new
touch $wxdir/local_nametable
if [[ -z "$2" ]]; then
# Interactive mode
cat << EOF
Pick one of the following update methods:
1) Thorough: Detect any differences between the current workspace
and its parent and update the active, new and renamed lists. Use
this in workspaces where files have been renamed or deleted or
there are files that are different from the parent that are not
checked out. Note, files must be under SCCS control in order for
this method to compare them to the parent workspace.
2) Quick: Only update the active list with files that are currently
checked out. Will not update the renamed list.
3) None: Use this on workspaces where there are no changes between
the workspace and its parent. This is very quick but will not
update the active, new or renamed lists.
EOF
read answer?"Which update method? [1|2|3]: "
case $answer in
1) wx_update;;
2) wx_update -q;;
3) ;;
*) fail "Bad answer: ${answer}. Rerun init command"\
"again";;
esac
yesno "Keep active list sorted by default?"
if [[ "$answer" == 'yes' ]]; then
print "true" > $wxdir/sort_active
else
print "false" > $wxdir/sort_active
fi
else
# non-interactive mode
case $2 in
# forced thorough update
-ft) wx_update; force=true;;
# forced quick update
-fq) wx_update -q; force=true;;
# forced no update
-fn) force=true;;
# invalid arg
-*) fail "$ME $command: unrecognized argument";;
esac
if [[ $3 == -s ]]; then
print "true" > $wxdir/sort_active
else
print "false" > $wxdir/sort_active
fi
fi
print
if [ -s $wxdir/active ]; then
basedir=$workspace
file_list=`wx_active`
if $force; then
# only backup if necessary
print "Will backup wx and active files if necessary"
wx_backup -t
else
print "Making backup copies of all wx and active files"
wx_backup
fi
else
echo "Active list empty, not doing backup."
echo
fi
echo "$ME initialization complete"
}
#
# Find all checked out files
#
wx_checked_out() {
typeset origdir=$(pwd)
cd $workspace
x=$(ls -t $wsdata/nametable $wxdir/sccs_dirs 2>/dev/null)
if [[ -z $x || "`basename $x`" == nametable ]]; then
if [ -f $wxdir/srcroot_dir ]; then
srcroot_dir=`cat $wxdir/srcroot_dir`
else
srcroot_dir=$DEFAULT_SRCDIR
fi
print -u2 "Workspace nametable changed: sccs_dirs out of date"
print -u2 "Updating $wxdir/sccs_dirs...this may take a few minutes.\n"
rm -f $wxdir/sccs_dirs
find $srcroot_dir -name SCCS -print | sort >$wxdir/sccs_dirs
fi
cd $workspace
rm -f $wxtmp/checked_out
# Note if srcroot_dir = . this must be removed from the front of the
# filepaths.
echo $(sed -e 's,$,/p.*,' $wxdir/sccs_dirs) | \
tr \\040 \\012 | \
grep -v '*' | \
sed -e 's,SCCS/p.,,' |sed -e 's,^\./,,' >$wxtmp/checked_out
cd $origdir
}
deal_ws_renames() {
# See if any active/renamed files were renamed externally
# (perhaps by bringover?) and try to rename the active entry
# filepath.
typeset fp newfp renamed localfile hash1 hash2 hash3 hash4 \
notrenamed_list origdir=$(pwd)
cd $workspace
list_putback |\
while read fp; do
if [[ ! -f $fp ]]; then
# file not found, suspect rename.
# using renamed for error checking.
renamed=false
# search cached local nt to find old hash info
grep "^$(escape_re $fp) " $wxdir/local_nametable |\
while read localfile hash1 hash2 hash3 hash4; do
# find new filepath
newfp=$(fgrep " $hash1 $hash2 $hash3 $hash4"\
$wsdata/nametable|cut -f1 -d' ')
[[ -z $newfp ]] && continue
if [[ $newfp != $fp ]]; then
update_renamed_file $fp $newfp
rename_active_entry $fp $newfp
echo "\nRenamed active file"\
"$fp to $newfp"
renamed=true
break
fi
done
if ! $renamed; then
if [[ -z $notrenamed_list ]]; then
notrenamed_list="$fp"
else
notrenamed_list="$notrenamed_list\n$fp"
fi
fi
fi
done
if [[ -n $notrenamed_list ]]; then
ring_bell
cat <<-EOF
Warning, active file(s):
$(echo $notrenamed_list)
not found and cannot be renamed. Use "$ME ea" to edit the active list to
remove these entries if they do not exist in this workspace.
EOF
fi
cd $origdir
}
#
# Old style update the active file list (by appending all checked out files).
# This is what the original wx update did.
#
wx_update_quick() {
# Sort active if requested.
[[ "$1" == "-s" ]] && ACTSORT=sort
wx_checked_out
cd $wxdir
rm -f tmp/files.old tmp/files.new active.new
wx_active >tmp/files.old || fail "Error: cannot create $wxtmp/files.old"
# sed has a hard tab, used to delete lines containing only whitespace
sed '/^[ ]*$/d' tmp/files.old tmp/checked_out|
nawk '!seen[$0]++' | $ACTSORT > tmp/files.new ||
fail "Error: cannot create $wxtmp/files.new"
cp -f new new.old || fail "Error: cannot create new.old."
while read filepath ; do
add_local_nt_entry $filepath
(echo "$filepath"; echo; wx_show_comment; echo)
done < tmp/files.new > active.new ||
fail "Error: cannot create $wxdir/active.new"
mv -f active active.old
mv -f active.new active
echo
echo "New active file list:"
echo
cat tmp/files.new
echo
echo "Diffs from previous active file list:"
echo
${WXDIFFCMD:-diff} tmp/files.old tmp/files.new
echo "End active diffs =========================="
# Do new file processing after active list is updated.
# Note, the parent nt read check below is hackish because we are
# assuming that lookup_parent needs to read the parent nt and if it
# can't then we want to just issue the warning.
if [[ -n $parent && ! -r $parent/Codemgr_wsdata/nametable ]]; then
echo "\nWarning: cannot read parent nametable, new file list"\
"not output." >&2
else
while read filepath; do
# lookup_parent populates local nt cache
if lookup_parent $filepath; then
remove_new $filepath
else
add_new $filepath
fi
done < tmp/files.new
echo
echo "New new-file list:"
echo
cat new
echo
echo "Diffs from previous new-file list:"
echo
${WXDIFFCMD:-diff} new.old new
echo "End new diffs =========================="
fi
}
#
# Update various lists (active, renamed, new)
#
wx_update() {
typeset i efp sortarg do_quick=false
typeset -i rc found
# default, update all lists
typeset update_active=true update_renamed=true update_new=true
while getopts :qrs i; do
case $i in
q) do_quick=true;;
r) update_active=false
update_new=false;;
s) ACTSORT=sort; sortarg="-s";;
*) fail "Invalid flag -$OPTARG. See 'wx help' for more"\
"info.";;
esac
done
deal_ws_renames
if $do_quick; then
# Do old school wx update (only for checked out files)
# This is faster but not as thorough.
wx_update_quick $sortarg
return
fi
if [[ -z $parent ]]; then
fail "Error: cannot do thorough update, no parent. Use 'update -q'"\
"instead."
fi
if [[ ! -r $parent/Codemgr_wsdata/nametable ]]; then
fail "Error: cannot read $parent/Codemgr_wsdata/nametable"
fi
# create tmp/checked_out file which putback -n may not list.
# Do this before putback so it doesn't unnecessarily update the
# sccs dirs cache.
wx_checked_out
# Get output of putback -n to detect renames and active files.
if [ -f $wxdir/srcroot_dir ]; then
get_pb_output $(cat $wxdir/srcroot_dir)
else
get_pb_output $DEFAULT_SRCDIR
fi
cd $wxdir
if $update_renamed; then
if [[ -f renamed ]]; then
mv renamed renamed.old ||
fail "Error: cannot create $wxdir/renamed.old."
else
touch renamed.old ||
fail "Error: cannot create $wxdir/renamed.old."
fi
nawk ' /^rename from:/{orig_file=$3}
$1 == "to:" {print $2 " " orig_file}' \
tmp/putback.out |$ACTSORT > tmp/renamed ||\
fail "Error, creation of $wxdir/tmp/renamed failed."
mv -f tmp/renamed renamed || \
fail "Error: cannot create $wxdir/renamed"
for filepath in $(cut -f1 -d' ' renamed); do
add_local_nt_entry $filepath
done
echo "New renamed file list:"
echo
cat renamed
echo
echo "Diffs from previous renamed file list:"
echo
${WXDIFFCMD:-diff} renamed.old renamed
echo "End renamed diffs =========================="
fi
if $update_active; then
# Create active list from putback output.
nawk '/^(update|create): / {print $2};
/^The following files are currently checked out/ \
{p=1; continue};
/^"/ {continue};
NF == 0 {p=0; continue};
{if (p==1)
print $1}' tmp/putback.out |
sort -u > tmp/active_nawk_out ||
fail "Error: cannot create $wxtmp/active_nawk_out"
# list files in conflict also
nawk '/^(conflict): / {print $2}' tmp/putback.out |
sort -u > tmp/conflict_nawk_out ||
fail "Error: cannot create $wxtmp/conflict_nawk_out"
# Need to read $wsdata/nametable if there are conflicts
if [[ -s tmp/conflict_nawk_out && ! -r $wsdata/nametable ]]
then
fail "Error: cannot read $wsdata/nametable."
fi
# clear the tmp active file
print -n > tmp/active.new || fail "Error: cannot create tmp/active.new."
# store current active list
wx_active > tmp/files.old ||
fail "Error: cannot create $wxtmp/files.old"
# go through all the possible active files (keeping the existing
# ones as well). Note hard tab in sed arg.
for filepath in $(sed '/^[ ]*$/d' tmp/files.old \
tmp/checked_out tmp/conflict_nawk_out \
tmp/active_nawk_out | nawk '!seen[$0]++' | $ACTSORT); do
efp=$(escape_re $filepath)
if grep -q "^$efp$" tmp/conflict_nawk_out; then
# conflict files have a parent but the
# putback output only shows the parent's
# filename, need to find local name in
# case of rename
grep "^$efp " $parent/Codemgr_wsdata/nametable|\
read localfile hash1 hash2 hash3 hash4
local_file="$(\
fgrep " $hash1 $hash2 $hash3 $hash4" \
$wsdata/nametable | cut -f1 -d' ')"
# continue if empty string
[[ -z "$local_file" ]] && continue
if ! grep -q "^$local_file" tmp/active.new; then
filepath=$local_file
else
continue
fi
fi
add_local_nt_entry $filepath
(echo $filepath; echo; wx_show_comment; echo)\
>> tmp/active.new
done
rm -f tmp/active_nawk_out
mv -f active active.old
mv -f tmp/active.new active
wx_active > tmp/files.new
echo
echo "New active file list:"
echo
cat tmp/files.new
echo
echo "Diffs from previous active file list:"
echo
${WXDIFFCMD:-diff} tmp/files.old tmp/files.new
echo "End active diffs =========================="
rm -f tmp/files.old tmp/files.new
fi
# The new list is for caching names of new files to speed up commands
# that list the new files.
if $update_new; then
if [ -f new ]; then
cp -f new new.old || fail "Error: cannot create file new.old."
elif [ ! -f new.old ]; then
touch new.old || fail "Error: cannot create file new.old."
fi
# Create new list from putback output.
nawk '/^create: / {print $2};' tmp/putback.out |
sort -u > tmp/new || fail "Error: cannot create $wxtmp/new."
mv -f tmp/new new
echo
echo "New new-file list:"
echo
cat new
echo
echo "Diffs from previous new-file list:"
echo
${WXDIFFCMD:-diff} new.old new
echo "End new diffs =========================="
fi
}
wx_edit() {
# Must be called via wx_eval
if [ -f SCCS/p.$file ]; then
echo "$filepath already checked out"
update_active $filepath
elif [ -f $file ]; then
echo $filepath
if sccs edit $silent $file; then
update_active $filepath
else
fail "sccs edit $filepath failed."
fi
else
ring_bell
echo "Warning. file $filepath not found."
fi
[[ $ACTSORT == sort ]] && do_active_sort=true
}
wx_unedit() {
# Must be called via wx_eval
typeset -i force=0
typeset arg msg
# set positional args to contents of global $args
set -- $args
while getopts :f arg; do
case $arg in
f) force=1;;
*) fail "Invalid flag -$OPTARG. See 'wx help' for"\
"more info.";;
esac
done
msg="differs from parent file, will remain in active list."
if [[ ! -f SCCS/p.$file ]]; then
echo "$filepath not checked out"
else
if [[ $backup_done -eq 0 ]]; then
if [[ $force -eq 0 ]]; then
yesno "Do you want to backup files first?"
if [[ "$answer" == "yes" ]]; then
wx_backup || fail "Backup failed."
fi
else
# only backup if necessary
print "Will backup wx and active files if necessary"
wx_backup -t || fail "Backup failed."
fi
backup_done=1;
# cd to the dir where the file is in case
# wx_backup took us somewhere else.
cd ${workspace}/$dir
fi
echo $filepath
if sccs unedit $silent $file; then
if [[ $force -eq 1 ]]; then
if is_active $filepath; then
if wx_pnt_filepath $filepath; then
if cmp -s $file $parentfilepath; then
remove_active_entry $filepath
else
print "$filepath $msg"
fi
fi
fi
else
ask_remove_active_entry
fi
fi
fi
}
wx_create() {
# Must be called via wx_eval
typeset -i checkout=0 force=0
typeset arg
while getopts :fo arg; do
case $arg in
o) checkout=1;;
f) force=1;;
*) fail "Invalid flag -$OPTARG. See 'wx help' for"\
"more info.";;
esac
done
if [ ! -f $file ]; then
ring_bell
echo "Error! $filepath is not a file."
return 1
elif [ -f $workspace/deleted_files/$filepath ]; then
ring_bell
cat >&2 <<-EOF
Error: a deleted version of $filepath exists.
You must undelete the file and edit that version.
Run:
'cd $workspace'
'$ME mv deleted_files/$filepath $filepath'
'$ME edit $filepath'
EOF
return 1
elif [[ -n $parent && -f $parent/$filepath ]]; then
ring_bell
cat >&2 <<-EOF
Error! $filepath exists in the parent workspace $parent.
Choose a different name.
EOF
return 1
elif [[ -n $parent && -f $parent/deleted_files/$filepath ]]; then
ring_bell
cat >&2 <<-EOF
Error! a deleted version of $filepath exists in the parent workspace
You must undelete the file and edit that version.
Run:
'cd $workspace'
'bringover deleted_files/$filepath'
'$ME mv deleted_files/$filepath $filepath'
'$ME edit $filepath'
EOF
return 1
elif [ -f SCCS/s.$file ]; then
echo "$filepath already created, active list not"\
"updated." >&2
else
# XXX it would be nice if keyword would work on new files
if ! egrep "$SCCSKEYWORD" $file >/dev/null; then
ring_bell
cat >&2 <<-EOF
Warning!!!
$filepath
is missing SCCS keywords. See
/net/wizard.eng/export/misc/general_docs/keyword_info.txt
for more info. Note, pay attention to the tabs.
EOF
if [[ $force -ne 1 ]]; then
yesno "Continue with create?"
if [[ "$answer" != 'yes' ]]; then
echo "Aborting create $filepath"
return 1
fi
fi
fi
if ! wx_copyright; then
# Sound bell
ring_bell
cat >&2 <<-EOF
Warning!!!
$filepath
has copyright problems. See
/net/wizard.eng/export/misc/general_docs/golden_rules.txt
for more info.
EOF
if [[ $force -ne 1 ]]; then
yesno "Continue with create?"
if [[ "$answer" != 'yes' ]]; then
echo "Aborting create $filepath"
return 1
fi
fi
fi
if ! cddlchk -a $file; then
# Sound bell
ring_bell
cat >&2 <<-EOF
Warning!!!
$filepath
has CDDL block problems. See
http://www.opensolaris.org/os/community/onnv/devref_toc/devref_7/#7_2_3_nonformatting_considerations
for more info.
EOF
if [[ $force -ne 1 ]]; then
yesno "Continue with create?"
if [[ "$answer" != 'yes' ]]; then
echo "Aborting create $filepath"
return 1
fi
fi
fi
if [[ ! -d SCCS ]]; then
mkdir SCCS || fail "Error: cannot create SCCS dir."
fi
if [[ -n "$comment_file" ]]; then
sccs create $silent -y"$(\
sed '/^[ ]*$/d' $comment_file)" $file ||
fail "sccs create $filepath failed."
else
sccs create $silent $file ||
fail "sccs create $filepath failed."
fi
rm -f ,$file
update_active $filepath
add_new $filepath
if [[ $checkout -eq 1 ]]; then
sccs edit $silent $file ||
fail "sccs edit $filepath failed."
fi
[[ $ACTSORT == sort ]] && do_active_sort=true
fi
}
wx_uncreate() {
# Must be called via wx_eval
# undoes a 'wx create'
typeset efp
typeset -i force=0
case $1 in
-f) force=1;;
-*) fail "$ME $command: unrecognized argument";;
esac
if [[ $backup_done -eq 0 ]]; then
if [[ $force -eq 0 ]]; then
yesno "Do you want to backup files first?"
if [[ "$answer" == 'yes' ]]; then
wx_backup || fail "Backup failed."
fi
else
# only backup if necessary
print "Will backup wx and active files if necessary"
wx_backup -t || fail "Backup failed."
fi
backup_done=1;
cd $workspace/$dir
fi
if [[ ! -f $file ]]; then
echo "$filepath not found, skipping"
return 1
fi
efp=$(escape_re $filepath)
if ! wx_pnt_filepath; then
# This is a new file so let's uncreate it.
answer='no'
if [[ $force -ne 1 ]]; then
cat <<-EOF
$filepath appears to be a new file.
Note, $command will remove its SCCS info from your
workspace and entry in the active list but will leave
the file in your workspace.
EOF
# yesno sets answer
yesno "Continue $command $filepath?"
else
# forced to yes
answer='yes'
fi
if [[ "$answer" == 'yes' ]]; then
if [[ ! -f SCCS/p.$file ]]; then
sccs edit $file ||
fail "sccs edit $filepath failed."
fi
rm -f SCCS/s.$file SCCS/p.$file
# For later cleanup on exit
if grep -q "^$efp " $wsdata/nametable 2>/dev/null; then
NEED_WS_CLEAN='y'
fi
if is_active $filepath; then
remove_active_entry $filepath
fi
remove_new $filepath
else
echo "skipping $filepath"
fi
else
echo "Not new, skipping $filepath"
fi # if ! wx_pnt_filepath
}
wx_reset() {
# Must be called via wx_eval
# resets a local file to the parent version
typeset efp
typeset -i force=0
case $1 in
-f) force=1;;
-*) fail "$ME $command: unrecognized argument";;
esac
if [[ $backup_done -eq 0 ]]; then
if [[ $force -eq 0 ]]; then
yesno "Do you want to backup files first?"
if [[ "$answer" == 'yes' ]]; then
wx_backup || fail "Backup failed."
fi
else
# only backup if necessary
print "Will backup wx and active files if necessary"
wx_backup -t || fail "Backup failed."
fi
backup_done=1;
fi
if [[ ! -f $file ]]; then
print "$filepath not found, skipping"
return 1
fi
efp=$(escape_re $filepath)
if wx_pnt_filepath; then
if [[ $force -ne 1 ]]; then
answer='no' # safe default
cat <<-EOF
Regarding: $filepath
$command will reset the file contents and sccs history to that of the parent:
$parentfilepath
and remove the entry from the active and renamed lists.
EOF
if [[ $filepath != $parentfile ]]; then
print "Note: local file will be reset to parent filepath."
fi
# yesno sets answer
yesno "Continue $command $filepath?"
else
# forced to yes
answer='yes'
fi
if [[ "$answer" == 'yes' ]]; then
if is_active $filepath; then
remove_active_entry $filepath
fi
if renamed; then
remove_renamed_entry $filepath
fi
rm -f $file SCCS/[ps].$file
grep -v "^$efp " $wsdata/nametable > $wxtmp/nametable.new || \
fail "Error: cannot create $wxtmp/nametable.new ."
mv -f $wxtmp/nametable.new $wsdata/nametable || \
fail "Error: mv -f $wxtmp/nametable.new $wsdata/nametable failed."
# add to bringover list for more efficient bringover
bofilelist="$bofilelist $parentfile"
else
print -u2 "Skipping $filepath"
fi
else
cat >&2 <<-EOF
Warning: skipping $filepath
as it appears to be new. Use 'uncreate' to remove this new file from the
workspace.
EOF
fi # if ! wx_pnt_filepath
}
cyclic_rename() {
# Detect the cyclic rename that causes Teamware problems.
# See 'man workspace' for more info
typeset new_filepath=$1 old_filepath=$2\
found_new=false found_old=false
typeset prev_new prev_old
while read prev_new prev_old; do
if [[ "deleted_files/$new_filepath" == $prev_new &&
$old_filepath != $prev_new ]]; then
# Cyclic rename
return 0
fi
if [[ $new_filepath == $prev_old && $prev_new != $old_filepath ]]
then
# The new file was the old file of a previous rename
found_new=true
if $found_old; then
# Cyclic rename
return 0
fi
elif [[ $old_filepath == $prev_new &&
$new_filepath != $prev_old ]]; then
# The old filepath was the new filepath of a
# previous rename and this rename is not an undo
# (new filepath is diff from previous old
# filepath)
found_old=true
if $found_new; then
# Cyclic rename
return 0
fi
fi
done < $wxdir/renamed
# Not a cyclic rename
return 1
}
wx_delete() {
# Must be called via wx_eval
typeset efp
typeset -i force=0
case $1 in
-f) force=1;;
-*) fail "$ME $command: unrecognized argument";;
esac
if [[ $backup_done -eq 0 ]]; then
if [[ $force -eq 0 ]]; then
yesno "Do you want to backup files first?"
if [[ "$answer" == 'yes' ]]; then
wx_backup || fail "Backup failed."
fi
else
# only backup if necessary
print "Will backup wx and active files if necessary"
wx_backup -t || fail "Backup failed."
fi
backup_done=1;
cd $workspace/$dir
fi
if [[ ! -f $file ]]; then
fail "$filepath isn't a file."
fi
# this is used a couple times so save escape_re value
efp=$(escape_re $filepath)
if wx_pnt_filepath; then
# Not a new file (has a parent)
if is_active $filepath; then
ring_bell
cat >&2 <<-EOF
Warning! $filepath
is in active list. You should run
"$ME reedit $filepath"
"$ME unedit $filepath"
which should remove it from the active list then run
"$ME $command $filepath".
Note, if you have made changes to this file that you want to keep, back
it up first.
$filepath not deleted.
EOF
return 1
fi
# See if this is already in the renamed list
if grep -q "^deleted_files/$efp " $wxdir/renamed; then
ring_bell
if [[ -f $workspace/deleted_files/$filepath ]]; then
cat >&2 <<-EOF
Warning: $filepath
has already been deleted.
Check for deleted_files/$filepath
in $wxdir/renamed .
EOF
else
cat >&2 <<-EOF
Warning! the $ME renamed list appears to be corrupt.
EOF
fail "Please run '$ME update -r' and try this"\
"command again."
fi
fi
if workspace filerm $file; then
# we know filerm renames files under deleted_files/
update_renamed_file $filepath deleted_files/$filepath
print "$filepath deleted"
print
print "To recover $filepath do:"
print "'cd $workspace'"
print "'$ME mv deleted_files/$filepath $filepath'"
else
print "There was an error while trying to delete $filepath"
fi
else
# This is a new file so let's remove it.
if is_active $filepath; then
ring_bell
cat >&2 <<-EOF
Warning: $filepath
is in active list. You should run
"$ME uncreate $filepath"
which should remove it from the active list
then run "$ME $command $filepath".
$filepath not deleted.
EOF
return 1
fi
answer='no'
if [[ $force -ne 1 ]]; then
cat <<-EOF
Warning: $filepath
appears to be a new file.
Do you want to completely remove the file and SCCS info from
your workspace? (If you answer no, the file will just be
removed from the active list if it's in there. If you answer
yes, the file and associated SCCS history files will removed
from the active list and also removed entirely from the
workspace.)
EOF
# yesno sets answer
yesno "Completely remove $filepath?"
else
# forced to yes
answer='yes'
fi
if [[ "$answer" == 'yes' ]]; then
rm -f $file SCCS/s.$file
[[ -f SCCS/p.$file ]] && rm -f SCCS/p.$file
echo "$filepath removed from workspace."
# For later cleanup, optional
if grep -q "^$efp " $wsdata/nametable 2>/dev/null; then
NEED_WS_CLEAN='y'
fi
fi
remove_new $filepath
fi
}
wx_mv() {
# create some local variables to avoid side effects
typeset efp old_filepath new_filepath
cd $workspace
old_filepath=$1
new_filepath=$2
if [[ -d $old_filepath && ( -d $new_filepath || ! -f $new_filepath ) ]]
then
if [[ $(basename $old_filepath) == "SCCS" ]]; then
return
fi
echo "Doing a $command between two directories can take a "\
"while, please be patient."
# deal with directory to directory move
if [[ -d $new_filepath ]]; then
base="$(basename $old_filepath)/"
else
base=
fi
sccsmv $old_filepath $new_filepath ||
fail "sccsmv $old_filepath $new_filepath failed."
# remove previous renamed entry
remove_renamed_entry $old_filepath
update_renamed_dir $new_filepath/$base
if grep -q "^$efp/" $wsdata/nametable 2>/dev/null; then
# Old entries in workspace nametable so set this
# to clean up on exit
NEED_WS_CLEAN='y'
fi
# rename path of active entry
sed "s|^$efp/|$new_filepath/$base|" $wxdir/active \
> $wxtmp/active || fail "Error: cannot create $wxtmp/active."
mv $wxtmp/active $wxdir/active ||
fail "Error: cannot create $wxdir/active."
sed "s|^$efp/|$new_filepath/$base|" $wxdir/new \
> $wxtmp/new || fail "Error: cannot create $wxtmp/new."
mv $wxtmp/new $wxdir/new || fail "Error: cannot create $wxdir/new."
elif [[ -f $old_filepath && -d $new_filepath ]]; then
wx_mv_file $old_filepath $new_filepath/$(basename $old_filepath)
elif [[ -f $old_filepath && ! -f $new_filepath ]]; then
wx_mv_file $old_filepath $new_filepath
elif [[ ! -f $old_filepath ]]; then
fail "Error! $old_filepath not found."
elif [[ -f $new_filepath ]]; then
fail "Error! $new_filepath exists."
fi
}
wx_mv_file() {
# store literal filepath in local var. to avoid side effects
typeset efp old_filepath new_filepath
cd $workspace
old_filepath=$1
new_filepath=$2
if [[ ! -f $old_filepath ]]; then
fail "Error! $old_filepath does not exist."
elif [[ -f $new_filepath ]]; then
fail "Error! $new_filepath already exists."
else
if cyclic_rename $new_filepath $old_filepath; then
fail "Cyclic renamed detected. See 'man workspace'"\
"for more info."
fi
if workspace filemv $old_filepath $new_filepath; then
update_renamed_file $old_filepath $new_filepath
efp=$(escape_re $old_filepath)
if is_active $old_filepath; then
# In active list so update list with new
# file name
rename_active_entry $old_filepath $new_filepath
fi
if grep -q "^$efp$" $wxdir/new; then
remove_new $old_filepath
add_new $new_filepath
fi
if grep -q "^$efp " $wsdata/nametable 2>/dev/null; then
NEED_WS_CLEAN=y
fi
else
echo "There was an error renaming $old_filepath to "\
"$new_filepath"
fi
fi
}
sccs_rmdel_done() {
# Note there are literal tabs in the []'s below so be careful when
# editing.
# file not in SCCS so return false (1)
[[ ! -f SCCS/s.$file ]] && return 1
if wx_pnt_filepath; then
sccs prt -a $parentfilepath > $wxtmp/parenthist
sccs prt -a $file > $wxtmp/filehist
diff $wxtmp/parenthist $wxtmp/filehist |
grep '^> R [0-9]\.[0-9]'|
egrep -v ' (Codemgr|Fake)[ ]' |
sed 's/^> //' > $wxtmp/newrmdels
[[ ! -f $wxtmp/newrmdels ]] && fail "Error: cannot create $wxtmp/newrmdels"
rm -f $wxtmp/parenthist $wxtmp/filehist
else
# New file, no parent
sccs prt -a $file |
egrep -v \
'^R [0-9]+(\.[0-9]+)+[ ].* (Codemgr|Fake)[ ]' |
egrep '^R [0-9]+(\.[0-9]+)+[ ]' > $wxtmp/newrmdels
[[ ! -f $wxtmp/newrmdels ]] && fail "Error: cannot create $wxtmp/newrmdels"
fi
if [[ -s $wxtmp/newrmdels ]]; then
cat $wxtmp/newrmdels
rm -f $wxtmp/newrmdels
# an rmdel was done so return true
return 0
else
rm -f $wxtmp/newrmdels
# no rmdel was done so return false
return 1
fi
}
rmdelchk() {
# returns 0 (success) if an rmdel was done.
# Should be called via wx_eval().
if sccs_rmdel_done ; then
ring_bell
cat <<-EOF
Warning, it looks like 'sccs rmdel' was run on $filepath
This will cause a problem for Teamware. Please fix this.
Note, this can be fixed by doing '$ME reedit $filepath'
EOF
return 0
else
return 1
fi
}
wx_delget() {
typeset -i force=0
typeset arg comment_found=false
while getopts :f arg; do
case $arg in
f) force=1;;
*) fail "Invalid flag -$OPTARG. See 'wx help' for"\
"more info.";;
esac
done
if [[ (! -f SCCS/s.$file && ! -f SCCS/p.$file) ||
(-f SCCS/s.$file && -f SCCS/p.$file) ]]; then
# Check for keywords unless force is set or file is in
# keywords.NOT
if [[ $force -ne 1 ]] && [ -f SCCS/p.$file ] &&
! grep -q "^$(escape_re $filepath)$" \
$wxdir/keywords.NOT 2>/dev/null &&
! keywords -p $file; then
ring_bell
cat <<-EOF
The keywords check has detected a problem with $filepath
If this check should be skipped for this file, put the filepath in
${wxdir}/keywords.NOT.
See /net/wizard.eng/export/misc/general_docs/keyword_info.txt
for more info about keywords. Note, pay attention to the tabs.
EOF
yesno "Continue with $command for $filepath?"
if [[ "$answer" != 'yes' ]]; then
echo "Aborting $command $filepath\n"
return
fi
fi
[[ -f $wxtmp/comment ]] && rm $wxtmp/comment
if [[ -n "$comment_file" ]]; then
# note hard tab in sed r.e.
sed '/^[ ]*$/d' $comment_file > $wxtmp/comment &&
comment_found=true
else
wx_show_comment >$wxtmp/comment && comment_found=true
fi
if $comment_found; then
echo $filepath
cat $wxtmp/comment
if [[ -f SCCS/s.$file ]]; then
# file history so check in file
sccs delget $silent -y"`cat $wxtmp/comment`" \
$file ||
fail "sccs delget failed $filepath."
else
# no file history so create file
sccs create $silent -y"`cat $wxtmp/comment`" \
$file ||
fail "sccs create $filepath failed."
rm -f ,$file
fi
[[ -n "$comment_file" ]] &&
update_active_comment $filepath
else
ring_bell
print "\nError: no comments (NO_COMMENT) registered for $filepath"
if [[ $force -ne 1 ]] ; then
yesno "Invoke ${EDITOR:-vi} to edit"\
"$wxdir/active"'?'
if [ "$answer" == 'yes' ]; then
${EDITOR:-vi} $wxdir/active
wx_delget
else
fail "Edit $wxdir/active and try again."
fi
else
fail "Edit $wxdir/active and try again."
fi
fi
elif [[ -f SCCS/s.$file && ! -f SCCS/p.$file ]]; then
echo "$filepath already checked in"
elif [[ ! -f SCCS/s.$file && -f SCCS/p.$file ]]; then
fail "Error, $filepath is missing SCCS/s.$file ."
fi
}
wx_get() {
if [[ -f SCCS/s.$file ]]; then
sccs get $args -s $file || fail "sccs get $file failed."
else
ring_bell
echo "$filepath not in SCCS"
fi
}
wx_info() {
if [ -f SCCS/p.$file ]; then
if [[ -w $file ]]; then
echo "$filepath (checked out)"
else
ring_bell
echo "$filepath (Warning, inconsistent state."
echo " SCCS/p.$file exists but $file is readonly.)"
fi
elif [[ ! -f $file ]]; then
ring_bell
echo "$filepath (Warning, not found in $workspace)"
elif [[ ! -f SCCS/s.$file ]]; then
ring_bell
echo "$filepath (Warning, not in SCCS)"
else
echo "$filepath (checked in)"
fi
echo "Check-in comment:"
wx_show_comment
if [ -f SCCS/s.$file ]; then
echo "Most recent delta: \c"
sccs prt -y $file
fi
echo "File name status:"
if renamed; then
# old is set by renamed
echo "Locally renamed, parent file = $parentfile"
elif lookup_parent $filepath; then
# parentfile is set by lookup_parent
if [[ "$filepath" != "$parentfile" ]]; then
echo "In parent ws, file renamed to: $parentfile"
else
echo "Same as parent."
fi
else
echo "New file (does not exist in parent ws)."
fi
echo
}
wx_copyright() {
typeset _problem=0
case $file in
*.adb) return;;
*.fdbg) return;;
*.in) return;;
esac
year=`date +%Y`
oldcopyright1='Copyright \(c\).* Sun Microsystems, Inc.'
# The backslash on the next line is just a hack so that
# 'wx copyright' on itself doesn't trigger a false positive.
oldcopyright2='Copyright\ .* by Sun Microsystems, Inc.'
copyright='Copyright '$year' Sun Microsystems, Inc.'
reserved='All rights reserved.'
license='Use is subject to license terms.'
if egrep -s ''"$oldcopyright1"'' $file ; then
echo "old copyright with '(c)' in $filepath"
_problem=1
fi
if egrep -s ''"$oldcopyright2"'' $file; then
echo "old copyright with 'by' in $filepath"
_problem=1
fi
if egrep -s ''"$copyright"' '"$reserved"'' $file; then
echo "Need two spaces between copyright and all rights "\
"reserved phrases in $filepath"
_problem=1
fi
if ! egrep -s ''"$copyright"'' $file; then
echo "Proper $year copyright missing in $filepath."
echo "Only the current year should appear."
_problem=1
fi
if ! egrep -s ''"$reserved"'' $file; then
echo "'$reserved' message missing in $filepath"
_problem=1
fi
if ! egrep -s ''"$license"'' $file ; then
echo "'$license' message missing in $filepath"
_problem=1
fi
return $_problem
}
get_multi_deltas() {
# Get list of files with more that one delta when putback.
# set global multi_delta_list.
if ! deltachk >/dev/null 2>&1; then
multi_delta_list="$multi_delta_list $filepath"
fi
}
wx_reedit() {
typeset -i numkids=`workspace children | wc -l`
typeset i newfiles only_multideltas=false
case $1 in
-m) only_multideltas=true;;
-*) fail "Invalid flag $1. See 'wx help' for more"\
"info.";;
esac
if [[ ! -f $wsdata/nametable ]]; then
echo "$wsdata/nametable not found, all files assumed new."
ok_to_proceed "Okay to continue with $command?"
elif [[ ! -r $wsdata/nametable ]]; then
fail "Error: cannot read $wsdata/nametable."
fi
if $only_multideltas; then
# get_multi_deltas sets multi_delta_list
wx_eval get_multi_deltas
# set file_list for wx_eval wx_reedit_file below
file_list=$multi_delta_list
fi
cd $workspace
for i in $file_list; do
if [[ ! -f $i ]]; then
fail "$i does not exist."
fi
if ! lookup_parent $i; then
if [[ -z $newfiles ]]; then
newfiles="$i"
else
newfiles="$newfiles\n$i"
fi
fi
done
if [[ -n $newfiles ]]; then
# If there are some new files, give user a warning
cat <<-EOF | ${PAGER:-more}
$ME thinks following files are new (not in parent workspace) and will
reset their file histories to version 1.1 (exit if this list isn't correct):
$(echo $newfiles)
EOF
ok_to_proceed "Okay to continue with $command?"
if ! $CHECKIN; then
cat <<-EOF
Hint, use '$ME redelget' to collapse/reset new file histories to version
1.1 since '$ME $command' will check out the file and '$ME delget' always
increments the file version doing the check in.
EOF
fi
fi
if [ $numkids -gt 0 ]; then
echo "WARNING: This workspace has the following children:"
echo
workspace children
echo
echo "The reedit command will coalesce all children's deltas"
echo "into one, losing all delta comments in the process."
ok_to_proceed 'Are you sure you want to proceed?'
fi
echo
yesno "Do you want to backup files first?"
if [[ "$answer" == 'yes' ]]; then
wx_backup || fail "Backup failed."
fi
echo "$command beginning..."
echo
wx_eval wx_reedit_file
echo
echo "$command complete"
echo
[[ $ACTSORT == sort ]] && do_active_sort=true
}
wx_reedit_file() {
# Must be called via wx_eval
typeset comment_found=false
if [[ ! -f $file ]]; then
echo "$file does not exist. Can not reedit $file"
return
fi
echo $filepath
# Is there a parent file?
if wx_pnt_filepath; then
rm -f $wxtmp/s.$file
cp -p $parentsdot $wxtmp/s.$file ||
fail "Error: cannot cp $parentsdot $wxtmp/s.$file ."
# get the latest parent delta and comment and filter out
# certain fields removing trailing spaces
p_delta="$(sccs prt -y $parentsdot|expand -1|grep 'SCCS'|\
cut -f'4,5,6,9-' -d' '|sed 's/ *$//')"
if [[ -z "$p_delta" ]]; then
ring_bell
echo "Warning ${command}: skipping $filepath,"
echo "cannot get parent delta info"
echo
return 1
fi
# create a list of local deltas in the same format
# also removing trailing spaces
sccs prt $file|expand -1|
nawk '
/^D [0-9]+(\.[0-9]+)+ +[0-9][0-9]\/[0-9][0-9]/ {
if (delta != "") {
# print previous delta info
print delta comment;
}
delta=sprintf("%s %s %s %s ",$3, $4, $5, $8);
comment = "";
}
! /^D [0-9]+(\.[0-9]+)+ +[0-9][0-9]\/[0-9][0-9]/ {
# Add comment lines to comment variable
if (comment == "") {
if (NF > 0) {
comment = $0;
} else {
# empty lines require a space
# in comment.
comment = " ";
}
} else {
if (NF > 0) {
comment = comment " " $0;
} else {
comment = comment " ";
}
}
}
END {
if (delta != "") {
# print last delta info
print delta comment;
}
}' | sed 's/ *$//' > $wxtmp/l_deltas ||
fail "Error: cannot create $wxtmp/l_deltas."
# If the latest parent delta doesn't appear in the local file
# then a bringover is required. Use fgrep because comment may
# have RE chars in it.
if ! fgrep "$p_delta" $wxtmp/l_deltas >/dev/null; then
ring_bell
echo "\nWarning ${command}: skipping $filepath because:"
echo "parent's version of $filepath"
echo "is newer than child's -- bringover required."
echo
return 1
fi
if [ ! -f SCCS/p.$file ]; then
if sccs edit $silent $file; then
update_active $filepath
else
fail "sccs edit $file failed."
fi
fi
# make copy of local file and copy parent's SCCS s. file over
# local.
mv -f $file ${file}.wx_reedit ||
fail "mv -f $file ${file}.wx_reedit failed."
rm -f SCCS/s.$file SCCS/p.$file
cp $wxtmp/s.$file SCCS/s.$file ||
fail "cp $wxtmp/s.$file SCCS/s.$file failed."
if sccs edit $silent $file; then
update_active $filepath
else
fail "sccs edit $file failed."
fi
mv -f ${file}.wx_reedit $file ||
fail "mv -f ${file}.wx_reedit $file failed."
if $CHECKIN; then
wx_delget
fi
touch $file
else
# reediting a new file.
if [[ -f SCCS/s.$file ]]; then
if [[ ! -f SCCS/p.$file ]]; then
# File needs to be checked out
sccs edit $silent $file ||
fail "sccs edit $file failed."
fi
# clean up SCCS since we are going to create again.
rm -f SCCS/s.$file
fi
# clean up SCCS since we are going to create again.
[[ -f SCCS/p.$file ]] && rm -f SCCS/p.$file
[[ -f $wxtmp/comment ]] && rm $wxtmp/comment
wx_show_comment >$wxtmp/comment && comment_found=true
if $comment_found; then
echo $filepath
cat $wxtmp/comment
rm -f SCCS/s.$file SCCS/p.$file
sccs create $silent -y"`cat $wxtmp/comment`" $file ||
fail "sccs create $filepath failed."
rm -f ,$file
[[ -n "$comment_file" ]] &&
update_active_comment $filepath
else
ring_bell
echo "\nError, no comments registered for $filepath"
if [[ $force -ne 1 ]] ; then
yesno "Invoke ${EDITOR:-vi} to edit"\
"$wxdir/active"'?'
if [[ "$answer" == 'yes' ]]; then
${EDITOR:-vi} $wxdir/active
wx_reedit_file
else
fail "Edit $wxdir/active and try again."
fi
else
fail "Edit $wxdir/active and try again."
fi
fi
if $CHECKIN; then
# No need to check out file.
return
fi
if sccs edit $silent $file; then
update_active $filepath
add_new $filepath
else
fail "sccs edit $file failed."
fi
fi
}
#
# Warn if there are sccs delta issues
#
deltachk() {
# must be run via wx_eval
typeset -i numdeltas
typeset newfile checkedout=false
if wx_pnt_filepath; then
# find number of deltas by subtracting the number in the parent
# from the local file (note the literal Control-A in the grep
# R.E.s below).
(( numdeltas = $(grep '^d D' SCCS/s.$file|wc -l) - \
$(grep '^d D' $parentsdot|wc -l) ))
newfile=false
else
# checking a new file (note the literal Control-A in the grep
# R.E.)
numdeltas=$(grep '^d D' SCCS/s.$file|wc -l)
newfile=true
fi
if [[ -z $numdeltas ]]; then
cat <<-EOF
Warning: the local file:
$filepath
does not appear to have a sccs delta history file or the sccs delta
history file is corrupt. If the local file is new try using:
"cd $dir"
"$ME create $file"
If the file is not new (exists in parent):
"cd $dir"
Save a copy of the local file
Remove the SCCS/[ps].$file history files
"bringover $filepath"
"$ME edit $file"
Then carefuly merge the saved copy of local file with the
file brought over from parent. Hint: twmerge is a good merge
tool.
EOF
return 1
fi
[[ -f SCCS/p.$file ]] && checkedout=true
# Note the use of hard tabs in the messages
case $numdeltas in
0) if $checkedout; then
# file is checked out so assume there
# will be 1 delta when checked in.
return 0
else
if [[ -n $parentfilepath ]]; then
if cmp -s $file $parentfilepath; then
cat <<-EOF
Warning: the local file:
$filepath
and the parent file:
$parentfilepath
content are identical. There are no new deltas in the local file.
If this file is no longer required in the active list use:
"cd $dir"
"$ME reset $file"
to remove file from the wx state files (active list, etc...)
EOF
else
cat <<-EOF
Warning: the local file:
$filepath
and the parent file:
$parentfilepath
have the same number of deltas but contents differ. A bringover may be
required before putback.
EOF
fi
else
cat <<-EOF
Warning: the local file:
$filepath
is new but doesn't appear to contain any deltas. The SCCS delta history file
may need to be recreated. If so:
"cd $dir"
"rm SCCS/s.$file"
"$ME create $file"
EOF
fi
return 1
fi ;;
1) if $checkedout; then
cat <<-EOF
Regarding $filepath
Warning! There may be more than 1 delta when you check this file in
(currently checked out). Run '$ME redelget' on this file to collapse
the deltas and check in with 1 delta unless putting back > 1 bug.
EOF
return 1
else
return 0
fi ;;
-*) # a negative number means the parent has more deltas
cat <<-EOF
Regarding $filepath
Warning! The parent file has more deltas than the local file.
You should bringover the local file to fix this.
EOF
;;
*) if $newfile && $checkedout; then
cat <<-EOF
Regarding $filepath
Warning! There may be more than 1 delta when you check this file in
(currently checked out). Run '$ME redelget' on this file to collapse
the deltas and check in with 1 delta unless putting back > 1 bug.
EOF
else
cat <<-EOF
Regarding $filepath
Warning! There is more than 1 delta. Run:
'cd $dir; $ME redelget $file'
to collapse the deltas on this file and check in with 1 delta unless
putting back > 1 bug.
EOF
fi
return 1;;
esac
}
wx_cstyle() {
case $file in
*.[ch]) ;;
*) return;;
esac
((CSTYLE_INDEX = CSTYLE_INDEX + 1))
(cd $workspace;
cstyle ${CSTYLE_FLAGS} $args $filepath >\
$wxtmp/wx.cstyle.$CSTYLE_INDEX) &
}
wx_jstyle() {
case $file in
*.java) ;;
*) return;;
esac
((JSTYLE_INDEX = JSTYLE_INDEX + 1))
(cd $workspace;
jstyle ${JSTYLE_FLAGS} $args $filepath >\
$wxtmp/wx.jstyle.$JSTYLE_INDEX) &
}
wx_find_compression_progs() {
gzip=/usr/bin/gzip
if [[ ! -x $gzip && -n "$GZIPBIN" ]]; then
gzip=$GZIPBIN
fi
bzip2=/usr/bin/bzip2
if [[ ! -x $bzip2 && -n "$BZIP2BIN" ]]; then
bzip2=$BZIP2BIN
fi
}
wx_get_backup_dir() {
typeset backup_dir_file
# if backup_dir hasn't been set already...
if [[ -z "$backup_dir" ]]; then
# use the backup dir specifier in the wx/
backup_dir_file=$wxdir/backup_dir
if [[ ! ( -f $backup_dir_file && -r $backup_dir_file &&
-s $backup_dir_file ) ]]; then
fail "$backup_dir_file: missing, empty, or not readable"
fi
backup_dir=`cat $backup_dir_file`
fi
if [[ ! ( -d $backup_dir && -x $backup_dir && -r $backup_dir ) ]]; then
fail "$backup_dir: missing, not a directory, or bad permissions"
fi
}
#
# This code requires that the files (n.sdot, n.pdot and n.clear) for a given
# backup have the same extension (.tar, .tar.gz, or .tar.bz2). It also
# disallows the existance of two incarnations of the same file (i.e.
# n.clear.tar and n.clear.tar.gz)
#
# It's up to the user to straighten things out if the above conditions are
# violated. The only time that is a problem is if they are trying to
# restore a version which violates the above rules.
#
# Takes one argument, the version number.
#
# Returns:
# (return code) 0 if exists and consistent,
# 1 if not found,
# 2 if inconsistent
# b_clear, b_sdot, b_pdot On success, the full path to the clear, sdot
# and pdot files comp, ext The compression program for and
# extension of said files
#
wx_check_backup() {
typeset _new _b_new _renamed _b_renamed _active _b_active \
_local_nt _b_local_nt found bad
_version=$1
clear=$_version.clear.tar
sdot=$_version.sdot.tar
pdot=$_version.pdot.tar
not=$_version.not.tar
_renamed=$_version.renamed
_b_renamed=$backup_dir/$_renamed
_new=$_version.new
_b_new=$backup_dir/$_new
_active=$_version.active
_b_active=$backup_dir/$_active
_local_nt=$_version.local_nametable
_b_local_nt=$backup_dir/$_local_nt
_sort=$_version.sort_active
_b_sort=$backup_dir/$_sort
found=false
bad=false
#
# these arrays must be in sync with:
# 1. the immediately following _count variable
# 2. wx_find_last_backup's egrep expression
# 3. wx_backup's "$args" handling.
# 4. wx_find_compression_progs's programs
#
set -A _comps "" "$gzip" "$bzip2"
set -A _extns "" ".gz" ".bz2"
_count=3
idx=0
while [[ $idx -lt $_count ]] ; do
_ext=${_extns[$idx]}
_comp=${_comps[$idx]}
_clear=$clear$_ext
_sdot=$sdot$_ext
_pdot=$pdot$_ext
_b_clear=$backup_dir/$_clear
_b_sdot=$backup_dir/$_sdot
_b_pdot=$backup_dir/$_pdot
if [[ -f $_b_clear || -f $_b_sdot ]]; then
if $found; then
echo "$backup_dir: both $_version.*.tar$ext "\
"and $_version.*.tar$_ext exist"
bad=true
else
ext=$_ext
comp=$_comp
found=true
fi
fi
if [[ -f $_b_clear && ! -f $_b_sdot ]]; then
echo "$backup_dir: $_clear exists; $_sdot does not"
bad=true
elif [[ ! -f $_b_clear && -f $_b_sdot ]]; then
echo "$backup_dir: $_sdot exists; $_clear does not"
bad=true
elif [[ ! -f $_b_sdot && -f $_b_pdot ]]; then
echo "$backup_dir: $_pdot exists; $_sdot does not"
bad=true
fi
idx=`expr $idx + 1`
done
if [[ ! -f $_b_renamed && -f $_b_active ]]; then
# Can determine compression only
return 1
fi
if [[ -f $_b_renamed && -f $_b_active && -f $_b_new &&
-f $_b_local_nt ]]; then
found=true
else
bad=true
fi
$bad && return 2
$found || return 1
b_renamed=$_b_renamed
b_new=$_b_new
b_active=$_b_active
b_local_nt=$_b_local_nt
if [[ -f $backup_dir/$clear$ext && -f $backup_dir/$sdot$ext ]]; then
b_clear=$backup_dir/$clear$ext
b_sdot=$backup_dir/$sdot$ext
else
b_clear=
b_sdot=
fi
# It's not an error if this doesn't exist.
if [[ -f $backup_dir/$pdot$ext ]]; then
b_pdot=$backup_dir/$pdot$ext
else
b_pdot=
fi
# It's not an error if this doesn't exist.
if [[ -f $backup_dir/$not ]]; then
b_not_files=$backup_dir/$not
else
b_not_files=
fi
# It's not an error if this doesn't exist.
if [[ -f $_b_sort ]]; then
b_sort=$_b_sort
else
b_sort=
fi
return 0
}
#
# finds the number of the last backup.
#
# Returned in $result, which is -1 if no backups are found
#
wx_find_last_backup() {
#
# The list of extensions in the egrep expression must be in sync
# with wx_check_backup's arrays
#
result=`ls -1 $backup_dir | egrep \
'^[0-9][0-9]*\.((pdot|sdot|clear)\.tar($|\.gz$|\.bz2$)|active|renamed|new|local_nametable$)'| \
sed 's/^\([0-9][0-9]*\)\..*$/\1/'| sort -rn | head -1`
[[ -n "$result" ]] # fail if result is empty
}
#
# wx_do_backup
# Returns 0 on successful backup, 1 if nothing to backup, 2 any other
# error.
#
wx_do_backup() {
_type=$1 # type of files (for user)
_out=$2 # file to write to
_comp="$3" # compression program, or empty for no compression
_evalarg=$4 # arg to wx_eval to get the correct file list
typeset backupfiles=$(wx_eval "$_evalarg")
echo
echo "Saving $_type files to $_out"
echo
if [[ -z $backupfiles ]]; then
echo "Note, nothing to backup."
return 1
fi
if [[ -n "$_comp" ]]; then
( tar cvf - $backupfiles 2>$BACKUP_ERRORS || \
rm -f $_out ) | $_comp -9 -c > $_out || rm -f $_out
else
tar cvf $_out $backupfiles 2>$BACKUP_ERRORS ||
rm -f $_out
fi
[[ -f "$_out" ]] || return 2 # $_out is removed on any error
return 0
}
wx_do_restore() {
_type=$1 # type of files (for user)
_in=$2 # file to read from
_comp="$3" # uncompressing program
echo
echo "Restoring $_type files from $_in"
echo
if [[ -n "$_comp" ]]; then
#
# if decompression fails, echo a bad value to make tar fail
#
($_comp -dc < $_in || echo "fail") | tar xvpf - || return 1
else
tar xvpf $_in || return 1
fi
return 0
}
#
# do renames in a workspace from a backup set
#
wx_do_renames() {
typeset _in=$1 # file to read from
if [[ ! -f $wsdata/nametable ]]; then
echo "$wsdata/nametable not found, not doing renames."
return 0
fi
echo
echo "Restoring renamed files from $_in"
echo
# Note this assumes we're staring in $workspace
while read new hash1 hash2 hash3 hash4; do
# get current local file name
current=$(grep " $hash1 $hash2 $hash3 $hash4$" \
$wsdata/nametable | cut -f1 -d' ')
if [[ -z $current ]]; then
# nothing to rename
continue
fi
if [[ "$new" == "$current" ]]; then
# rename not needed
continue
fi
if [[ ! -f $new ]]; then
if [[ ! -d $(dirname $new) ]]; then
mkdir -p $(dirname $new) ||
fail "Error: cannot create dir $(dirname $new)"
fi
echo "Renaming current workspace file $current to $new"
workspace filemv $current $new
else
if [[ -f $current ]]; then
ring_bell
cat >&2 <<-EOF
Warning: $current
and $new
files both exist in current workspace with the
same hash. The restored renamed list should be recreated by running:
'$ME update -r'
Skipping rename of $current
to $new
EOF
fi
fi
done < $_in
return 0
}
wx_backup() {
typeset orig_file_list ws_file back_file
typeset newer=false
typeset origdir=$PWD
case $1 in
-i) wx_get_backup_dir
echo "Backup dir is $backup_dir"
ls -ltr $backup_dir
echo "Backup dir is $backup_dir"
cd $origdir
return ;;
-t) newer=true
# backup if wx files are newer than last backup.
# Implies use of default compression and no
# interaction. Doing shift so case further down
# won't see -t.
shift;;
esac
# save state in case wx_backup called from another command.
orig_file_list=$file_list
# we always backup the active files.
file_list=$(wx_active)
if [[ ! -s $wxdir/renamed && -z $file_list ]]; then
echo "There isn't anything to backup."
file_list=$orig_file_list
return 0
fi
# must be in workspace to do backup
cd $workspace || fail "Error: cannot cd $workspace"
if $newer; then
# get latest wx state files and active files but skip
# wx/tmp and wx/*.old files.
ws_file=$(ls -1t $wxdir/!(tmp|*.old) $file_list|head -1)
# get latest backup.
wx_get_backup_dir
back_file=$(ls -1t $backup_dir/*|head -1)
if [[ ( -z "$back_file" && -n "$ws_file" ) || \
(( -n "$back_file" && -n "$ws_file" ) && \
$ws_file -nt $back_file ) ]]
then
: # continue with backup
else
print "Skipping backup, last backup newer than wx"\
"files."
file_list=$orig_file_list
cd $origdir
return 0
fi
fi
wx_find_compression_progs
wx_get_backup_dir
if [[ ! -w $backup_dir ]]; then
fail "$backup_dir: not writable"
fi
if wx_find_last_backup; then
prev_backup=$result
version=`expr $result + 1`
else
prev_backup=
version=0
fi
#
# This must be in sync with wx_check_backup's arrays
#
case $1 in
-n) ext=; comp=;;
-z) ext=.gz; comp=$gzip;;
-b) ext=.bz2; comp=$bzip2;;
"-") shift;; # treat this as use default compression
"") ;; # treat this as use default compression
-??*) fail "$ME $command: only accepts a single argument";;
*) fail "$ME $command: unrecognized argument";;
esac
if [[ -z "$1" ]]; then
#
# default to the compression of the previous backup
#
if [[ -z "$prev_backup" ]]; then
ext=
comp=
else
wx_check_backup $prev_backup
# A return of 1 is okay
if [ $? -gt 1 ]; then
echo "$backup_dir/$prev_backup.*: "\
"cannot determine previous "\
"compression."
if $newer; then
# Assume we want backup.
answer="yes"
else
yesno "Proceed with no "\
"compression?"
fi
if [[ $answer == "no" ]]; then
echo "No backup done."
file_list=$orig_file_list
cd $origdir
return
fi
ext=
comp=
fi
fi
fi
if [[ -n "$comp" && ! -x "$comp" ]]; then
echo "${comp}: missing. defaulting to no compression"
ext=
comp=
fi
b_clear=$backup_dir/$version.clear.tar$ext
b_sdot=$backup_dir/$version.sdot.tar$ext
b_pdot=$backup_dir/$version.pdot.tar$ext
b_local_nt=$backup_dir/$version.local_nametable
b_active=$backup_dir/$version.active
b_renamed=$backup_dir/$version.renamed
b_new=$backup_dir/$version.new
b_not_files=$backup_dir/$version.not.tar
b_sort=$backup_dir/$version.sort_active
#
# If anything goes wrong, clean up after ourselves
#
trap "/usr/bin/rm -f $b_clear $b_sdot $b_pdot $b_active $b_renamed $b_new $b_local_nt $b_not_files $b_sort; exit 1" 0 1 2 3 15
fail_msg='failed. Cleaning up. '
#
# It is not a hard error for the SCCS/s.file to be missing. We just
# let the user know what's going on.
#
sdot_cmd='
_sdot="SCCS/s.$file";
_file="$dir/$_sdot";
if [[ -f $_sdot ]]; then
echo "$_file";
else
echo "$_file: not found" >&2;
fi
'
pdot_cmd='
_pdot="SCCS/p.$file";
_sdot="SCCS/s.$file";
_file="$dir/$_pdot";
if [[ -f $_pdot ]]; then
echo "$_file";
elif [[ ! -f $_sdot ]]; then
echo "$_file: not checked in" >&2;
elif [[ -w $file ]]; then
echo "$_file: not found but $file is writable!" >&2;
fi
'
# Do this first in case there are no active files
echo
echo "Saving renamed file list to $b_renamed"
echo
cp $wxdir/renamed $b_renamed || fail "$b_renamed: $fail_msg"
if [[ -f $wxdir/local_nametable ]]; then
echo
echo "Saving local_nametable to $b_local_nt"
echo
cp $wxdir/local_nametable $b_local_nt || \
fail "$b_local_nt: $fail_msg"
fi
if [[ -f $wxdir/sort_active ]]; then
print
print "Saving sort_active to $b_active"
print
cp $wxdir/sort_active $b_sort || fail "$b_sort: $fail_msg"
fi
if ls wx/*.NOT >/dev/null 2>&1; then
echo
echo "Saving .NOT files to $b_not_files"
echo
tar -cf $b_not_files wx/*.NOT || fail "$b_not_files: $fail_msg"
fi
# Are there any active files to backup?
if [[ -n $file_list ]]; then
wx_do_backup 'clear' $b_clear "$comp" 'echo $filepath' ||
fail "$b_clear: $fail_msg"
wx_do_backup 'sdot' $b_sdot "$comp" "$sdot_cmd" ||
fail "$b_sdot: $fail_msg"
echo
echo "Saving new list to $b_new"
echo
cp $wxdir/new $b_new || fail "$b_new: $fail_msg"
# It's not fatal if the backup error for pdot files is
# 'no files to backup'. This is because it's possible
# that the active files aren't checked out so there
# won't be any pdot files.
wx_do_backup 'pdot (if any)' $b_pdot "$comp" "$pdot_cmd"
if [[ $? -gt 1 ]]; then
fail "$b_pdot: $fail_msg $(cat $BACKUP_ERRORS)"
fi
fi
echo
echo "Saving active file list to $b_active"
echo
cp $wxdir/active $b_active || fail "$b_active: $fail_msg"
trap - 0 1 2 3 15
rm -f $BACKUP_ERRORS
# restore file_list state.
file_list=$orig_file_list
cd $origdir
return 0
}
wx_restore() {
typeset force=0
case $1 in
-f) force=1;;
-*) fail "Invalid flag $1. See 'wx help' for more info.";;
esac
if [[ $force -eq 0 ]]; then
cat <<-EOF
Warning, the restore command will overwrite several files including the
active and renamed lists. This could be a problem if you have made
changes to your workspace and $ME related files following the last
backup. It may be a good idea to run:
$ME update
after the restore so that the active and renamed lists are updated with
the new changes in the workspace.
Also, restore may perform workspace renames in this workspace if it
finds that the existing file has a pathname that differs from that in
the backup being restored.
EOF
ok_to_proceed "Do you really want to do the restore?"
fi
wx_find_compression_progs
wx_get_backup_dir
if wx_find_last_backup; then
version=$result
else
fail "$backup_dir: no backups found"
fi
if [[ $force -eq 0 ]]; then
ask 'Version to restore from' $version
version=$answer
fi
#
# wx_check_backup sets $comp, $b_clear, and $b_sdot when successful
#
if wx_check_backup $version; then
:
else
if [[ $? -eq 2 ]]; then
fail "$backup_dir/$version.*: unable to restore"\
"inconsistent version"
else
fail "$backup_dir: Unable to find version $version"
fi
fi
b_active=$backup_dir/$version.active
if [[ -n "$comp" && ! -x "$comp" ]]; then
fail "${comp}: missing -- cannot decompress $b_clear"
fi
# must be in workspace to do restore
cd $workspace || fail "Error: cannot cd $workspace"
[[ -f $b_renamed ]] || fail "$b_renamed: missing"
[[ -f $b_new ]] || fail "$b_new: missing"
[[ -f $b_active ]] || fail "$b_active: missing"
[[ -r $b_renamed ]] || fail "$b_renamed: not readable"
[[ -r $b_new ]] || fail "$b_new: not readable"
[[ -r $b_active ]] || fail "$b_active: not readable"
if [[ -f $b_clear ]]; then
[[ -r $b_clear ]] || fail "$b_clear: not readable"
fi
if [[ -f $b_sdot ]]; then
[[ -r $b_sdot ]] || fail "$b_sdot: not readable"
fi
if [[ -f $b_pdot ]]; then
[[ -r $b_pdot ]] || fail "$b_pdot: not readable"
fi
if [[ -f $b_local_nt ]]; then
[[ -r $b_local_nt ]] || fail "$b_local_nt: not readable"
fi
if [[ -f $b_not_files ]]; then
[[ -r $b_not_files ]] || fail "$b_not_files: not readable"
fi
if [[ -f $b_sort ]]; then
[[ -r $b_sort ]] || fail "$b_sort: not readable"
fi
#
# If something goes wrong, we need to make sure they notice, so
# we make the message quite visible, and echo a BELL.
#
fail_msg='Extraction failed.
*DANGER* *DANGER* workspace could be corrupted *DANGER* *DANGER*'
cp $b_renamed $wxdir/renamed || fail "$wxdir/renamed: $fail_msg"
cp $b_new $wxdir/new || fail "$wxdir/new: $fail_msg"
cp $b_active $wxdir/active || fail "$wxdir/active: $fail_msg"
cp $b_local_nt $wxdir/local_nametable ||
fail "$wxdir/local_nametable: $fail_msg"
if [[ -n $b_sort ]]; then
cp $b_sort $wxdir/sort_active || \
fail "$wxdir/sort_active: $fail_msg"
fi
# Need to move active files that are renamed in current ws back to
# their name in the active list to avoid two copies of the file
# occuring when the clear files are restored below.
wx_do_renames $wxdir/local_nametable ||
fail "$wxdir/local_nametable: $fail_msg"
if [[ -n $b_not_files ]]; then
tar -xf $b_not_files || fail "$wx/*.NOT: $fail_msg"
fi
# It's not an error if there is no clear backup.
if [[ -f $b_clear ]]; then
wx_do_restore "clear" $b_clear "$comp" ||
fail "$b_clear: $fail_msg"
fi
# It's not an error if there is no sdot backup.
if [[ -f $b_sdot ]]; then
wx_do_restore "sdot" $b_sdot "$comp" ||
fail "$b_sdot: $fail_msg"
fi
# It's not an error if there is no pdot backup.
if [[ -f $b_pdot ]]; then
wx_do_restore "pdot" $b_pdot "$comp" ||
fail "$b_pdot: $fail_msg"
fi
# Do some integrity checking
for filepath in $(wx_active); do
if cd ${workspace}/$(dirname $filepath); then
file=$(basename $filepath)
# If file is not writable then assume the
# SCCS/p.file is bogus. This can happen if a
# file is checked out and a wx restore is done
# and the restored file was not checked out when
# it was backed up.
if [[ ! -w $file && -f SCCS/p.$file ]]; then
ring_bell
cat <<-EOF
Warning! $filepath is in inconsistent state.
$filepath is not writable and SCCS/p.$file exists.
Removing SCCS/p.$file
To edit the file run '$ME edit $filepath'
EOF
rm -f SCCS/p.$file
elif [[ -w $file && ! -f SCCS/p.$file ]]; then
ring_bell
cat <<-EOF
Warning! $filepath is in inconsistent state.
$filepath is writable
but there is no SCCS/p.$file
EOF
yesno "Should this file be checked out?"
if [[ "$answer" == 'yes' ]]; then
if mv $file $wxtmp; then
if sccs edit $file; then
update_active $filepath
fi
mv -f $wxtmp/$file $file
fi
else
ask_remove_active_entry
echo "Setting $filepath read only"
chmod ugo-w $file
fi
fi
else
ring_bell
echo "\nWarning! Could not check sccs state of "\
"$filepath"
fi
done
}
wx_fullreview() {
if wx_pnt_filepath; then
:
else
parentfilepath=/dev/null
fi
if $show_comments && wx_show_comment > $wxdir/comment; then
comm=-y"`cat $wxdir/comment`"
codereview "$comm" $args $parentfilepath $workspace/$filepath
else
codereview $args $parentfilepath $workspace/$filepath
fi
}
#
# Check on RTI status for bug ID's found in active list comments.
#
rtichk() {
typeset bug bugs[] rtidir rtifile suffix rtitype='MarketingRelease'
typeset rtibug rti project release state gatetype='MarketingRelease'
# gate contains the gate dir, not full path
typeset gate=${parent##*/} usewebrti='false'
typeset webrticli=$(whence webrticli 2>/dev/null)
typeset -i i j rc=0 warnhdr=0
typeset nolookup opt
if [[ -f $wxdir/rtichk.NOT ]]; then
print "\nSkipping RTI check:"
return
else
print "\nDoing RTI check:"
fi
while getopts :N opt; do
case $opt in
N) nolookup='-N' ;;
*) fail "Invalid flag -$OPTARG." ;;
esac
done
# Is the parent a patch gate?
if [[ $parent == *-patch* ]]; then
rtitype='Patch'
suffix='P'
RTIDIRS=$PRTIDIRS
gatetype='Patch'
fi
# Is the parent a test gate?
if [[ $parent == *-stc2 || $parent == *-test ]]; then
rtitype='RTI'
gatetype='RTI'
fi
# Use new RTI query tool if there's a gate and there is an
# executable webrticli.
# Note, webrticli needs a gate arg to correctly determine status.
if [[ -z $gate ]]; then
cat >&2 <<-EOF
Warning: cannot find a parent gate, skipping webrticli checking. Will
check RTI status using old style checking...
EOF
else
if [[ -z $webrticli ]]; then
# if webrticli isn't in the PATH, try default path
webrticli=/net/webrti.sfbay/export/home/bin/webrticli
fi
if [[ -x $webrticli ]]; then
usewebrti='true'
else
cat >&2 <<-EOF
Warning: cannot find webrticli, skipping webrticli checking. Will check
RTI status using old style checking...
EOF
fi
fi
# Use wx_summary to output bug ID's in active list comments,
# redirecting warnings about non-bug ID's to file for later use.
set -A bugs $(wx_summary -ao $nolookup 2>$wxtmp/bugwarnings|cut -f1 -d' ')
((i = 0)) # init bugs array index
for bug in ${bugs[@]}; do
if [[ $bug == 'accept' ]]; then
# skip this bug since it's accepted.
# Increment bugs[] index.
((i = i + 1))
continue
fi
if $usewebrti; then
# try new RTI query interface
$webrticli -g $gate RTIstatus $bug > $wxtmp/webrticli.out 2>&1
rc=$?
case $rc in
0) if [[ $(wc -l < $wxtmp/webrticli.out) -ne 1 ]]; then
# paranoid: should only have 1 line
cat <<-EOF
Warning: for bug $bug the RTI status can not be determined using webrtcli.
Please contact the gatekeeper. The output of webrtcli is:
EOF
cat $wxtmp/webrticli.out
else
IFS=':' read rtibug rti project \
release state rtitype \
< $wxtmp/webrticli.out
if [[ $gatetype != $rtitype ]]; then
cat <<-EOF
Warning: for bug $bug the RTI $rti is a $rtitype type but the parent gate
$gate is a $gatetype gate. A $gatetype RTI must be submitted to putback
bug $bug to $gate.
EOF
elif [[ $state == 'S_ACCEPTED' ]]; then
# found accepted bug
bugs[i]='accept'
fi
fi
# skip old-style checking
((i = i + 1))
continue ;;
1) # Serious system related problem has occured
cat <<-EOF
Warning: for bug $bug the RTI status can not be determined using webrtcli.
Please contact the gatekeeper. The output of webrtcli is:
EOF
cat $wxtmp/webrticli.out
# skip old-style checking
((i = i + 1))
continue ;;
5) # Incorrect gate name specified.
# See if bug can be found at all.
$webrticli RTIstatus $bug > /dev/null 2>&1
if [[ $? -ne 3 ]]; then
# If the return is something
# other than the CR
# can't be found (3), issue
# a warning.
cat <<-EOF
Warning: for bug $bug webrticli was unable to map current parent gate $gate
to a RTI release. Please contact the gatekeeper. The output of webrtcli is:
EOF
cat $wxtmp/webrticli.out
# skip old-style checking
((i = i + 1))
continue
fi ;;
# Dealing with other error codes is
# tricky because the user may be using
# the old school rtitool and we don't
# want to needlessly warn.
esac
fi # end if $usewebrti
# If bug wasn't found above then fall back to old school rti lookup...
# XXX if it is determined at some point that everyone is
# using the new web RTI tool then the fallback code can
# be removed.
# Old style RTI lookup...
# See if there is an accepted rti (the filename indicates state)
for rtidir in $RTIDIRS; do
# make sure the rti dir is mounted
ls -d $rtidir >/dev/null
if [[ ! (-d $rtidir && -r $rtidir) ]]; then
cat <<-EOF
Warning: cannot check status of RTI's. Check with the gatekeepers to see why
$rtidir
is not accessible.
EOF
return 1
fi
rtifile="${rtidir}/${suffix}${bug}.accept"
if [[ -f "$rtifile" ]]; then
# This bug was accepted since the
# rtifile exists
bugs[i]='accept'
((j = 0))
while (( j < ${#bugs[@]} )); do
# Let's see if any other bugs
# were accepted in the rti file
if [[ ${bugs[j]} != 'accept' ]] &&
grep -q "^${bugs[j]} " $rtifile
then
bugs[j]='accept'
fi
((j = j + 1))
done # while [[ j -lt ${#bugs[@]} ]]
# stop checking in rtidirs and go to next bug
break
fi # if [[ -f "$rtifile" ]]
done # rtidir in set of rtidirs
# Increment bugs[] index.
((i = i + 1))
done # for bug in ${bugs[@]}
for bug in ${bugs[@]}; do
if [[ $bug != 'accept' ]]; then
if [[ $warnhdr -ne 1 ]]; then
cat <<-EOF
Warning: there doesn't seem to be an approved $rtitype RTI for the
following bug IDs listed in your active list comments (see '$ME bugs').
Make sure your $rtitype RTI is approved before putting back to an
official ON gate (hint, use either <http://webrti.sfbay> or 'rtitool'
depending on the project to submit an $rtitype RTI):
EOF
((warnhdr = 1))
# set return code to indicate problem
[[ $rc -eq 0 ]] && ((rc = 1))
fi
print $bug
fi
done
if [[ -s $wxtmp/bugwarnings ]]; then
cat <<-EOF
There are issues with the bug ID format in the
$wxdir/active file.
Please fix the following and run rtichk again:
EOF
cat $wxtmp/bugwarnings
((rc = 1))
fi
if [[ $i -eq 0 ]]; then
print "\nWarning: no bug ID's in active list."
fi
return $rc
}
#
# Do a Teamware putback of active and renamed files.
#
wx_putback() {
# Use pbargs array to store Teamware putback args.
# verbatim is for -v verbatim flag which doesn't get passed to
# putback.
typeset i verbatim pbargs[] pbfiles narg=false force=false
typeset nolookup=false
if $FILES_PASSED; then
# use the user specified files
pbfiles=$file_list
else
# use the pblist (active and renamed)
pbfiles=$(wx_active -p)
fi
while getopts :fnp:qvN i; do
case $i in
# Force the putback (no user interaction)
f) force=true;;
n) narg=true
pbargs[${#pbargs[@]}]="-$i" ;;
q) pbargs[${#pbargs[@]}]="-$i" ;;
p) pbargs[${#pbargs[@]}]="-$i"
pbargs[${#pbargs[@]}]="$OPTARG"
# setting parent for user prompt below
parent="$OPTARG" ;;
# -v doesn't get passed to putback.
v) verbatim='-v';;
N) nolookup='-N';;
*) fail "Invalid flag -$OPTARG. See 'wx help'"\
"for more info.";;
esac
done
if ! $narg; then
# real putback
# get pb comments, will be used later.
if ! wx_summary -p $verbatim $nolookup >$wxtmp/pb_comments; then
# Fail if comments have problems.
fail "\nError, improper comments found. Use -v"\
"to bypass this check."
fi
if ! $force; then
# not force so give more warning.
( # using subshell to capture stdout to file.
cat <<-EOF
Remember to run '$ME pbchk' before doing a final putback (esp. if
doing a putback to an official ON gate). Make sure your workspace
parent ($parent) is correct.
It's a good idea to check your code diffs before putback ('$ME pdiffs').
Also, run '$ME $command -n' and check for conflicts before doing the
final putback.
EOF
if [[ -z "$(wx_summary -bo 2>/dev/null)" ]]; then
cat <<-EOF
Don't forget the ARC ID info in your active list comments if there is an
ARC case associated with your putback.
EOF
fi
echo "\nThe putback comment will be:"
cat $wxtmp/pb_comments
print "========== End of putback comments ======="
# Output warning if RTI isn't approved.
rtichk $nolookup
print "========== End of RTI check output ======="
cat <<-EOF
The following files will be used for putback:
$pbfiles
EOF
) | ${PAGER:-more}
ok_to_proceed "Do you really want to"\
"'$PUTBACK ${pbargs[@]}' to $parent?"
fi
fi
# Do the putback, passing in active list comments if required.
# putback both active and renamed/deleted files.
cd $workspace
if $narg; then
# Don't use putback comment if -n is given (trial putback)
$PUTBACK "${pbargs[@]}" $pbfiles
else
# feed active list comments into real putback
wx_summary $verbatim $nolookup |$PUTBACK "${pbargs[@]}" $pbfiles
fi
return
}
outchk() {
# List files that are checked out but not in active list.
typeset outfile do_header=true
wx_checked_out >/dev/null
# if $wxtmp/checked_out is 0 bytes then return
[[ -s $wxtmp/checked_out ]] || return
sort $wxtmp/checked_out > $wxtmp/co_sort
wx_active | sort > $wxtmp/active_sort
for outfile in $(comm -12 $wxtmp/active_sort $wxtmp/co_sort); do
if $do_header; then
echo "\nWarning, the following active list files are"\
"checked out:"
do_header=false
fi
echo "$outfile"
done
do_header=true
for outfile in $(comm -13 $wxtmp/active_sort $wxtmp/co_sort); do
if $do_header; then
cat <<-EOF
Warning, the following files are checked out but not in active list
(Run "$ME update -q" to add them to the active list):
EOF
do_header=false
fi
echo "$outfile"
done
rm -f $wxtmp/co_sort $wxtmp/active_sort
}
#
# run Teamware resolve and do reedit only on merged files.
#
wx_resolve() {
typeset merged_file
# clear the file_list, will be set below
file_list=
grep -v '^VERSION ' $wsdata/conflicts > $wxtmp/conflicts
[[ ! -f $wxtmp/conflicts ]] && fail "Error: cannot create $wxtmp/conflicts"
# run Teamware resolve
resolve $* || fail "Teamware resolve failed."
# resolve will remove files from $wsdata/conflicts when
# successfully merged.
# set file_list to files that were merged.
for merged_file in $(cat $wxtmp/conflicts); do
if ! grep -q '^'"$(escape_re $merged_file)"'$' \
$wsdata/conflicts; then
# set file_list for wx_eval later.
file_list="$file_list $merged_file"
fi
done
if [[ -n $file_list ]]; then
ok_to_proceed "Re-edit merged files to collapse merge deltas?"
echo "Re-editing merged files"
echo
wx_eval wx_reedit_file
echo
echo "Re-edit complete"
echo
else
echo "No merged files to re-edit."
fi
}
#########################################################################
#
# Main
#
#
# Do some initial sanity checking and set up.
#
# Set the lang to standard English so wx doesn't get confused.
export LC_ALL=C
# Turn on debugging output early
if echo "$*"|/usr/xpg4/bin/grep -q -E ' -D( *$| )'; then
typeset -ft $(typeset +f)
set -x
fi
ME=$(basename $0)
export ME
if [[ -d /usr/xpg4/bin ]]; then
# Want to use xpg4 versions of fgrep and grep
PATH=/usr/xpg4/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH
else
fail "Error: directory /usr/xpg4/bin not found."
fi
unset CDPATH # if set "cd" will print the new directory on stdout
# which screws up wx_eval.
DEFAULT_SRCDIR=usr
if [[ $# -eq 0 || "$1" == help ]]; then
# output usage now to avoid unnecessary checking below.
wx_usage
fi
if [[ "$1" == version ]]; then
# output version now to avoid unnecessary checking below.
version
exit 0
fi
whence workspace >/dev/null || fail "Error: cannot find workspace command in \$PATH."
# Note, PUTBACK can be set to "cm_env -g -o putback" to use Casper Dik's
# turbo-dir.flp scripts to speed up thorough updates.
PUTBACK=${PUTBACK:='putback'}
BRINGOVER=${BRINGOVER:='bringover'}
dot=$PWD
if [[ -n "$CODEMGR_WS" ]]; then
# ws was used.
# normalize the workspace name.
workspace=$(cd $CODEMGR_WS && workspace name)
# If the current dir is in a workspace check that it is the same
# as CODEMGR_WS.
if [[ -n "$(workspace name)" ]]; then
if ! echo "$(/bin/pwd)/" | grep -q "^$workspace/"; then
cat <<-EOF
Warning, $ME will use $ME files in workspace $workspace (the current
directory is not in this workspace).
EOF
ok_to_proceed "Okay to proceed?"
fi
fi
else
# If current dir is in a workspace then use output of workspace
# name as current ws.
workspace=$(workspace name)
if [[ -n "$workspace" ]]; then
CODEMGR_WS=$workspace
export CODEMGR_WS
fi
fi
[[ -z "$workspace" ]] &&
fail "No active workspace, run \"ws <workspace>\" or"\
"\"cd <workspace>\"."
workspace_basename=`basename $workspace`
wxdir=${WXDIR:-$workspace/wx}
wxtmp=$wxdir/tmp
wsdata=$workspace/Codemgr_wsdata
node=`uname -n`
if [ -f $wsdata/parent ]; then
parent=`tail -1 $wsdata/parent`
else
parent=
fi
if [[ $parent == *:* ]]; then
parentdir=${parent#*:}
parentnode=${parent%%:*}
if [[ $parentnode == $node ]]; then
parent=$parentdir
else
parent=/net/$parentnode$parentdir
fi
fi
# Store backup state
backup_done=0
# store state if new files are deleted
NEED_WS_CLEAN='n'
# XXX doing this because keywords doesn't work on new files
# Note doing the echo so the tabs are apparent
SCCSKEYWORD=$(echo "ident\t+\"(\%\Z\%\%\M\%\t+\%\I\%|\%W\%)\t+\%\E\% SMI\"")
# file that contains comments for use in create and checkin
comment_file=
# mode for updating comments in active list
comment_mode="replace"
CSTYLE_FLAGS=${CSTYLE_FLAGS:='-P -p'}
JSTYLE_FLAGS=${JSTYLE_FLAGS:='-p'}
BACKUP_ERRORS=/tmp/${ME}_berrors_$(/usr/xpg4/bin/id -un)_$$
# global for reedit command, don't checkin by default
CHECKIN=false
# Indicates that the parent nametable cache needs refreshing
need_pnt_refresh=true
# Indicate whether file args were specified
FILES_PASSED=false
# Used to store files that have more than one delta compared to parent
multi_delta_list=
# Used to bringover any files just before exit of wx
bofilelist=
# should codereviews include delta comments?
show_comments=true
# Determines if active list should be sorted by default
# If sort_active contains true then we sort the active list on updates.
if [[ -r $wxdir/sort_active && "$(cat $wxdir/sort_active)" == "true" ]]; then
ACTSORT=sort
else
ACTSORT=cat
fi
# These are set depending on what needs sorting
do_renamed_sort=false
do_active_sort=false
# Places to search for approved RTIs
RTIDIRS="/net/wizard.eng/export/consolidation/rtiroute/newrtis
/net/wizard.eng/export/consolidation/rtiroute/oldrtis
/net/onstc.eng/export/stc/Rtitool/consolidation/rtiroute/newrtis
/net/onstc.eng/export/stc/Rtitool/consolidation/rtiroute/oldrtis"
# Places to search for approved Patch RTIs
PRTIDIRS="/net/wizard.eng/export/consolidation/rtiroute/newprtis
/net/wizard.eng/export/consolidation/rtiroute/oldprtis"
export workspace parent wxdir file dir filepath backup_done DEFAULT_SRCDIR
#
# main section
#
# Get wx command
command=$1
comlist=$command
shift
case $command in
apply|eval) subcommand=$1; shift;;
grep|egrep|sed|nawk) pattern=$1; shift;;
nits) comlist="cstyle jstyle hdrchk copyright cddlchk keywords";
echo "Note, nits is a subset of pbchk checks.";;
pbchk) comlist="cstyle jstyle hdrchk copyright cddlchk keywords"
comlist="$comlist rmdelchk deltachk comchk rtichk outchk";;
esac
orig_args="$@"
silent=
args=
file_list=
typeset tmp_file_list tmp_args
#
# Some subcommands pass through all arguments.
#
case $command in
webrev) args="$orig_args"; shift $#;;
esac
# Parse args
while [ $# -gt 0 ]; do
case $1 in
-c|-C)
if [[ $command == @(delget|checkin|ci|create) ]]; then
# set global comment_file
[[ "$1" == "-C" ]] && comment_mode="append"
comment_file=$2;
if ! echo $comment_file|grep -q '^/'; then
comment_file="$(pwd)/$comment_file"
fi
if [[ -z "$comment_file" ]]; then
fail "Missing comment file."\
"Run 'wx help' for info."
fi
[[ ! -r "$comment_file" ]] &&
fail "Can not read comment file"\
"$comment_file."
echo "Using comment file $comment_file"\
"for comments."
# shift past the comment_file arg
shift
elif [[ $1 == '-C' && $command == 'diffs' ||
$command == 'tdiffs' &&
-z $WXDIFFCMD ]]; then
if [[ $2 != +([0-9]) ]]; then
# provide default context value for
# compat with old wx
args="$args -C5"
else
args="$args -C$2"
# shift past context lines arg
shift
fi
else
args="$args $1"
fi;;
-D) : ;; # debug flag, already processed
-p) if [[ $command == @(putback|pb) ]]; then
if workspace access $2 >/dev/null; then
# 2nd arg is a workspace
args="$args $1 $2"
else
fail "$2 not a workspace."\
"Run 'wx help' for info."
fi
# shift past the parent ws arg
shift
else
# for other commands -p doesn't have a arg
args="$args $1"
fi;;
-r) if [[ $command == @(get|extract) ]]; then
# 2nd arg is the version #
args="$args $1 $2"
# shift past 2nd arg
shift
else
# for other commands -r doesn't have a arg
args="$args $1"
fi;;
-s) if [[ "$command" == @(update|init) ]]; then
args="$args $1"
else
silent=-s
fi;;
-N) if [[ "$command" == @(codereview|fullreview) ]]; then
show_comments=false
else
args="$args $1"
fi ;;
-*) args="$args $1";;
*) if [[ -z "$file_list" ]]; then
file_list="$1"
else
file_list="$file_list $1"
fi;;
esac
shift
done
if [[ "$command" == "init" ]]; then
if [ -z "$file_list" ]; then
file_list=$DEFAULT_SRCDIR
fi
wx_init $file_list $args
exit
fi
if [ ! -d $wxdir/tmp ]; then
echo "Workspace does not appear to be initialized for $ME."
echo "The initialization process will create a few files under"
echo "$wxdir but will not otherwise affect your workspace."
ok_to_proceed 'OK to proceed?'
ask "Where is the root of the source code in this workspace?" \
$DEFAULT_SRCDIR
# wx_init modifies file_list so save current value
tmp_file_list=$file_list
file_list=
# save off args and set to null to avoid side effects
tmp_args=$args
args=
wx_init $answer
# restore original file list and cd to original dir in case there's
# a command to execute.
file_list=$tmp_file_list
args=$tmp_args
cd $dot
fi
if [[ ! -f $wxdir/local_nametable ]]; then
touch $wxdir/local_nametable
fi
# Doing this for backward compat since old wx doesn't have a renamed list
if [[ ! -f $wxdir/renamed ]]; then
# if 'wx update' or 'wx update -r' is the command then skip
# renamed list creation since it will happen anyway.
if [[ "$command" != "update" ]] || echo "$args"|grep -q -- "-q"; then
ring_bell
cat <<-EOF
$ME needs to create a renamed file list. If you are sure that no files
were renamed or deleted in the current workspace then answer no to the
following question.
EOF
yesno "Okay to search for renamed files (can be slow)?"
if [[ "$answer" == "yes" ]]
then
wx_update -r
else
touch $wxdir/renamed
fi
fi
fi
# Doing this for backward compat since old wx doesn't have a new list
if [[ ! -f $wxdir/new ]]; then
ring_bell
cat <<-EOF
$ME needs to create a new-file list (cache names of newly created
files). Please be patient.
EOF
# Avoid a putback -n which is slow, just use lookup_parent()
touch $wxdir/new || fail "Error: cannot create $wxdir/new list"
wx_active |
while read filepath; do
if ! lookup_parent $filepath; then
add_new $filepath
fi
done
echo "\nNew files:"
cat $wxdir/new
echo
fi
if [[ "$command" == @(restore|backup|bu) ]]; then
# If the backup dir was specified as a file arg...
if [ -n "$file_list" ]; then
backup_dir=$(echo "$file_list"|cut -f1 -d' ')
fi
# unset file_list since this file arg has been processed here.
unset file_list
elif [[ "$command" == "ea" ]]; then
# Do this command before wx_active is run because the active list
# may be corrupt.
cd $wxdir
exec ${EDITOR-vi} active
elif [[ "$command" == @(unedit|uncheckout|unco) ]]; then
if [[ -z "$file_list" && $args != *-f ]]; then
echo "$ME will $command all active files which may remove"\
"them from the active list."
ok_to_proceed 'Do you REALLY want to do this?'
fi
cp $wxdir/active $wxdir/active.old
elif [[ "$command" == @(bugs|arcs) ]]; then
# -v verbatim is not valid for these commands
if echo "$args"|grep -q -- "-v"; then
fail "Invalid flag -v. Run 'wx help' for info."
fi
elif [[ "$command" == "create" ]]; then
if [ -z "$file_list" ]; then
fail "$command missing file arg(s). Run 'wx help' for info."
fi
cp $wxdir/active $wxdir/active.old ||
fail "Error could not backup $wxdir/active"
elif [[ "$command" == @(delget|checkin|ci) && -n "$comment_file" ]]; then
cp $wxdir/active $wxdir/active.old ||
fail "Error could not backup $wxdir/active"
elif [[ "$command" == @(mv) ]]; then
if [[ $(echo "$file_list"|wc -w) -ne 2 ]]; then
fail "$command requires two args. Run 'wx help' for info."
fi
cp $wxdir/active $wxdir/active.old ||
fail "Error could not backup $wxdir/active"
cp $wxdir/renamed $wxdir/renamed.old ||
fail "Error could not backup $wxdir/renamed"
elif [[ "$command" == @(delete|rm) ]]; then
if [ -z "$file_list" ]; then
echo "$ME will try to delete all active files which may "\
"remove them from the active list."
ok_to_proceed 'Do you REALLY want to do this?'
fi
cp $wxdir/active $wxdir/active.old ||
fail "Error: could not backup $wxdir/active"
cp $wxdir/renamed $wxdir/renamed.old ||
fail "Error: could not backup $wxdir/renamed"
elif [[ "$command" == reset ]]; then
cp $wsdata/nametable $wxtmp/nametable.orig || \
fail "Error: cp $wsdata/nametable $wxtmp/nametable.orig failed."
fi
if [ -z "$file_list" ]; then
basedir=$workspace
file_list=$(wx_active) || fail
else
base_file_list=$file_list
file_list=
for basefile in $base_file_list; do
# normalize the filepaths
if [[ -d $basefile ]]; then
basedir=$(cd $basefile && /bin/pwd)
abspath=$basedir
else
basedir=$(cd $(dirname $basefile) && /bin/pwd)
abspath=$basedir/$(basename $basefile)
fi
if [[ ! -d $basedir ]]; then
fail "Error: Path to $basefile does not exist."
elif [[ $(cd $basedir; workspace name) != $workspace ]]; then
fail "Error: $basefile isn't in current workspace: $workspace."
fi
filepath=${abspath##$workspace/}
if [[ -z "$file_list" ]]; then
file_list="$filepath"
else
file_list="$file_list $filepath"
fi
done
FILES_PASSED=true
fi
if [[ "$command" == @(nits|pbchk) ]]; then
tmp_list=
# skip nits/pbchk checks for files listed in $command.NOT
if [[ -f $wxdir/${command}.NOT ]]; then
for _a_file in $file_list; do
if grep -q "^$(escape_re $_a_file)$" \
$wxdir/${command}.NOT
then
echo "skipping $command checks for "\
"$_a_file (skipping)"
else
tmp_list="$tmp_list $_a_file"
fi
done
file_list=${tmp_list# }
fi
[[ -z $file_list ]] && exit 0
fi
# This is where the commands are executed.
for command in $comlist; do
cd $dot
case $command in
list|active) wx_active $args ;;
pblist) wx_active -p;;
renamed) list_renamed $args ;;
new) list_new $args;;
update) wx_update $args;;
out) wx_checked_out; cat $wxtmp/checked_out;;
diffs) wx_eval -r 'print -- "\n------- $filepath -------\n";
sccs get -s -p -k $filepath |
${WXDIFFCMD:-diff} $args - $filepath';;
tdiffs) ## As diffs but also shows new files.
if [[ -r $wxdir/new ]]; then
## Read names of new files into space separated list.
while read new_file
do
new_files="${new_files}${new_file} "
done < $wxdir/new
else
new_files=""
fi
## For new files a comparison is made with /dev/null thus
## all lines will appear to have been added.
wx_eval -r 'print -- "\n------- $filepath -------\n";
if [[ ${new_files} == *"${filepath} "* ]]; then
${WXDIFFCMD:-diff} $args /dev/null $filepath;
else
sccs get -s -p -k $filepath |
${WXDIFFCMD:-diff} $args - $filepath;
fi';;
pdiffs|tpdiffs)
## Parent Diffs - Compare with parent file. For
## 'tpdiffs' when the parent file does not exist the
## child file is assumed new and compared to
## /dev/null; thus all lines will appear to have been
## added.
wx_eval '
print -- "\n------- $filepath -------\n";
if wx_pnt_filepath; then
echo "Index: $filepath";
${WXDIFFCMD:-diff} $args $parentfilepath
$workspace/$filepath;
elif [[ $command == 'tpdiffs' ]]; then
${WXDIFFCMD:-diff} $args /dev/null
$workspace/$filepath;
else
print "New file (does not exist in parent).";
fi';;
pvi) wx_eval '
echo $filepath;
if wx_pnt_filepath; then
${EDITOR-vi} $args $parentfilepath;
else
echo "New file (does not exist in parent)";
fi';;
edit|checkout|co) wx_eval wx_edit;;
unedit|uncheckout|unco) wx_eval wx_unedit;;
create) wx_eval wx_create $args;;
uncreate) wx_eval wx_uncreate $args;;
delete|rm) wx_eval wx_delete $args;;
mv) wx_mv $file_list;;
delget|checkin|ci) wx_eval wx_delget $args;;
get|extract) wx_eval wx_get;;
reset) wx_eval wx_reset $args;;
putback|pb) wx_putback $args;;
resolve) wx_resolve $args;;
prt) wx_eval 'sccs prt $args $file';;
comments) wx_eval 'echo $filepath; echo; wx_show_comment; echo';;
bugs) wx_summary -ao $args;;
arcs) wx_summary -bo $args;;
pbcom) wx_summary -po $args;;
info) wx_eval wx_info;;
reedit|recheckout|reco) wx_reedit $args;;
redelget|recheckin|reci) CHECKIN=true; wx_reedit $args;;
cstyle) echo "\nDoing cstyle check:"
rm -f $wxtmp/wx.cstyle.*;
export CSTYLE_INDEX=0;
wx_eval wx_cstyle;
wait;
sort -k 1,1 -k 2,2n $wxtmp/wx.cstyle.* 2> /dev/null
;;
jstyle) echo "\nDoing jstyle check:"
rm -f $wxtmp/wx.jstyle.*;
export JSTYLE_INDEX=0;
wx_eval wx_jstyle;
wait;
sort -k 1,1 -k 2,2n $wxtmp/wx.jstyle.* 2> /dev/null
;;
hdrchk) echo "\nDoing header format check:";
cd $workspace;
hdrchk_files=;
for filepath in $file_list ; do
if echo $filepath | grep -q '\.h$'; then
if [[ -s $wxdir/${command}.NOT ]] &&
grep -q "^$(escape_re $filepath)$" \
$wxdir/${command}.NOT
then
echo "$filepath (skipping)"
else
hdrchk_files="$hdrchk_files $filepath"
fi
fi
done
hdrchk -a $args $hdrchk_files ;;
makestyle) echo "\nDoing makestyle check:";
cd $workspace; mlist=$(wx_active | grep '[Mm]akefile');
[[ -n "$mlist" ]] && makestyle $args $mlist;;
keywords)
echo "\nDoing keywords check:";
cd $workspace;
keyword_files=;
for filepath in $file_list ; do
if [[ -s $wxdir/${command}.NOT ]] &&
grep -q "^$(escape_re $filepath)$" \
$wxdir/${command}.NOT
then
echo "$filepath (skipping)"
else
keyword_files="$keyword_files $filepath"
fi
done
keywords -p $args $keyword_files;;
rmdelchk) echo "\nDoing sccs rmdel check:"; wx_eval rmdelchk;;
rtichk) rtichk;;
deltachk) echo "\nDoing multi delta check:"; wx_eval deltachk;;
copyright) echo "\nDoing copyright check:"; wx_eval wx_copyright;;
cddlchk)
echo "\nDoing CDDL block check:";
cd $workspace;
cddlnot="";
if [[ -s $wxdir/${command}.NOT ]]; then
cddlnot="-x $wxdir/${command}.NOT"
fi
#
# Split the file list into new files and existing files.
# New files must have a CDDL block whereas existing files don't
# necessarily have to have a block, but if they do it must be
# valid. Both sets of files are subject to cddlchk.NOT
# exception processing.
#
old=""
new=""
for filepath in $file_list; do
if wx_pnt_filepath $filepath; then
old="$old $filepath"
else
new="$new $filepath"
fi
done
[[ ! -z $new ]] && cddlchk $cddlnot $args -a $new
[[ ! -z $old ]] && cddlchk $cddlnot $args $old
;;
comchk) echo "\nDoing comments check:"; wx_summary -n 2>&1;;
outchk) echo "\nDoing out check:"; outchk;;
backup|bu) wx_backup $args;;
restore) wx_restore $args;;
apply) wx_eval "$subcommand \$file";;
eval) wx_eval "$subcommand";;
grep|egrep)
wx_eval '
if egrep -s '\'$pattern\'' $file;
then
echo $filepath;
$command $args '\'$pattern\'' $file;
fi';;
nawk|sed)
wx_eval 'echo $filepath; $command $args '\'$pattern\'' $file';;
codereview) args="-e $args"; wx_eval wx_fullreview;;
fullreview) wx_eval wx_fullreview;;
webrev) wx_webrev $args;;
dir) echo $wxdir;;
e) cd $wxdir; exec ${EDITOR-vi} $orig_args;;
ws) cd $wsdata; cat $orig_args;;
args) cat $wsdata/args;;
access) cat $wsdata/access_control;;
*) ring_bell;
echo "Command not found. Run 'wx help' for command list.";
exit 1;;
esac
done
if [[ $NEED_WS_CLEAN == 'y' ]]; then
# clean up the nametable
print -u2 "Running workspace updatenames to clean up nametable, may"\
"take a while."
workspace updatenames >&2
fi
if [[ -n $bofilelist ]]; then
$BRINGOVER $bofilelist
fi
# save sorting for last for some speed up.
if [[ $ACTSORT == sort ]]; then
if $do_renamed_sort; then
sort_renamed
fi
if $do_active_sort; then
sort_active
fi
fi