#!/bin/sh
#
# p4
#
# Wrapper for Perforce "p4" command to extend it to support the
# more popular CVS update/commit model.
#
# Stick this in your $PATH before /usr/bin/p4.
#
# Author: Rick Richardson <rickr@mn.rr.com>
# http://http://home.mn.rr.com/richardsons/
#
# TODO import:
# Handle repository vendortag releasetag args
# TODO rename:
# Theres a problem if you do this:
# p4 rename xxx yyy; p4 commit; p4 rename yyy xxx; p4 commit
# The file will end up deleted.
#
P4=/usr/bin/p4
TMP=/tmp/p4blather
TMP=/tmp/p4blather$$
#
# Save the original value of P4CONFIG, so we can warn the user in
# our "p4 ws" command. Then set P4CONFIG if it wasn't already set.
#
saveP4CONFIG="$P4CONFIG"
if [ "$P4CONFIG" = "" ]; then
export P4CONFIG=.p4config
fi
#
# Report an error and exit
#
PROGNAME="$0"
error() {
echo "`basename $PROGNAME`: $1" >&2
exit 1
}
#
# Version of "p4" command that eats the blather and returns just
# a valid exit status code. Yes, p4 needs an option to do this.
#
p4rc() {
$P4 -s "$@" >$TMP 2>&1
while read tag blather
do
case "$tag" in
error:)
rm -f $TMP
return 1
;;
esac
done < $TMP
rm -f $TMP
return 0
}
case "$1" in
annotate)
shift
for file in "$@"
do
if [ -d "$file" ]; then
p4 files $file/... |
while read pfile blather
do
p4pr.perl $pfile
done
else
p4pr.perl $file
fi
done
;;
commit)
shift
if [ $# = 0 ]; then
# Finger out which files need to be committed...
# ... ala CVS, current dir and lower only.
$P4 diff -se ./... 2>/dev/null |
while read file
do
p4rc edit $file || error "Can't p4 edit $file"
done
$P4 submit ./...
else
# User supplied list of files/dirs to commit
pfiles=
for file in "$@"
do
if [ -d "$file" ]; then
$P4 diff -se $file/... 2>/dev/null |
while read dirfile
do
p4rc edit $dirfile ||
error "Can't p4 edit $dirfile"
done
pfiles="$pfiles $file/..."
else
p4rc edit $file || error "Can't p4 edit $file"
pfiles="$pfiles $file"
fi
done
$P4 submit $pfiles
fi
;;
import)
# TODO: handle repository vendortag releasetag args
find . -type f -print | $P4 -x - add
$P4 submit ./...
;;
rename)
shift
if [ $# != 2 ]; then
error "Usage: p4 rename from to"
fi
FROM="$1"
TO="$2"
$P4 integrate $FROM $TO
$P4 delete $FROM
# TODO: theres a problem if you do this:
# p4 rename xxx yyy; p4 commit; p4 rename yyy xxx; p4 commit
# The file will end up deleted.
;;
stat)
shift
# Convert directory names to p4 syntax
pfiles=
for file in "$@"
do
if [ -d "$file" ]; then
pfiles="$pfiles $file/..."
else
pfiles="$pfiles $file"
fi
done
if [ "$pfiles" = "" ]; then
pfiles=./...
fi
echo "Files needing an update/sync..."
$P4 diff -sd $pfiles |
sed -e 's/^/ /'
$P4 sync -n $pfiles 2>&1 |
sed -e 's/^/ /' -e 's/File(s) up-to-date./None/' \
-e '/file(s) up-to-date./d'
echo
echo "Files needing a commit/submit..."
$P4 diff -se $pfiles |
sed -e 's/^/ /'
;;
update)
# Do a sync and then a resolve
shift
if [ $# = 0 ]; then
# ala CVS, sync/resolve current dir and lower only.
# Pick up files that are missing...
$P4 diff -sd ./... | $P4 -x- sync -f
# Pick up files that have changed...
$P4 sync ./...
$P4 resolve ./...
else
# Convert directory names to p4 syntax
pfiles=
for file in "$@"
do
if [ -d "$file" ]; then
pfiles="$pfiles $file/..."
else
pfiles="$pfiles $file"
fi
done
# Pick up files that are missing...
$P4 diff -sd $pfiles | $P4 -x- sync -f
# Pick up files that have changed...
$P4 sync $pfiles
$P4 resolve $pfiles
fi
;;
ws)
shift
if [ $# = 0 ]; then
error "Usage: p4 ws <wsname> [serv:port [user [passwd]]]"
fi
if [ -f "$P4CONFIG" ]; then
error "$P4CONFIG exists. Remove it first"
fi
WSNAME="$1"
PORT="$2"
USER="$3"
PASSWD="$4"
if [ "$P4PORT" = "" ]; then
if [ "$PORT" = "" ]; then
echo "P4PORT=perforce:1666" > $P4CONFIG
else
echo "P4PORT=$PORT" > $P4CONFIG
fi
else
echo "P4PORT=$P4PORT" > $P4CONFIG
fi
echo "P4CLIENT=$WSNAME" >> $P4CONFIG
if [ "$USER" != "" ]; then
echo "P4USER=$USER" >> $P4CONFIG
fi
if [ "$PASSWD" != "" ]; then
echo "P4PASSWD=$PASSWD" >> $P4CONFIG
fi
$P4 client -o | sed 's/noallwrite/allwrite/' | $P4 client -i
$P4 client
if [ "$saveP4CONFIG" = "" ]; then
echo "Warning: Add 'export P4CONFIG=.p4config' to your .profile"
echo "Warning: for safety in case you stop using this wrapper"
fi
;;
help)
if [ $# = 1 ]; then
$P4 | sed '/p4 help env.*/a\
p4 help ext list extended commands provided by p4 wrapper'
elif [ $2 = "ext" ]; then
cat <<-EOF
Most extended subcommands take file and/or directory
arguments, recursing on the directories. If no arguments
are supplied to such a command, it will recurse on the
current directory (inclusive) by default. This is the
surprise-free behavior CVS users are used to.
Extended Perforce client commands:
p4 annotate file|dir ...
Make a listing of who changed what line.
p4 commit [file|dir] ...
Submit changed files to the depot.
p4 import
Add all files in current directory and below to
the depot.
p4 rename from to
Rename the file "from" as "to".
p4 stat [file|dir] ...
Report all files needing an update/sync
and/or a commit/submit.
p4 update [file|dir] ...
Get latest files from depot, doing a resolve
if necessary.
p4 ws <wsname> [server:port [user [passwd]]]
Create a new workspace in the current directory.
EOF
else
$P4 "$@"
fi
;;
*)
# Hand off all other commands to p4
exec $P4 "$@"
;;
esac