Added Perforce plugin.
[profile.git] / .vim / perforce / bakup.sh
1 #!/bin/bash\r
2 # Author: Hari Krishna Dara ( hari_vim at yahoo dot com ) \r
3 # Last Change: 17-Mar-2004 @ 18:47\r
4 # Requires:\r
5 #   - bash or ksh (tested on cygwin and MKS respectively).\r
6 #   - Info Zip for the -z option to work (comes with linux/cygwin). Download for\r
7 #     free from:\r
8 #       http://www.info-zip.org/\r
9 #   - GNU tar for the -a option to work (comes with linux/cygwin).\r
10 # Version: 1.4.2\r
11 # Licence: This program is free software; you can redistribute it and/or\r
12 #          modify it under the terms of the GNU General Public License.\r
13 #          See http://www.gnu.org/copyleft/gpl.txt \r
14 # Description:\r
15 #   Shell script to take backup of all the open files in perforce SCM.\r
16 #\r
17 #TODO:\r
18 #   - Zip comment option -zz is no longer working?\r
19 #   - To create cpio archives, I can use "cpio -o -H | gzip" command.\r
20 #   - Option to generate a diff at the end.\r
21 #   - Option to restrict by type (useful to avoid huge binary files).\r
22 #   - Support to run zip from a different directory (to avoid certain path\r
23 #     component from getting into zipfile).\r
24 \r
25 usage()\r
26 {\r
27 cat <<END\r
28 $0 [<backup dir>] [<source dir>] ...\r
29 $0 -h -n -q -v -z -zz [-c <change number>] [-t <backup dir>] [-r <backup root>] [[-s <source dir>] ...]\r
30     -t specify full path name to the target directory. If -z is specified this\r
31        becomes the path to the zip file name.\r
32     -r set the root for creating the default backup dir/zip file. Not used if\r
33        "backup dir" is specified. You can also set BAKUP_ROOT environmental\r
34        variable. Defaults to p: (p drive), because that is what it is on my\r
35        system :).\r
36     -i incremental backup, which makes the program use the previous backup\r
37        directory/archive for that day (if it exists) instead of creating a new\r
38        one. For tar (with "-a" option), you will have to provide one of the\r
39        relevant options to force reuse an existing archive ("-ar" e.g.) or the\r
40        existing archive will simply get overwritten. However this will not work\r
41        with compressed tar archives. You can also specify any existing backup\r
42        directory/archive path explicitly by using the "-t" option.\r
43     -a create a tar file instead of copying the files. You can specify the\r
44        tar file name using -t option.\r
45     -a[-|--]<taropt>\r
46        Pass -taropt to tar command.\r
47        Ex:\r
48         - Pass "-aC <dir>" or "-adirectory=<dir>" to cd to a directory before\r
49           creating the tar file (thus dropping file component).\r
50         - Pass "-az" to gzip the created tar file.\r
51     -z create a zip file instead of copying the files. You can specify the\r
52        zip file name using -t option.\r
53     -z[-]<zipopt>\r
54        Pass -zipopt to zip command.\r
55        Ex: Pass -zz for a prompt from zip to enter a comment.\r
56     -s limit to open files matching the given wildcard (local or depot). This\r
57        can be repeated multiple times to specify multiple source directories.\r
58        You can pass in anything that the 'p4 opened' command itself accepts.\r
59     -c limit the files to those specified in the change number, in addition to\r
60        the -s option. This can't be repeated multiple times though.\r
61     -n don't execute any commands, just show what is going to be done. Does not\r
62        currently work with -z option.\r
63     -q quite mode, no messages\r
64     -v verbose mode, print messages (the default).\r
65     -h print help message (this message) and exit\r
66   The first unspecified directory is treated as target directory, and the\r
67   remaining directories are treated as source directories. The '-n' option can\r
68   be used to generate a batch script that can be run later. The source\r
69   directory can be in depot or local format (NO BACKSLASHES PLEASE). Do not\r
70   combine multiple options into one argument.\r
71 Examples:\r
72      bakup.sh\r
73          - Backup all the open files into a default generated backup dir. in p:\r
74            drive (p: driver is the default backup directory).\r
75      bakup.sh mybak c:/dev/branch/src\r
76          - Backup open files only under 'c:/dev/branch/src' into 'mybak'\r
77            directory.\r
78      bakup.sh -s //depot/branch/src -s //depot/branch/cfg\r
79          - Backup open files only under 'src' and 'cfg' into the default bakup\r
80            dir.\r
81 \r
82      You could add -z option to all the above usages to create a zip file\r
83      instead of creating a directory. You need to have Info-Zip installed in the\r
84      path for this to work.\r
85 \r
86      bakup.sh -n > mybackup.bat\r
87          - Generates a 'mybackup.bat' batch file that can be run at a later\r
88            time to take a backup. The files to be backed up are based on the\r
89            time the script was generated, so it should be regenerated if the\r
90            list has changed since then.\r
91 END\r
92 exit 1\r
93 }\r
94 \r
95 generateTargetDirName()\r
96 {\r
97     today=`date +"%d-%b-%Y"`\r
98     inc=1\r
99     #echo "---first time"\r
100     tDir="$targetRoot/bakup-$today"\r
101     prevDir=$tDir\r
102     while [ -d $tDir -o -f $tDir.* ]; do\r
103         inc=$[inc + 1]\r
104         prevDir=$tDir\r
105         tDir="$targetRoot/bakup-${today}_$inc"\r
106         #echo "---subsequent time inc=$inc tDir=$tDir"\r
107     done\r
108     if [ $incrementalMode -ne 0 ]; then\r
109         tDir=$prevDir # Backup one level to use an existing db.\r
110     fi\r
111     echo "$tDir"\r
112 }\r
113 \r
114 getExtOpt()\r
115 {\r
116     archiveOpt=${1/[-+]$2/}\r
117     case $archiveOpt in\r
118     --*)\r
119         ;;\r
120     -??*) # Mistyped long option\r
121         archiveOpt="-$archiveOpt"\r
122         ;;\r
123     -*)\r
124         ;;\r
125     ??*) # Long option.\r
126         archiveOpt="--$archiveOpt"\r
127         ;;\r
128     *)\r
129         archiveOpt="-$archiveOpt"\r
130         ;;\r
131     esac\r
132     echo $archiveOpt\r
133 }\r
134 \r
135 #getExtOpt '-a--directory' 'a'\r
136 #getExtOpt '-a-directory' 'a'\r
137 #getExtOpt '-adirectory' 'a'\r
138 #getExtOpt '-aC' 'a'\r
139 #getExtOpt '-a-C' 'a'\r
140 #exit\r
141 \r
142 checkOptArg='\r
143     shift;\r
144     if [ $# -eq 0 ]; then\r
145         usage;\r
146     fi\r
147 '\r
148 \r
149 testMode=0\r
150 archiveOpts=''\r
151 chDirectory='' # If set, the listing is generated relative to this dir.\r
152 archiveMode=0\r
153 verboseMode=1\r
154 targetDir=""\r
155 targetRoot=""\r
156 sourceDirs=""\r
157 changeNumber=""\r
158 compressedTar=0\r
159 incrementalMode=0\r
160 until [ $# -eq 0 ]; do\r
161     case $1 in\r
162     -h|-help|--help)\r
163         usage\r
164         ;;\r
165     -v)\r
166         verboseMode=1\r
167         ;;\r
168     -q)\r
169         verboseMode=0\r
170         ;;\r
171     -i)\r
172         incrementalMode=1\r
173         ;;\r
174     -a)\r
175         archiveMode=2 # Tar.\r
176         verboseMode=0 # Turn on quite mode, as zip will anyway show the files.\r
177         testMode=1 # Turn on test mode, so we won't copy files.\r
178         ;;\r
179     -a*)\r
180         # Need to take care of options with optional args.\r
181         extOpt=`getExtOpt $1 a`\r
182         if [ $extOpt = -z -o $extOpt = -Z -o $extOpt = -j ]; then\r
183             compressedTar=1\r
184             tarExt=`echo $extOpt | awk 'BEGIN{ext["-j"]="bz2";ext["-z"]="gz";ext["-Z"]="Z";}{print ext[$0];}'`\r
185         fi\r
186         archiveOpts="${archiveOpts} $extOpt"\r
187         case $extOpt in\r
188         --directory)\r
189             chDirectory=${extOpt/*=}\r
190             ;;\r
191         -C)\r
192             eval $checkOptArg\r
193             chDirectory=$1\r
194             #echo "---setting chDirectory=$chDirectory"\r
195             archiveOpts="${archiveOpts} $chDirectory"\r
196             ;;\r
197         esac\r
198         ;;\r
199     -z)\r
200         archiveMode=1 # Zip.\r
201         verboseMode=0 # Turn on quite mode, as zip will anyway show the files.\r
202         testMode=1 # Turn on test mode, so we won't copy files.\r
203         ;;\r
204     -z*)\r
205         # Need to take care of options with optional args.\r
206         archiveOpts="${archiveOpts} `getExtOpt $1 z`"\r
207         ;;\r
208     -n)\r
209         testMode=1\r
210         verboseMode=0\r
211         ;;\r
212     -c)\r
213         eval $checkOptArg\r
214         changeNumber=$1\r
215         ;;\r
216     -t)\r
217         eval $checkOptArg\r
218         targetDir=$1\r
219         ;;\r
220     -r)\r
221         eval $checkOptArg\r
222         targetRoot=$1\r
223         ;;\r
224     -s)\r
225         eval $checkOptArg\r
226         sourceDirs="$sourceDirs $1"\r
227         #echo "---setting sourceDirs=$sourceDirs"\r
228         ;;\r
229     -?)\r
230         usage\r
231         ;;\r
232     *)\r
233         if [ "$targetDir" = "" ]; then\r
234             #echo "---setting targetDir=$targetDir"\r
235             targetDir=$1\r
236         else\r
237             #echo "---appending sourceDirs=$1"\r
238             sourceDirs="$sourceDirs $1"\r
239         fi\r
240         ;;\r
241     esac\r
242     shift\r
243 done\r
244 \r
245 # For tar, we can add -a option only if no other equivalent option is specified.\r
246 if [ $archiveMode -eq 2 ]; then\r
247     case $archiveOpts in\r
248     *-[Acdtrux]*)\r
249         ;;\r
250     *)\r
251         archiveOpts="$archiveOpts -c"\r
252         ;;\r
253     esac\r
254 fi\r
255 \r
256 if [ x${targetDir}x = xx -a x${targetRoot}x = xx ]; then\r
257     targetRoot=$BAKUP_ROOT\r
258     if [ "$targetRoot" = "" ]; then\r
259         targetRoot="p:"\r
260     fi\r
261 fi\r
262 \r
263 if [ "$targetDir" = "" ]; then\r
264     targetDir=`generateTargetDirName`\r
265 fi\r
266 \r
267 if [ "$sourceDirs" = "" ]; then\r
268     # By default backup all the open files.\r
269     sourceDirs="//..."\r
270 fi\r
271 \r
272 \r
273 # Create a dir if it doesn't exist, exit on error.\r
274 createDir()\r
275 {\r
276     if ! [ -d "$1" ]; then\r
277 \r
278         if [ $testMode -eq 1 -o $verboseMode -eq 1 ]; then\r
279             echo "mkdir -p $1" 1>&4\r
280         fi\r
281 \r
282         if [ $testMode -eq 0 ]; then\r
283             mkdir -p "$1"\r
284             if [ $? -ne 0 ]; then\r
285                 echo "Error creating $1" 1>&2\r
286                 exit 1\r
287             fi\r
288         fi\r
289     fi\r
290 }\r
291 \r
292 \r
293 #if [ $testMode -eq 1 ]; then\r
294 #    echo "Running in test mode"\r
295 #fi\r
296 \r
297 if [ $archiveMode -eq 0 ]; then\r
298     createDir $targetDir 4>&1\r
299 fi\r
300 \r
301 if [ $verboseMode -eq 1 ]; then\r
302     echo "Copying to target directory: $targetDir"\r
303 fi\r
304 \r
305 # Testing for $BASH will not work, if you happen to use the cygwin sh instead of\r
306 #   bash.\r
307 unset PWD\r
308 codelineRoot=`p4 info | sed -n -e 's;\\\\;/;g' -e 's/Client root: //p'`\r
309 #echo "---codelineRoot=$codelineRoot"\r
310 rootDirLength=${#codelineRoot}\r
311 \r
312 if [ $archiveMode -eq 1 ]; then\r
313     fileExt=''\r
314     if [ ${targetDir%.zip} = $targetDir ]; then\r
315         fileExt='.zip'\r
316     fi\r
317     pipeCmd="zip ${archiveOpts} -@ ${targetDir}${fileExt}"\r
318     echo "Using: '${pipeCmd}' to create zip archive"\r
319 elif [ $archiveMode -eq 2 ]; then\r
320     fileExt=''\r
321     if [ $compressedTar -eq 1 -a ${targetDir%.tar.$tarExt} = $targetDir ]; then\r
322         fileExt=".tar.$tarExt"\r
323     elif [ $compressedTar -ne 1 -a ${targetDir%.tar} = $targetDir ]; then\r
324         fileExt='.tar'\r
325     fi\r
326     pipeCmd="tar -vf ${targetDir}${fileExt} ${archiveOpts} -T -"\r
327     echo "Using: '${pipeCmd}' to create tar archive"\r
328 else\r
329     pipeCmd="cat"\r
330 fi\r
331 \r
332 exec 4>&1; {\r
333     for sourceDir in $sourceDirs; do\r
334         if [ ! -f $sourceDir ]; then\r
335             case $sourceDir in\r
336                 *...)\r
337                     ;;\r
338                 */)\r
339                     sourceDir="${sourceDir}..."\r
340                     ;;\r
341                 *)\r
342                     sourceDir="${sourceDir}/..."\r
343                     ;;\r
344             esac\r
345         fi\r
346         if [ "$changeNumber" = "" ]; then\r
347             openedCmd="p4 opened $sourceDir"\r
348         else\r
349             openedCmd="p4 opened -c $changeNumber $sourceDir"\r
350         fi\r
351         if [ $verboseMode -eq 1 ]; then\r
352             echo "Collecing list of open files using: $openedCmd" 1>&4\r
353         fi\r
354 \r
355         # FIXME: I couldn't get it working with the following IFS, don't know\r
356         # why. So as a temp. work-around, I am temporarily substituting spaces\r
357         # with '|' in sed and converting them back to spaces in the start of the\r
358         # loop.\r
359         #IFS="\n\r"\r
360         openedFiles=`$openedCmd | \\r
361                      sed -e '/ - delete \(default \)\?change /d' \\r
362                          -e 's/#.*//' |\r
363                      p4 -x - where | \\r
364                      sed -e 's;.\+/[^/]\+/\([^ /]\+\) //.*\1 \(.*\1\);\2;' \\r
365                          -e "s;^${chDirectory}/*;;" \\r
366                          -e 's/ /|/g' \\r
367                          -e 's;\\\\;/;g'`\r
368         for file in `echo $openedFiles`; do\r
369             file=${file//\|/ }\r
370             #echo "---file = $file" 1>&4\r
371             dir=`dirname "$file"`\r
372             # Relative to the codeline root.\r
373             tgtDir="${targetDir}/${dir:$rootDirLength}"\r
374             #echo "---tgtDir = $tgtDir" 1>&4\r
375 \r
376             if [ $archiveMode -eq 0 ]; then\r
377                 createDir "$tgtDir"\r
378             fi\r
379 \r
380             if [ $archiveMode -ne 0 ]; then\r
381                 echo $file 1>&3\r
382             elif [ $testMode -eq 1 -o $verboseMode -eq 1 ]; then\r
383                 echo "cp \"$file\" \"$tgtDir\"" 1>&4\r
384             fi\r
385             if [ $testMode -eq 0 ]; then\r
386                 cp "$file" "$tgtDir"\r
387                 if [ $? -ne 0 ]; then\r
388                     echo "Error copying $1" 1>&2\r
389                     exit 1\r
390                 fi\r
391             fi\r
392         done\r
393     done\r
394 } 3>&1 | $pipeCmd\r
395 \r
396 # vim6: et sw=4\r