#!/bin/bash MYP4BIN=$HOME/bin P4BIN=$MYP4BIN/p4.bin P4DBIN=$MYP4BIN/p4d.bin if [ ! -f $P4BIN ]; then what=$(uname) if [ "$what" == 'Darwin' ]; then MYPLAT="bin.darwin90x86_64" else MYPLAT="bin.linux26x86_64" fi echo "Downloading required Perforce binaries for $MYPLAT ..." which wget > /dev/null if [ $? -eq 0 ]; then wget -q -O $P4BIN ftp://ftp.perforce.com/perforce/r14.1/$MYPLAT/p4 wget -q -O $P4DBIN ftp://ftp.perforce.com/perforce/r14.1/$MYPLAT/p4d else curl -q -o $P4BIN ftp://ftp.perforce.com/perforce/r14.1/$MYPLAT/p4 curl -q -o $P4DBIN ftp://ftp.perforce.com/perforce/r14.1/$MYPLAT/p4d fi chmod a+x $P4BIN chmod a+x $P4DBIN echo "Done." fi # Check every so often like every 32 times or so if [ "$1" == "check" ] || [ $(($RANDOM / 911)) -eq 0 ]; then THIS_REV=27 NEWER_REV=$(($THIS_REV+1)) which wget > /dev/null if [ $? -eq 0 ]; then wget -S --spider \ https://swarm.workshop.perforce.com/files/guest/alan_h_teague/myp4/p4?v=$NEWER_REV \ > /dev/null 2> /dev/null if [ $? -eq 0 ]; then echo "A newer version of myp4 is available" echo "https://swarm.workshop.perforce.com/files/guest/alan_h_teague/myp4/p4" elif [ "$1" == "check" ]; then echo "No newer version is available" exit 0 fi else cur=$(curl -o /dev/null --silent --head --write-out "%{http_code}\n" \ https://swarm.workshop.perforce.com/files/guest/alan_h_teague/myp4/p4?v=$NEWER_REV) if [ "$cur" == "200" ]; then echo "A newer version of myp4 is available" echo "https://swarm.workshop.perforce.com/files/guest/alan_h_teague/myp4/p4" elif [ "$1" == "check" ]; then echo "No newer version is available" exit 0 fi fi fi if [ -z "$P4CONFIG" ]; then export P4CONFIG=".myp4" fi if [ -z "$P4IGNORE" ]; then export P4IGNORE=".myp4ignore" fi rootDir=$($P4BIN -ztag set | \ egrep "^P4CONFIG=$P4CONFIG" | \ cut -d "'" -f 2 | \ sed "s/$P4CONFIG/.myp4d/") if [ "$rootDir" == 'noconfig' ]; then if [ "$1" != 'init' ]; then $P4BIN "$@" exit $? fi echo 'Initializing...' baseDir="$PWD" if [ -n "$2" ]; then baseDir="$PWD/$2" fi rootDir="$baseDir/.myp4d" if [ -d "$rootDir" ]; then echo "Perforce storage already maps to $rootDir" exit 1 fi mkdir -p "$rootDir" cat > "$baseDir/$P4CONFIG" < "$baseDir/$P4IGNORE" < "$baseDir/.gitignore" < /dev/null $P4BIN depot -d depot > /dev/null $P4BIN depot -o branch | $P4BIN depot -i > /dev/null $P4BIN protect -o | $P4BIN protect -i > /dev/null $P4BIN client -o branches-master | \ sed -e 's=//branch/... //branches-master/...=//branch/master/... //branches-master/...=' \ -e 's/noallwrite/allwrite/' \ -e 's/normdir/rmdir/' \ -e 's/nomodtime/modtime/' \ -e 's/submitunchanged/revertunchanged/' | \ $P4BIN client -i > /dev/null # Create the initial client $P4BIN client -o -t branches-master | \ $P4BIN client -i > /dev/null exit 0 fi if [ ! -d "$rootDir" ]; then $P4BIN "$@" exit $? fi curBranch=$($P4BIN client -o | \ egrep "//branch/[^/]+/... " | head -1 | \ sed -e 's=^.*//branch/==' -e 's=/[.][.][.].*$==') P4USER=$USER P4CLIENT=$USER case $1 in init) echo "Already within a Perforce storage structure: $rootDir" exit 1 ;; server) if [ -z "$2" ]; then echo ":1666" > "$rootDir/myPort" else echo "$2" > "$rootDir/myPort" fi port=$(head -1 "$rootDir/myPort") $P4DBIN -r "$rootDir" -vserver=3 -Llog_file -p $port -d echo "Stop server by running: p4 -p $port admin stop" exit 0 ;; checkpoint) $P4BIN reconcile -m -f //$P4CLIENT/... oops=$($P4BIN reconcile -n -m -f //$P4CLIENT/... 2>&1 | \ grep 'no file(s) to reconcile' | \ wc -l) if [ $oops -eq 0 ]; then echo "There is a problem with reconcile. Fix it before continuing" exit 1 fi cnt=$($P4BIN -ztag opened //$P4CLIENT/... 2>&1 | wc -l) if [ $cnt -gt 0 ]; then if [ -z "$2" ]; then $P4BIN submit -d "Auto-checkpoint" else $P4BIN submit -d "$2" fi fi exit 0 ;; switch) if [ "$2" == '-a' ]; then for f in $($P4BIN -ztag clients -e 'branches-*' | \ grep '... client ' | \ sed -e 's/branches-//' -e 's/... client //'); do if [ "$f" == "$curBranch" ]; then echo "$f *" else echo $f fi done exit 0 fi if [ "$2" != '-b' ]; then toBranch="$2" if [ -z "$toBranch" ]; then echo "Current branch $curBranch" exit 0 fi branch_client=$($P4BIN -ztag clients -e "branches-$2" | \ grep "... client " | \ sed -e 's/... client //') if [ -z "$branch_client" ]; then echo "Branch $2 does not exist, yet (use -b to create)" exit 1 fi if [ "$toBranch" == "$curBranch" ]; then echo "Already there, wasn't that fast?" exit 0 fi work=$($P4BIN -ztag opened //$P4CLIENT/... 2> /dev/null | wc -l) if [ $work -eq 0 ]; then work=$($P4BIN -ztag status //$P4CLIENT/... 2> /dev/null | wc -l) fi if [ $work -gt 0 ]; then echo "There are pending changes, how do you want to proceed?" # One day add in (m) Move changes read -p '(s) Shelve changes for later (r) Revert changes (q) Quit? ' \ answer case $answer in s) newChange=$($P4BIN change -o | \ sed -e "s//Shelf for $curBranch/" | \ $P4BIN change -i | sed -e 's/^Change //' -e 's/ .*//') $P4BIN reconcile -f -c $newChange //$P4CLIENT/... oops=$($P4BIN reconcile -n -f //$P4CLIENT/... 2>&1 | \ grep 'no file(s) to reconcile' | \ wc -l) if [ $oops -eq 0 ]; then echo "There is a problem with reconcile. Fix it before continuing" exit 1 fi $P4BIN shelve -c $newChange > /dev/null $P4BIN key "branchShelf-$USER-$curBranch" $newChange > /dev/null $P4BIN revert -w //branch/$curBranch/... > /dev/null ;; r) read -p 'New files will be deleted, edits discarded, etc. Are you sure? (y/n) ' \ answer if [ "$answer" == "y" ]; then $P4BIN reconcile -f //$P4CLIENT/... > /dev/null 2> /dev/null $P4BIN revert -w //branch/$curBranch/... else echo "Aborting..." exit 1 fi ;; q) exit 0 ;; esac fi echo "Switch from $curBranch to $toBranch" if [ -z "$branch_client" ]; then $P4BIN client -o | \ sed -e "s=//branch/[^/]*/... //$USER/...=//branch/$toBranch/... //$USER/...=" | \ $P4BIN client -i > /dev/null else $P4BIN client -s -t $branch_client > /dev/null fi $P4BIN sync -q //$P4CLIENT/... 2> /dev/null curShelf=$($P4BIN key "branchShelf-$USER-$toBranch") if [ $curShelf != 0 ]; then echo "Unshelving $curShelf" $P4BIN unshelve -s $curShelf $P4BIN shelve -d -c $curShelf > /dev/null $P4BIN change -d $curShelf > /dev/null $P4BIN key -d "branchShelf-$USER-$toBranch" > /dev/null fi exit 0 fi newBranch=$3 if [ -z "$newBranch" ]; then echo "Current branch $curBranch" exit 0 fi branch_client=$($P4BIN -ztag clients -e "branches-$2" | \ grep "... client " | \ sed -e 's/... client //') if [ -n "$branch_client" ]; then echo "Existing branch $newBranch" echo "Perhaps you meant to say: p4 switch $newBranch (i.e., no -b)" exit 1 fi if [[ $newBranch == *-* ]]; then echo "Branch names cannot contain dashes." exit 1 fi if [[ $newBranch =~ \ ]]; then echo "Branch names cannot contain spaces." exit 1 fi work=$($P4BIN -ztag opened //$P4CLIENT/... 2> /dev/null | wc -l) if [ $work -eq 0 ]; then work=$($P4BIN -ztag status //$P4CLIENT/... 2> /dev/null | wc -l) fi if [ $work -gt 0 ]; then echo "There are pending changes, how do you want to proceed?" # One day add in (m) Move changes read -p '(s) Shelve changes for later (r) Revert changes (q) Quit? ' \ answer case $answer in s) newChange=$($P4BIN change -o | \ sed -e "s//Shelf for $curBranch/" | \ $P4BIN change -i | sed -e 's/^Change //' -e 's/ .*//') $P4BIN reconcile -f -c $newChange //$P4CLIENT/... oops=$($P4BIN reconcile -n -f //$P4CLIENT/... 2>&1 | \ grep 'no file(s) to reconcile' | \ wc -l) if [ $oops -eq 0 ]; then echo "There is a problem with reconcile. Fix it before continuing" exit 1 fi $P4BIN shelve -c $newChange > /dev/null $P4BIN key "branchShelf-$USER-$curBranch" $newChange > /dev/null $P4BIN revert -w //branch/$curBranch/... > /dev/null ;; r) read -p 'New files will be deleted, edits discarded, etc. Are you sure? (y/n) ' \ answer if [ "$answer" == "y" ]; then $P4BIN reconcile -f //$P4CLIENT/... > /dev/null 2> /dev/null $P4BIN revert -w //branch/$curBranch/... else echo "Aborting..." exit 1 fi ;; q) exit 0 ;; esac fi emptyBranch=$($P4BIN -ztag files -m1 ... 2> /dev/null | egrep '^[.][.][.]' | wc -l) if [ $emptyBranch == 0 ]; then echo "No files to branch" else $P4BIN populate -d "Branching //branches/$curBranch to //branches/$newBranch" \ //branch/$curBranch/... //branch/$newBranch/... if [ $? != 0 ]; then echo "Failed to create branch $2 mapping to //branch/$newBranch" exit 1 fi fi echo "Switch from $curBranch to $newBranch" $P4BIN client -o -t branches-master branches-$newBranch | \ sed -e "s=//branch/[^/]*/... //=//branch/$newBranch/... //=" | \ $P4BIN client -i > /dev/null $P4BIN client -s -t branches-$newBranch > /dev/null $P4BIN sync -q //$P4CLIENT/... 2> /dev/null exit 0 ;; mergefrom) fromBranch="$2" if [ -z "$fromBranch" ]; then echo 'Please specify the branch from which to merge' exit 1 fi branch_client=$($P4BIN -ztag clients -e "branches-$fromBranch" | \ grep "... client " | \ sed -e 's/... client //') if [ -z "$branch_client" ]; then echo "Branch $2 does not exist" exit 1 fi if [ "$fromBranch" == "$curBranch" ]; then echo 'Mobius branches are not supported' exit 0 fi work=$($P4BIN -ztag opened //$P4CLIENT/... 2> /dev/null | wc -l) if [ $work -eq 0 ]; then work=$($P4BIN -ztag status //$P4CLIENT/... 2> /dev/null | wc -l) fi if [ $work -gt 0 ]; then echo "There are pending changes, how do you want to proceed?" read -p '(s) Shelve changes for later (r) Revert changes (q) Quit? ' \ answer case $answer in s) newChange=$($P4BIN change -o | \ sed -e "s//Shelf for $curBranch/" | \ $P4BIN change -i | sed -e 's/^Change //' -e 's/ .*//') $P4BIN reconcile -f -c $newChange //$P4CLIENT/... oops=$($P4BIN reconcile -n -f //$P4CLIENT/... 2>&1 | \ grep 'no file(s) to reconcile' | \ wc -l) if [ $oops -eq 0 ]; then echo "There is a problem with reconcile. Fix it before continuing" exit 1 fi $P4BIN shelve -c $newChange > /dev/null $P4BIN key "branchShelf-$USER-$curBranch" $newChange > /dev/null $P4BIN revert -w //branch/$curBranch/... > /dev/null ;; r) read -p 'New files will be deleted, edits discarded, etc. Are you sure? (y/n) ' \ answer if [ "$answer" == "y" ]; then $P4BIN reconcile -f //$P4CLIENT/... > /dev/null 2> /dev/null $P4BIN revert -w //branch/$curBranch/... else echo "Aborting..." exit 1 fi ;; q) exit 0 ;; esac fi integ_dir="" branch_branch=$($P4BIN -ztag branches -e "merge-$fromBranch-$curBranch" | \ grep "... branch " | \ sed -e 's/... branch //') if [ -z "$branch_branch" ]; then branch_branch=$($P4BIN -ztag branches -e "merge-$curBranch-$fromBranch" | \ grep "... branch " | \ sed -e 's/... branch //') integ_dir="-r" fi if [ -z "$branch_branch" ]; then # Simple integ, perhaps complexFrom=$($P4BIN -ztag client -o branches-$fromBranch | egrep '^... View1') complexTo=$($P4BIN -ztag client -o branches-$curBranch | egrep '^... View1') if [ "$complexFrom" != "" ]; then echo "$fromBranch is complex aka multiple lines in View" echo "Need to define a branchspec for merge-$fromBranch-$curBranch" $P4BIN -ztag client -o branches-$fromBranch | \ egrep '^... View[0-9]' | \ awk '{ print $3; }' > .$$.left $P4BIN -ztag client -o branches-$curBranch | \ egrep '^... View[0-9]' | \ awk '{ print $3; }' > .$$.right echo "Something like: p4 branchspec merge-$fromBranch-$curBranch" echo "View:" lcnt=$(wc -l .$$.left | awk '{ print $1;}' ) rcnt=$(wc -l .$$.right | awk '{ print $1;}' ) if [ $lcnt -lt $rcnt ]; then num=$(($rcnt - $lcnt)) for(( i=0; i < $num; i++ )); do echo "//???/..." >> .$$.left done elif [ $rcnt -lt $lcnt ]; then num=$(($lcnt - $rcnt)) for(( i=0; i < $num; i++ )); do echo "//???/..." >> .$$.right done fi paste .$$.left .$$.right | sed -e 's/^/ /' \rm .$$.left .$$.right exit 1 fi if [ -n "$complexTo" ]; then echo "$curBranch is complex aka multiple lines in View" echo "Need to define a branchspec for merge-$fromBranch-$curBranch" $P4BIN -ztag client -o branches-$fromBranch | \ egrep '^... View[0-9]' | \ awk '{ print $3; }' > .$$.left $P4BIN -ztag client -o branches-$curBranch | \ egrep '^... View[0-9]' | \ awk '{ print $3; }' > .$$.right echo "Something like: p4 branchspec merge-$fromBranch-$curBranch" echo "View:" lcnt=$(wc -l .$$.left | awk '{ print $1;}' ) rcnt=$(wc -l .$$.right | awk '{ print $1;}' ) if [ $lcnt -lt $rcnt ]; then num=$(($rcnt - $lcnt)) for(( i=0; i < $num; i++ )); do echo "//???/..." >> .$$.left done elif [ $rcnt -lt $lcnt ]; then num=$(($lcnt - $rcnt)) for(( i=0; i < $num; i++ )); do echo "//???/..." >> .$$.right done fi paste .$$.left .$$.right | sed -e 's/^/ /' \rm .$$.left .$$.right exit 1 fi $P4BIN integ //branch/$fromBranch/... //branch/$curBranch/... $P4BIN resolve -am else # Defined integ, simple echo "Merging using branchspec $branch_branch" $P4BIN integ -b $branch_branch $integ_dir $P4BIN resolve -am fi echo "Assuming no issues, you should now submit..." ;; help) $P4BIN "$@" echo echo "Extra local commands:" echo " p4 switch {branchName} Switch to specified branch or report current" echo " p4 switch -b {newBranchName} Create new branch or report current" echo " p4 switch -a List the defined branches" echo echo " p4 branch FROM-TO Define how to merge between two branches" echo " Only needed if branches use multi-line views" echo " p4 mergefrom BRANCHNAME Run integ from named branch into current one" echo " Only needed if branches use multi-line views" echo " p4 checkpoint {description} Reconcile and submit if needed" echo " p4 server {port} Start up a network accessible p4d linked to" echo " this Perforce storage structure" echo " p4 check Force a check for updates of myp4" ;; *) $P4BIN "$@" exit $? ;; esac