--- /dev/null
+#!/bin/bash\r
+# Author: Hari Krishna Dara ( hari_vim at yahoo dot com ) \r
+# Last Change: 17-Mar-2004 @ 18:47\r
+# Requires:\r
+# - bash or ksh (tested on cygwin and MKS respectively).\r
+# - Info Zip for the -z option to work (comes with linux/cygwin). Download for\r
+# free from:\r
+# http://www.info-zip.org/\r
+# - GNU tar for the -a option to work (comes with linux/cygwin).\r
+# Version: 1.4.2\r
+# Licence: This program is free software; you can redistribute it and/or\r
+# modify it under the terms of the GNU General Public License.\r
+# See http://www.gnu.org/copyleft/gpl.txt \r
+# Description:\r
+# Shell script to take backup of all the open files in perforce SCM.\r
+#\r
+#TODO:\r
+# - Zip comment option -zz is no longer working?\r
+# - To create cpio archives, I can use "cpio -o -H | gzip" command.\r
+# - Option to generate a diff at the end.\r
+# - Option to restrict by type (useful to avoid huge binary files).\r
+# - Support to run zip from a different directory (to avoid certain path\r
+# component from getting into zipfile).\r
+\r
+usage()\r
+{\r
+cat <<END\r
+$0 [<backup dir>] [<source dir>] ...\r
+$0 -h -n -q -v -z -zz [-c <change number>] [-t <backup dir>] [-r <backup root>] [[-s <source dir>] ...]\r
+ -t specify full path name to the target directory. If -z is specified this\r
+ becomes the path to the zip file name.\r
+ -r set the root for creating the default backup dir/zip file. Not used if\r
+ "backup dir" is specified. You can also set BAKUP_ROOT environmental\r
+ variable. Defaults to p: (p drive), because that is what it is on my\r
+ system :).\r
+ -i incremental backup, which makes the program use the previous backup\r
+ directory/archive for that day (if it exists) instead of creating a new\r
+ one. For tar (with "-a" option), you will have to provide one of the\r
+ relevant options to force reuse an existing archive ("-ar" e.g.) or the\r
+ existing archive will simply get overwritten. However this will not work\r
+ with compressed tar archives. You can also specify any existing backup\r
+ directory/archive path explicitly by using the "-t" option.\r
+ -a create a tar file instead of copying the files. You can specify the\r
+ tar file name using -t option.\r
+ -a[-|--]<taropt>\r
+ Pass -taropt to tar command.\r
+ Ex:\r
+ - Pass "-aC <dir>" or "-adirectory=<dir>" to cd to a directory before\r
+ creating the tar file (thus dropping file component).\r
+ - Pass "-az" to gzip the created tar file.\r
+ -z create a zip file instead of copying the files. You can specify the\r
+ zip file name using -t option.\r
+ -z[-]<zipopt>\r
+ Pass -zipopt to zip command.\r
+ Ex: Pass -zz for a prompt from zip to enter a comment.\r
+ -s limit to open files matching the given wildcard (local or depot). This\r
+ can be repeated multiple times to specify multiple source directories.\r
+ You can pass in anything that the 'p4 opened' command itself accepts.\r
+ -c limit the files to those specified in the change number, in addition to\r
+ the -s option. This can't be repeated multiple times though.\r
+ -n don't execute any commands, just show what is going to be done. Does not\r
+ currently work with -z option.\r
+ -q quite mode, no messages\r
+ -v verbose mode, print messages (the default).\r
+ -h print help message (this message) and exit\r
+ The first unspecified directory is treated as target directory, and the\r
+ remaining directories are treated as source directories. The '-n' option can\r
+ be used to generate a batch script that can be run later. The source\r
+ directory can be in depot or local format (NO BACKSLASHES PLEASE). Do not\r
+ combine multiple options into one argument.\r
+Examples:\r
+ bakup.sh\r
+ - Backup all the open files into a default generated backup dir. in p:\r
+ drive (p: driver is the default backup directory).\r
+ bakup.sh mybak c:/dev/branch/src\r
+ - Backup open files only under 'c:/dev/branch/src' into 'mybak'\r
+ directory.\r
+ bakup.sh -s //depot/branch/src -s //depot/branch/cfg\r
+ - Backup open files only under 'src' and 'cfg' into the default bakup\r
+ dir.\r
+\r
+ You could add -z option to all the above usages to create a zip file\r
+ instead of creating a directory. You need to have Info-Zip installed in the\r
+ path for this to work.\r
+\r
+ bakup.sh -n > mybackup.bat\r
+ - Generates a 'mybackup.bat' batch file that can be run at a later\r
+ time to take a backup. The files to be backed up are based on the\r
+ time the script was generated, so it should be regenerated if the\r
+ list has changed since then.\r
+END\r
+exit 1\r
+}\r
+\r
+generateTargetDirName()\r
+{\r
+ today=`date +"%d-%b-%Y"`\r
+ inc=1\r
+ #echo "---first time"\r
+ tDir="$targetRoot/bakup-$today"\r
+ prevDir=$tDir\r
+ while [ -d $tDir -o -f $tDir.* ]; do\r
+ inc=$[inc + 1]\r
+ prevDir=$tDir\r
+ tDir="$targetRoot/bakup-${today}_$inc"\r
+ #echo "---subsequent time inc=$inc tDir=$tDir"\r
+ done\r
+ if [ $incrementalMode -ne 0 ]; then\r
+ tDir=$prevDir # Backup one level to use an existing db.\r
+ fi\r
+ echo "$tDir"\r
+}\r
+\r
+getExtOpt()\r
+{\r
+ archiveOpt=${1/[-+]$2/}\r
+ case $archiveOpt in\r
+ --*)\r
+ ;;\r
+ -??*) # Mistyped long option\r
+ archiveOpt="-$archiveOpt"\r
+ ;;\r
+ -*)\r
+ ;;\r
+ ??*) # Long option.\r
+ archiveOpt="--$archiveOpt"\r
+ ;;\r
+ *)\r
+ archiveOpt="-$archiveOpt"\r
+ ;;\r
+ esac\r
+ echo $archiveOpt\r
+}\r
+\r
+#getExtOpt '-a--directory' 'a'\r
+#getExtOpt '-a-directory' 'a'\r
+#getExtOpt '-adirectory' 'a'\r
+#getExtOpt '-aC' 'a'\r
+#getExtOpt '-a-C' 'a'\r
+#exit\r
+\r
+checkOptArg='\r
+ shift;\r
+ if [ $# -eq 0 ]; then\r
+ usage;\r
+ fi\r
+'\r
+\r
+testMode=0\r
+archiveOpts=''\r
+chDirectory='' # If set, the listing is generated relative to this dir.\r
+archiveMode=0\r
+verboseMode=1\r
+targetDir=""\r
+targetRoot=""\r
+sourceDirs=""\r
+changeNumber=""\r
+compressedTar=0\r
+incrementalMode=0\r
+until [ $# -eq 0 ]; do\r
+ case $1 in\r
+ -h|-help|--help)\r
+ usage\r
+ ;;\r
+ -v)\r
+ verboseMode=1\r
+ ;;\r
+ -q)\r
+ verboseMode=0\r
+ ;;\r
+ -i)\r
+ incrementalMode=1\r
+ ;;\r
+ -a)\r
+ archiveMode=2 # Tar.\r
+ verboseMode=0 # Turn on quite mode, as zip will anyway show the files.\r
+ testMode=1 # Turn on test mode, so we won't copy files.\r
+ ;;\r
+ -a*)\r
+ # Need to take care of options with optional args.\r
+ extOpt=`getExtOpt $1 a`\r
+ if [ $extOpt = -z -o $extOpt = -Z -o $extOpt = -j ]; then\r
+ compressedTar=1\r
+ tarExt=`echo $extOpt | awk 'BEGIN{ext["-j"]="bz2";ext["-z"]="gz";ext["-Z"]="Z";}{print ext[$0];}'`\r
+ fi\r
+ archiveOpts="${archiveOpts} $extOpt"\r
+ case $extOpt in\r
+ --directory)\r
+ chDirectory=${extOpt/*=}\r
+ ;;\r
+ -C)\r
+ eval $checkOptArg\r
+ chDirectory=$1\r
+ #echo "---setting chDirectory=$chDirectory"\r
+ archiveOpts="${archiveOpts} $chDirectory"\r
+ ;;\r
+ esac\r
+ ;;\r
+ -z)\r
+ archiveMode=1 # Zip.\r
+ verboseMode=0 # Turn on quite mode, as zip will anyway show the files.\r
+ testMode=1 # Turn on test mode, so we won't copy files.\r
+ ;;\r
+ -z*)\r
+ # Need to take care of options with optional args.\r
+ archiveOpts="${archiveOpts} `getExtOpt $1 z`"\r
+ ;;\r
+ -n)\r
+ testMode=1\r
+ verboseMode=0\r
+ ;;\r
+ -c)\r
+ eval $checkOptArg\r
+ changeNumber=$1\r
+ ;;\r
+ -t)\r
+ eval $checkOptArg\r
+ targetDir=$1\r
+ ;;\r
+ -r)\r
+ eval $checkOptArg\r
+ targetRoot=$1\r
+ ;;\r
+ -s)\r
+ eval $checkOptArg\r
+ sourceDirs="$sourceDirs $1"\r
+ #echo "---setting sourceDirs=$sourceDirs"\r
+ ;;\r
+ -?)\r
+ usage\r
+ ;;\r
+ *)\r
+ if [ "$targetDir" = "" ]; then\r
+ #echo "---setting targetDir=$targetDir"\r
+ targetDir=$1\r
+ else\r
+ #echo "---appending sourceDirs=$1"\r
+ sourceDirs="$sourceDirs $1"\r
+ fi\r
+ ;;\r
+ esac\r
+ shift\r
+done\r
+\r
+# For tar, we can add -a option only if no other equivalent option is specified.\r
+if [ $archiveMode -eq 2 ]; then\r
+ case $archiveOpts in\r
+ *-[Acdtrux]*)\r
+ ;;\r
+ *)\r
+ archiveOpts="$archiveOpts -c"\r
+ ;;\r
+ esac\r
+fi\r
+\r
+if [ x${targetDir}x = xx -a x${targetRoot}x = xx ]; then\r
+ targetRoot=$BAKUP_ROOT\r
+ if [ "$targetRoot" = "" ]; then\r
+ targetRoot="p:"\r
+ fi\r
+fi\r
+\r
+if [ "$targetDir" = "" ]; then\r
+ targetDir=`generateTargetDirName`\r
+fi\r
+\r
+if [ "$sourceDirs" = "" ]; then\r
+ # By default backup all the open files.\r
+ sourceDirs="//..."\r
+fi\r
+\r
+\r
+# Create a dir if it doesn't exist, exit on error.\r
+createDir()\r
+{\r
+ if ! [ -d "$1" ]; then\r
+\r
+ if [ $testMode -eq 1 -o $verboseMode -eq 1 ]; then\r
+ echo "mkdir -p $1" 1>&4\r
+ fi\r
+\r
+ if [ $testMode -eq 0 ]; then\r
+ mkdir -p "$1"\r
+ if [ $? -ne 0 ]; then\r
+ echo "Error creating $1" 1>&2\r
+ exit 1\r
+ fi\r
+ fi\r
+ fi\r
+}\r
+\r
+\r
+#if [ $testMode -eq 1 ]; then\r
+# echo "Running in test mode"\r
+#fi\r
+\r
+if [ $archiveMode -eq 0 ]; then\r
+ createDir $targetDir 4>&1\r
+fi\r
+\r
+if [ $verboseMode -eq 1 ]; then\r
+ echo "Copying to target directory: $targetDir"\r
+fi\r
+\r
+# Testing for $BASH will not work, if you happen to use the cygwin sh instead of\r
+# bash.\r
+unset PWD\r
+codelineRoot=`p4 info | sed -n -e 's;\\\\;/;g' -e 's/Client root: //p'`\r
+#echo "---codelineRoot=$codelineRoot"\r
+rootDirLength=${#codelineRoot}\r
+\r
+if [ $archiveMode -eq 1 ]; then\r
+ fileExt=''\r
+ if [ ${targetDir%.zip} = $targetDir ]; then\r
+ fileExt='.zip'\r
+ fi\r
+ pipeCmd="zip ${archiveOpts} -@ ${targetDir}${fileExt}"\r
+ echo "Using: '${pipeCmd}' to create zip archive"\r
+elif [ $archiveMode -eq 2 ]; then\r
+ fileExt=''\r
+ if [ $compressedTar -eq 1 -a ${targetDir%.tar.$tarExt} = $targetDir ]; then\r
+ fileExt=".tar.$tarExt"\r
+ elif [ $compressedTar -ne 1 -a ${targetDir%.tar} = $targetDir ]; then\r
+ fileExt='.tar'\r
+ fi\r
+ pipeCmd="tar -vf ${targetDir}${fileExt} ${archiveOpts} -T -"\r
+ echo "Using: '${pipeCmd}' to create tar archive"\r
+else\r
+ pipeCmd="cat"\r
+fi\r
+\r
+exec 4>&1; {\r
+ for sourceDir in $sourceDirs; do\r
+ if [ ! -f $sourceDir ]; then\r
+ case $sourceDir in\r
+ *...)\r
+ ;;\r
+ */)\r
+ sourceDir="${sourceDir}..."\r
+ ;;\r
+ *)\r
+ sourceDir="${sourceDir}/..."\r
+ ;;\r
+ esac\r
+ fi\r
+ if [ "$changeNumber" = "" ]; then\r
+ openedCmd="p4 opened $sourceDir"\r
+ else\r
+ openedCmd="p4 opened -c $changeNumber $sourceDir"\r
+ fi\r
+ if [ $verboseMode -eq 1 ]; then\r
+ echo "Collecing list of open files using: $openedCmd" 1>&4\r
+ fi\r
+\r
+ # FIXME: I couldn't get it working with the following IFS, don't know\r
+ # why. So as a temp. work-around, I am temporarily substituting spaces\r
+ # with '|' in sed and converting them back to spaces in the start of the\r
+ # loop.\r
+ #IFS="\n\r"\r
+ openedFiles=`$openedCmd | \\r
+ sed -e '/ - delete \(default \)\?change /d' \\r
+ -e 's/#.*//' |\r
+ p4 -x - where | \\r
+ sed -e 's;.\+/[^/]\+/\([^ /]\+\) //.*\1 \(.*\1\);\2;' \\r
+ -e "s;^${chDirectory}/*;;" \\r
+ -e 's/ /|/g' \\r
+ -e 's;\\\\;/;g'`\r
+ for file in `echo $openedFiles`; do\r
+ file=${file//\|/ }\r
+ #echo "---file = $file" 1>&4\r
+ dir=`dirname "$file"`\r
+ # Relative to the codeline root.\r
+ tgtDir="${targetDir}/${dir:$rootDirLength}"\r
+ #echo "---tgtDir = $tgtDir" 1>&4\r
+\r
+ if [ $archiveMode -eq 0 ]; then\r
+ createDir "$tgtDir"\r
+ fi\r
+\r
+ if [ $archiveMode -ne 0 ]; then\r
+ echo $file 1>&3\r
+ elif [ $testMode -eq 1 -o $verboseMode -eq 1 ]; then\r
+ echo "cp \"$file\" \"$tgtDir\"" 1>&4\r
+ fi\r
+ if [ $testMode -eq 0 ]; then\r
+ cp "$file" "$tgtDir"\r
+ if [ $? -ne 0 ]; then\r
+ echo "Error copying $1" 1>&2\r
+ exit 1\r
+ fi\r
+ fi\r
+ done\r
+ done\r
+} 3>&1 | $pipeCmd\r
+\r
+# vim6: et sw=4\r