1057 lines
24 KiB
Bash
Executable File
1057 lines
24 KiB
Bash
Executable File
#! /usr/local/bin/bash
|
|
#
|
|
# neartool - a Clearcase emulator for working off-line.
|
|
#
|
|
# Usage:
|
|
#
|
|
# neartool mkelem [-c "comment"] [-nc] [-eltype type] filename
|
|
# Marks a new file as a versioned element and checks it out.
|
|
#
|
|
# neartool mkdir [-c "comment"] [-nc] new_dir
|
|
# Creates a new Clearcase directory.
|
|
#
|
|
# neartool mv old-file new-file
|
|
# Renames or moves a versioned element.
|
|
#
|
|
# neartool mv file1 file2 file3 ... to-dir
|
|
# Moves a number of versioned elements into a new directory.
|
|
#
|
|
# neartool (co|checkout) [-c "comment"] [-nc] filename
|
|
# "checks out" a file by saving its current version and making a new
|
|
# version writable. The file is also marked as "checked-out".
|
|
#
|
|
# neartool (unco|uncheckout) filename
|
|
# Reverses the effect of the previous checkout.
|
|
#
|
|
# neartool (ci|checkin) [-c "comment"] [-nc] filename
|
|
# Marks the file as "checked in" and finalizes its most recent
|
|
# version, making it read-only.
|
|
#
|
|
# neartool revert filename
|
|
# Backs up a version on a checked-in filename.
|
|
#
|
|
# neartool revertall filename
|
|
# Reverts a filename all the way to its original state as extracted
|
|
# from the Clearcase vobs.
|
|
#
|
|
# neartool collapse filename
|
|
# Collapse all versioning information and mark the file as
|
|
# "checked-in" and merged as is. Presumably this should only be
|
|
# done after merging the changes back into the actual clearcase
|
|
# vobs.
|
|
#
|
|
# neartool rmname filename
|
|
# Removes a filename from a Clearcase directory.
|
|
#
|
|
# neartool find root [opts]
|
|
# Finds all elements with versions at root or below. The options
|
|
# are ignored. This is just a hack to support ctihave.
|
|
#
|
|
# neartool (lsco|lscheckout) [-l] file1 file2 file3...
|
|
# Lists which of the files are currently checked out, if any. If no
|
|
# filenames are given, lists all of the checked out files in the
|
|
# current directory. The -l option is ignored.
|
|
#
|
|
# neartool diff [-pre] filename
|
|
# Performs a diff between the indicated filename and its previous
|
|
# version. The option -pre is ignored.
|
|
#
|
|
# neartool xdiff [-pre] filename
|
|
# Performs an xdiff between the indicated filename and its previous
|
|
# version. The option -pre is ignored.
|
|
#
|
|
#ENDCOMMENT
|
|
|
|
|
|
#
|
|
# get_nth_param ( param-no param1 param2 param3 ... )
|
|
#
|
|
# Sets the variable nth_param to the value of the parameter
|
|
# corresponding to param-no.
|
|
#
|
|
function get_nth_param {
|
|
local param_no=$1
|
|
shift $param_no
|
|
nth_param=$1
|
|
}
|
|
|
|
#
|
|
# get_last_param ( param1 param2 param3 ... )
|
|
#
|
|
# Sets the variable last_param to the value of the last non-blank
|
|
# parameter.
|
|
#
|
|
function get_last_param {
|
|
last_param="$1"
|
|
shift
|
|
while [ ! -z "$*" ]; do
|
|
last_param="$1"
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# format_comment ( comment_str )
|
|
#
|
|
# Writes the parameter -c '$comment_str', or -nc if the comment is
|
|
# empty, to the standard output. Handles nested quotes appropriately.
|
|
#
|
|
function format_comment {
|
|
local comment="$*"
|
|
|
|
if [ -z "$comment" ]; then
|
|
echo "-nc"
|
|
else
|
|
# Escaping single quotes inside a single-quoted string doesn't
|
|
# seem to work too reliably. Instead, we'll just remove single
|
|
# quotes. So there.
|
|
|
|
# This absurd number of backslashes is needed to output a single
|
|
# backslash through all this nesting.
|
|
# echo "-c '"`echo $comment | sed "s/'/\\\\\\\\'/g"`"'"
|
|
echo "-c '"`echo $comment | sed "s/'//g"`"'"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# list_comments ( dirname basename )
|
|
#
|
|
# Writes to stdout any comments associated with checked-out versions of
|
|
# the indicated file, in order.
|
|
#
|
|
function list_comments {
|
|
local dirname=$1
|
|
local basename=$2
|
|
local filename=$dirname/$basename
|
|
local file comment version
|
|
|
|
if [ -f $dirname/.ct0.$basename ]; then
|
|
# Now look for comments, in version-number order.
|
|
|
|
# We use a series of ls commands so we don't try to sort the
|
|
# filenames between the one-, two-, and three-digit version
|
|
# numbers.
|
|
|
|
for file in `(cd $dirname; ls .ct[0-9].$basename; ls .ct[0-9][0-9].$basename; ls .ct[0-9][0-9][0-9].$basename) 2>/dev/null`; do
|
|
version=`echo $file | sed "s/^\.ct\([0-9]*\).*$/\1/"`
|
|
comment=$dirname/.ct${version}comment.$basename
|
|
if [ -f $comment ]; then
|
|
sed s'/^/ /' <$comment
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
#
|
|
# get_highest_version ( dirname basename )
|
|
#
|
|
# Sets the variable $version to the numeric value that is the highest
|
|
# existing version number defined for the given filename. If the
|
|
# filename has no previous version numbers, sets $version to -1.
|
|
#
|
|
function get_highest_version {
|
|
local dirname=$1
|
|
local basename=$2
|
|
local filename=$dirname/$basename
|
|
local last
|
|
|
|
if [ -f $dirname/.ct0.$basename ]; then
|
|
# If there are any versions at all, get the highest-numbered one
|
|
# and return it.
|
|
|
|
# We use a series of ls commands so we don't try to sort the
|
|
# filenames between the one-, two-, and three-digit version
|
|
# numbers.
|
|
|
|
last=`(cd $dirname; ls .ct[0-9].$basename; ls .ct[0-9][0-9].$basename; ls .ct[0-9][0-9][0-9].$basename) 2>/dev/null | tail -1`
|
|
version=`echo $last | sed "s/^\.ct\([0-9]*\).*$/\1/"`
|
|
else
|
|
# If there aren't any versions yet, the highest-numbered existing
|
|
# version number is -1.
|
|
version=-1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# is_ctinternal ( basename )
|
|
#
|
|
# Returns success if the filename matches one of the internal filenames
|
|
# generated by this script, failure if it is a perfectly ordinary
|
|
# non-ct file.
|
|
#
|
|
function is_ctinternal {
|
|
local basename=$1
|
|
|
|
case $basename in
|
|
.ct[0-9].*|ct[0-9][0-9].*|ct[0-9][0-9][0-9].*|\
|
|
.ct[0-9]comment.*|.ct[0-9][0-9]comment.*|.ct[0-9][0-9][0-9]comment*|\
|
|
.ctco.*|.ctnew.*)
|
|
return 0;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# is_install_dir ( dirname )
|
|
#
|
|
# Returns success if the directory is any of the directories known to
|
|
# be install directories, such as inc, lib, lib/ss, etc.
|
|
#
|
|
function is_install_dir {
|
|
local dirname=$1
|
|
|
|
get_rel_dir $projroot $dirname
|
|
|
|
case $rel_dir in
|
|
inc) return 0;;
|
|
inc/*) return 0;;
|
|
include/*) return 0;;
|
|
lib) return 0;;
|
|
lib/*) return 0;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# rm_all_ctinternals ( dirname basename )
|
|
#
|
|
# Removes all the ctinternal files associated with the indicated file.
|
|
#
|
|
function rm_all_ctinternals {
|
|
local dirname=$1
|
|
local basename=$2
|
|
|
|
rm -f $dirname/.ct[0-9].$basename
|
|
rm -f $dirname/.ct[0-9][0-9].$basename
|
|
rm -f $dirname/.ct[0-9][0-9][0-9].$basename
|
|
rm -f $dirname/.ct[0-9]comment.$basename
|
|
rm -f $dirname/.ct[0-9][0-9]comment.$basename
|
|
rm -f $dirname/.ct[0-9][0-9][0-9]comment.$basename
|
|
rm -f $dirname/.ctnew.$basename
|
|
rm -f $dirname/.ctco.$basename
|
|
}
|
|
|
|
#
|
|
# sane_filename ( dirname basename )
|
|
#
|
|
# Performs some sanity checks on the filename. If the file is
|
|
# unusable, exits the script with a status of 1.
|
|
#
|
|
function sane_filename {
|
|
local dirname=$1
|
|
local basename=$2
|
|
local filename=$dirname/$basename
|
|
|
|
if [ -z "$basename" ]; then
|
|
echo "Filename unspecified." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if is_ctinternal $basename; then
|
|
echo "$filename is an internal filename and should not be checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# It's easy to accidentally attempt to check something out from the
|
|
# inc directory. Let's detect this.
|
|
|
|
if is_install_dir $dirname; then
|
|
echo "$basename is in an install directory." 1>&2
|
|
echo "It should probably not be checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -d $filename ]; then
|
|
# Let's just quietly ignore directories. If we issue the warning
|
|
# statement, it makes ctaddtgt and ctaddpkg seem like they're
|
|
# failing.
|
|
# echo "Cannot operate on directories." 1>&2
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
#
|
|
# get_fullpath ( local_dir )
|
|
#
|
|
# Sets $fullpath to the fully-qualified pathname associated with $local_dir.
|
|
#
|
|
function get_fullpath {
|
|
local local_dir=$1
|
|
|
|
if [ -z "$local_dir" ]; then
|
|
fullpath=`pwd`
|
|
else
|
|
if [ ! -d "$local_dir" ]; then
|
|
echo "Invalid directory: $local_dir" 1>&2
|
|
exit 1
|
|
fi
|
|
# If we use pwd instead of /bin/pwd, $PWD will be used, which will give
|
|
# the wrong answer
|
|
fullpath=`(cd $local_dir; /bin/pwd)`
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# get_rel_dir ( root_dir local_dir )
|
|
#
|
|
# Sets $rel_dir to the string which represents $local_dir relative to
|
|
# $root_dir. This is a simple string-prefix operation, and could fail
|
|
# in some obscure cases.
|
|
#
|
|
function get_rel_dir {
|
|
get_fullpath $1
|
|
local root_dir=$fullpath
|
|
|
|
get_fullpath $2
|
|
local local_dir=$fullpath
|
|
|
|
# Now remove the initial prefix.
|
|
if [ "$root_dir" = "$local_dir" ]; then
|
|
rel_dir="."
|
|
else
|
|
rel_dir=`echo $local_dir | sed 's:^'$root_dir/'::'`
|
|
|
|
if [ "$rel_dir" = "$local_dir" ]; then
|
|
echo "$local_dir is not a directory within $root_dir." 1>&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function ctmkelem {
|
|
local filename dirname basename
|
|
local comment eltype
|
|
|
|
eltype=text_file
|
|
while getopts c:n:e: flag; do
|
|
case $flag in
|
|
c) comment="$OPTARG";;
|
|
n) comment="";;
|
|
e) case $OPTARG in
|
|
ltype) get_nth_param $OPTIND "$@"
|
|
eltype=$nth_param
|
|
OPTIND=`expr $OPTIND + 1`;;
|
|
*) echo Invalid switch -e$OPTARG
|
|
exit 1;
|
|
esac;;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ -f $ctco ]; then
|
|
echo "$filename is already checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f $filename ]; then
|
|
# If the file doesn't exist, create it.
|
|
echo -n "" >$filename
|
|
fi
|
|
|
|
get_highest_version $dirname $basename
|
|
|
|
if [ $version -ne -1 ]; then
|
|
echo "$filename already has versions." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -w $filename ]; then
|
|
echo "$filename has no write permission, it's probably already a versioned element." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Create a ctnew file to indicate the file is newly created.
|
|
ctnew=$dirname/.ctnew.$basename
|
|
echo $eltype >$ctnew
|
|
chmod uga-w $ctnew
|
|
|
|
# Now "check out" the new filename by creating an empty first version.
|
|
|
|
next=$dirname/.ct0.$basename
|
|
nextcomment=$dirname/.ct0comment.$basename
|
|
|
|
if [ ! -z "$comment" ]; then
|
|
echo $comment >$nextcomment
|
|
chmod uga-w $nextcomment
|
|
fi
|
|
echo -n "" > $next
|
|
|
|
date >$ctco
|
|
done
|
|
}
|
|
|
|
function ctmkdir {
|
|
local filename dirname basename
|
|
local comment
|
|
|
|
while getopts c:n: flag; do
|
|
case $flag in
|
|
c) comment="$OPTARG";;
|
|
n) comment="";;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
if [ -z "$basename" ]; then
|
|
echo "Filename unspecified." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if is_ctinternal $basename; then
|
|
echo "$filename is an internal filename and should not be checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if mkdir $filename; then
|
|
# The directory is successfully made; record this in the
|
|
# Clearcase instructions.
|
|
get_rel_dir $projroot $dirname
|
|
echo "ctco -nc $rel_dir" >>$projroot/.ctcmds
|
|
echo "ctmkdir `format_comment $comment` $rel_dir/$basename" >>$projroot/.ctcmds
|
|
else
|
|
echo "Unable to create directory $filename." 1>&2
|
|
fi
|
|
done
|
|
}
|
|
|
|
#
|
|
# do_ctmv ( oldname newname )
|
|
#
|
|
# The implementation of ctmv. This renames a single file, possibly
|
|
# placing it in a new directory.
|
|
#
|
|
function do_ctmv {
|
|
local oldfilename olddirname oldbasename
|
|
local newfilename newdirname newbasename
|
|
|
|
oldfilename=$1
|
|
olddirname=`dirname $oldfilename`
|
|
oldbasename=`basename $oldfilename`
|
|
|
|
newfilename=$2
|
|
newdirname=`dirname $newfilename`
|
|
newbasename=`basename $newfilename`
|
|
|
|
sane_filename $olddirname $oldbasename
|
|
sane_filename $newdirname $newbasename
|
|
|
|
if [ ! -f $oldfilename ]; then
|
|
echo "$oldfilename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -f $newfilename ]; then
|
|
echo "$newfilename already exists--remove it first." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
oldctnew=$olddirname/.ctnew.$oldfilename
|
|
|
|
if [ ! -f $oldctnew ]; then
|
|
# The filename exists on the actual Clearcase vobs. We need to
|
|
# record the renaming.
|
|
|
|
get_rel_dir $projroot $olddirname
|
|
local oldroot=$rel_dir
|
|
get_rel_dir $projroot $newdirname
|
|
local newroot=$rel_dir
|
|
|
|
echo "ctco -nc $oldroot" >> $projroot/.ctcmds
|
|
if [ "$oldroot" != "$newroot" ]; then
|
|
echo "ctco -nc $newroot" >> $projroot/.ctcmds
|
|
fi
|
|
echo "ctmv $oldroot/$oldbasename $newroot/$newbasename" >> $projroot/.ctcmds
|
|
fi
|
|
|
|
# Now rename our local copy, and all of its version tracking stuff.
|
|
get_fullpath $newdirname
|
|
local newroot=$fullpath
|
|
|
|
(cd $olddirname;
|
|
for file in \
|
|
`ls .ct[0-9].$oldbasename \
|
|
.ct[0-9][0-9].$oldbasename \
|
|
.ct[0-9][0-9][0-9].$oldbasename \
|
|
.ct[0-9]comment.$oldbasename \
|
|
.ct[0-9][0-9]comment.$oldbasename \
|
|
.ct[0-9][0-9][0-9]comment.$oldbasename \
|
|
.ctnew.$oldbasename \
|
|
.ctco.$oldbasename \
|
|
$oldbasename 2>/dev/null`; do
|
|
ctprefix=`echo $file | sed 's:'$oldbasename'$::'`
|
|
mv -i $file $newroot/$ctprefix$newbasename
|
|
done)
|
|
}
|
|
|
|
function ctmv {
|
|
local source destination
|
|
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
get_last_param "$@"
|
|
destination=$last_param;
|
|
|
|
if [ ! -d "$destination" ]; then
|
|
# If we're not moving to a directory, we are renaming a file--and
|
|
# thus we can only allow two parameters.
|
|
source=$1
|
|
shift 2
|
|
if [ ! -z "$*" ]; then
|
|
echo Last filename must be a directory.
|
|
exit 1
|
|
fi
|
|
|
|
do_ctmv $source $destination
|
|
else
|
|
|
|
# Otherwise, we're moving a slew of files to a directory. Get
|
|
# each filename and move it.
|
|
for source in "$@"; do
|
|
if [ "$source" != "$destination" ]; then
|
|
do_ctmv $source $destination/$source
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
function ctco {
|
|
local filename dirname basename
|
|
|
|
while getopts c:n: flag; do
|
|
case $flag in
|
|
c) comment="$OPTARG";;
|
|
n) comment="";;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
okflag=y
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
okflag=
|
|
else
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ -f $ctco ]; then
|
|
echo "$filename is already checked out." 1>&2
|
|
okflag=
|
|
else
|
|
if [ -w $filename ]; then
|
|
echo "$filename has write permission, it's probably not a versioned element." 1>&2
|
|
echo "Try neartool mkelem $filename." 1>&2
|
|
okflag=
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "$okflag" ]; then
|
|
get_highest_version $dirname $basename
|
|
next=$dirname/.ct`expr $version + 1`.$basename
|
|
nextcomment=$dirname/.ct`expr $version + 1`comment.$basename
|
|
|
|
if [ ! -z "$comment" ]; then
|
|
echo $comment >$nextcomment
|
|
chmod uga-w $nextcomment
|
|
fi
|
|
|
|
mv $filename $next
|
|
cp $next $filename
|
|
chmod ug+w $filename
|
|
|
|
date >$ctco
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
function ctunco {
|
|
local ignore filename dirname basename
|
|
|
|
while getopts "r:" flag; do
|
|
case $flag in
|
|
r) ignore=;;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ ! -f $ctco ]; then
|
|
echo "$filename is not checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
get_highest_version $dirname $basename
|
|
last=$dirname/.ct$version.$basename
|
|
lastcomment=$dirname/.ct${version}comment.$basename
|
|
|
|
mv -f $last $filename
|
|
rm -f $lastcomment
|
|
rm $ctco
|
|
touch $filename # For emacs, and correct make behavior.
|
|
done
|
|
}
|
|
|
|
|
|
function ctci {
|
|
local filename dirname basename
|
|
local comment
|
|
|
|
while getopts c:n: flag; do
|
|
case $flag in
|
|
c) comment="$OPTARG";;
|
|
n) comment="";;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ ! -f $ctco ]; then
|
|
echo "$filename is not checked out." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# We touch the file, so emacs will note that it has changed.
|
|
touch $filename
|
|
chmod uga-w $filename
|
|
|
|
rm $ctco
|
|
done
|
|
}
|
|
|
|
|
|
function ctrevert {
|
|
local filename dirname basename
|
|
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ -f $ctco ]; then
|
|
echo "$filename is currently checked out. Use neartool unco $filename." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
get_highest_version $dirname $basename
|
|
|
|
if [ $version -eq -1 ]; then
|
|
echo "$filename has no versions." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
last=$dirname/.ct$version.$basename
|
|
lastcomment=$dirname/.ct${version}comment.$basename
|
|
|
|
mv -f $last $filename
|
|
rm -f $lastcomment
|
|
|
|
if [ $version -eq 0 ]; then
|
|
ctnew=$dirname/.ctnew.$basename
|
|
if [ -f $ctnew ]; then
|
|
echo "Removing newly created element $filename." 1>&2
|
|
rm -f $ctnew $filename
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
function ctrevertall {
|
|
local filename dirname basename
|
|
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
ct0=$dirname/.ct0.$basename
|
|
if [ ! -f $ct0 ]; then
|
|
echo "$filename has no versions." 1>&2
|
|
else
|
|
ctnew=$dirname/.ctnew.$basename
|
|
if [ ! -f $ctnew ]; then
|
|
# If we didn't newly create this file, preserve its original version.
|
|
mv -f $ct0 $filename
|
|
fi
|
|
rm_all_ctinternals $dirname $basename
|
|
fi
|
|
done
|
|
}
|
|
|
|
function ctcollapse {
|
|
local filename dirname basename
|
|
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
rm_all_ctinternals $dirname $basename
|
|
|
|
chmod uga-w $filename
|
|
touch $filename # For Emacs' benefit.
|
|
done
|
|
}
|
|
|
|
function ctrmname {
|
|
local filename dirname basename
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
ctnew=$dirname/.ctnew.$basename
|
|
|
|
if [ ! -f $ctnew ]; then
|
|
# The filename exists on the actual Clearcase vobs. We need to
|
|
# record the removing.
|
|
|
|
get_rel_dir $projroot $dirname
|
|
local root=$rel_dir
|
|
|
|
echo "ctco -nc $root" >> $projroot/.ctcmds
|
|
echo "ctrm $root/$basename" >> $projroot/.ctcmds
|
|
fi
|
|
|
|
# Now remove all of the versioned stuff.
|
|
ctcollapse $filename
|
|
|
|
# And remove the file itself.
|
|
rm -f $filename
|
|
done
|
|
}
|
|
|
|
|
|
function ctfind {
|
|
local root=$1
|
|
|
|
if [ -z "$root" ]; then
|
|
echo "Specify a starting point of the find." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
find $root -name .ct0.\* -print | sed 's/\.ct0\.//'
|
|
}
|
|
|
|
function ctdescribe {
|
|
local filename dirname basename
|
|
|
|
while getopts "" flag; do
|
|
case $flag in
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in `ls "$@"`; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
get_highest_version $dirname $basename
|
|
version=`expr $version + 1`
|
|
|
|
if [ -f $ctco ]; then
|
|
if [ $version -eq 0 ]; then
|
|
echo "$filename is checked out with no versions."
|
|
else
|
|
echo "$filename is checked out as version $version."
|
|
list_comments $dirname $basename
|
|
fi
|
|
else
|
|
if [ $version -eq 0 ]; then
|
|
echo "$filename has not been checked out and has no versions."
|
|
else
|
|
echo "$filename is checked in as version $version."
|
|
list_comments $dirname $basename
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
function ctlsco {
|
|
local filename dirname basename
|
|
local ignore
|
|
while getopts "l" flag; do
|
|
case $flag in
|
|
l) ignore=;;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
for filename in `ls "$@"`; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
ctco=$dirname/.ctco.$basename
|
|
if [ -f $ctco ]; then
|
|
ctdescribe $filename
|
|
fi
|
|
done
|
|
}
|
|
|
|
function ctdiff {
|
|
local filename dirname basename
|
|
local graphical
|
|
local ignore
|
|
local diff
|
|
|
|
while getopts "gp:" flag; do
|
|
case $flag in
|
|
g) graphical=y;;
|
|
p) ignore=;;
|
|
\?) exit 1;
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
diff=diff
|
|
if [ $graphical ]; then
|
|
# The user requested a graphical difference; use gdiff if we can
|
|
# find it. Otherwise, fall back to diff.
|
|
if which gdiff 2>/dev/null >/dev/null; then
|
|
diff=gdiff
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "No filenames given."
|
|
exit 1
|
|
fi
|
|
|
|
for filename in "$@"; do
|
|
dirname=`dirname $filename`
|
|
basename=`basename $filename`
|
|
|
|
sane_filename $dirname $basename
|
|
|
|
if [ ! -f $filename ]; then
|
|
echo "$filename does not exist." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
get_highest_version $dirname $basename
|
|
|
|
if [ $version -eq -1 ]; then
|
|
echo "$filename has no versions." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
last=$dirname/.ct$version.$basename
|
|
|
|
# First, call diff (the real diff) just to see if the files are
|
|
# different at all.
|
|
|
|
if diff $last $filename >/dev/null; then
|
|
echo Files are identical.
|
|
|
|
else
|
|
# If the files ARE different, then invoke diff again (which
|
|
# might be gdiff, this time) to actually report the differences.
|
|
# We must do it twice like this because gdiff might not return
|
|
# non-zero if the files are different.
|
|
|
|
$diff $last $filename
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
function usage {
|
|
sed '/#ENDCOMMENT/,$d' <$0 >&2
|
|
exit 1
|
|
}
|
|
|
|
|
|
#
|
|
# Main entry point
|
|
#
|
|
|
|
command=$1
|
|
if [ -z "$command" ]; then
|
|
usage
|
|
fi
|
|
|
|
shift
|
|
|
|
projroot=`ctproj -r`
|
|
|
|
if [ -z "$projroot" ]; then
|
|
echo "Not currently in a project tree." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
case $command in
|
|
mkelem) ctmkelem "$@";;
|
|
mkdir) ctmkdir "$@";;
|
|
mv) ctmv "$@";;
|
|
co|checkout) ctco "$@";;
|
|
unco|uncheckout) ctunco "$@";;
|
|
ci|checkin) ctci "$@";;
|
|
revert) ctrevert "$@";;
|
|
revertall) ctrevertall "$@";;
|
|
collapse) ctcollapse "$@";;
|
|
rmname) ctrmname "$@";;
|
|
find) ctfind "$@";;
|
|
lsco|lscheckout) ctlsco "$@";;
|
|
describe) ctdescribe "$@";;
|
|
diff) ctdiff "$@";;
|
|
xdiff) ctdiff -g "$@";;
|
|
h|help|-h) usage;;
|
|
*) echo "Invalid option: $command" 1>&2
|
|
exit 1;
|
|
esac
|