Fix compiler warning due to missing function prototype.
[svn.git] / contrib / client-side / asvn
blob5571664c0bb10a867fd073af7c56da07d122ff71
1 #!/bin/bash
2 #-------------------------------------------------------------------------
3 # Author: Ross Mark (rossm@controllingedge.com.au)
4 # Date: Tue Mar 11 10:02:57 EST 2003
6 # Copyright (C) 2003-2004 Ross Mark
8 #-------------------------------------------------------------------------
10 # Description:
11 # Archive SVN (asvn) will allow the recording of file types not
12 # normally handled by svn. Currently this includes devices,
13 # symlinks and file ownership/permissions.
15 # Every file and directory has a 'file:permissions' property set and
16 # every directory has a 'dir:devices' and 'dir:symlinks' for
17 # recording the extra information.
19 # Run this script instead of svn with the normal svn arguments.
22 # Licensing:
23 # This program is free software; you can redistribute it and/or modify
24 # it under the terms of the GNU General Public License as published by
25 # the Free Software Foundation; either version 2 of the License, or
26 # (at your option) any later version.
28 # This program is distributed in the hope that it will be useful,
29 # but WITHOUT ANY WARRANTY; without even the implied warranty of
30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 # GNU General Public License for more details.
33 # You should have received a copy of the GNU General Public License
34 # along with this program; if not, write to the Free Software
35 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 #-------------------------------------------------------------------------
40 # $HeadURL$
41 # $LastChangedDate$
42 # $LastChangedBy$
43 # $LastChangedRevision$
45 SVN=/usr/bin/svn
46 ACTION=""
47 DEV_PROP="dir:devices"
48 SYM_PROP="dir:symlinks"
49 FILE_PROP="file:permissions"
50 TMPFILE=/tmp/asvn.tmp.$$
51 TMPFILE1=/tmp/asvn.tmp1.$$
52 TMPFILE2=/tmp/asvn.tmp2.$$
53 PCWD=`/bin/pwd`
54 SKIPSVN='\( -name .svn -prune -false \)'
55 PRINTDETAILS="-printf \"file='%p' mode=%m user=%u(%U) group=%g(%G)\n\""
57 trap cleanup 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
59 function cleanup()
61 rm -f $TMPFILE $TMPFILE1 $TMPFILE2
64 function basedirname()
66 refname="$1"
67 dir="`dirname \"$2\"`"
68 ref="`expr \"$dir\" : \"$refname/\(.*\)\"`"
69 if [ -z "$ref" ]
70 then
71 echo .
72 else
73 echo $ref
78 # Modifies TMPFILE2
80 function addignorefile()
82 file="`basename \"$1\"`"
83 dir="`dirname \"$1\"`"
85 efile="`echo $file |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
86 gefile="`echo $efile |sed -e 's!\(\\\\\)!\\\\\\\\\1!g'`"
87 if ! ($SVN propget svn:ignore "$dir" | grep -q "^$gefile\$")
88 then
89 $SVN propget svn:ignore "$dir" |sed -e '/^$/d' >$TMPFILE2
90 echo "$efile" >>$TMPFILE2
91 $SVN propset svn:ignore -F $TMPFILE2 "$dir"
92 echo setting ignore
93 #cat $TMPFILE2 >&2
97 function deleteignorefile()
99 file="`basename \"$1\"`"
100 dir="`dirname \"$1\"`"
101 efile="`echo $file |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
102 gefile="`echo $efile |sed -e 's!\(\\\\\)!\\\\\\\\\1!g'`"
103 echo "deleting ignore setting for '$file'"
104 if ($SVN propget svn:ignore "$dir" | grep -q "^$gefile\$")
105 then
106 $SVN propget svn:ignore "$dir" |sed -e '/^$/d' |grep -v "^$gefile\$" >$TMPFILE2
107 $SVN propset svn:ignore -F $TMPFILE2 "$dir"
108 #cat $TMPFILE2 >&2
112 function recorddirinfo
114 eval "find $PCWD $SKIPSVN -o \( -type d ! -name .svn -print \)" |while read dirlist
116 updatedirsymlinks $1 "$dirlist"
117 updatedirdevices $1 "$dirlist"
118 done
121 function updatedirdevices()
123 CHECKIN=false
124 if [ "$1" = "-ci" ]
125 then
126 CHECKIN=true
127 shift
129 dir="$1"
131 echo checking $dir for devices
133 # Obtain the list of devices in this directory
135 find "$dir" \( \( -type b -o -type c -o -type p \) -print \) -o -type d ! -name "`basename \"$dir\"`" -prune | while read file
137 echo -n `find "$file" -printf "file='%f' mode=%m user=%u(%U) group=%g(%G)"`
138 [ -b "$file" ] && echo -n ' type=b'
139 [ -c "$file" ] && echo -n ' type=c'
140 [ -p "$file" ] && echo ' type=p'
141 if [ -b "$file" -o -c "$file" ]
142 then
143 ls -l "$file" |
144 sed -e 's/^[-lcpbrdwxXstugoTS]* *[0-9] [^ ]* *[^ ]* *\([0-9]*\), *\([0-9]*\) .*/ major=\1 minor=\2/'
146 # In this case file is the full path.
147 addignorefile "$file"
149 done | sort >$TMPFILE
152 # Obtain the currently defined devices
154 $SVN propget $DEV_PROP "$dir" >$TMPFILE1
157 # If the two list are the same then there is nothing to do.
159 if /usr/bin/cmp $TMPFILE1 $TMPFILE >/dev/null
160 then
161 return
164 if [ -s $TMPFILE ]
165 then
166 # There are devices in this directory
167 if [ "$CHECKIN" = "true" ]
168 then
169 # Add the current devices to the property
170 $SVN propset $DEV_PROP "$dir" -F $TMPFILE
171 else
172 # Delete all the unwanted devices ie not in TMPFILE1
173 cat $TMPFILE |while read line
175 file="`expr \"$line\" : \"file='\(.*\)' mode\"`"
176 if ! grep -q "file='$file'" $TMPFILE1
177 then
178 rm "$file"
179 deleteignorefile "$file"
181 done
183 else
184 # There are no devices in this directory
185 if [ "$CHECKIN" = "true" ]
186 then
187 $SVN propdel $DEV_PROP "$dir"
192 # If we are not a checkin then make sure all the devices are defined
194 if [ "$CHECKIN" != "true" ]
195 then
196 cat $TMPFILE1 |while read info
198 #echo info = $info
199 [ -z "$info" ] && continue
200 grep -q "$info" $TMPFILE && continue # This line still matches
201 file="`expr \"$info\" : \"file='\(.*\)' \"`"
202 mode=`expr "$info" : ".*' mode=\([0-9]*\) "`
203 user=`expr "$info" : ".* user=\([^(]*\)("`
204 uid=`expr "$info" : ".* user=[^(]*(\([0-9]*\) "`
205 group=`expr "$info" : ".* group=\([^(]*\)("`
206 gid=`expr "$info" : ".* group=[^(]*(\([0-9]*\) "`
207 type=`expr "$info" : ".* type=\(.\)"`
208 major=`expr "$info" : ".* major=\([0-9]*\)"`
209 minor=`expr "$info" : ".* minor=\([0-9]*\)"`
211 # This file is either missing or wrong
212 # Delete the old and create it anew.
214 rm -f "$dir/$file"
215 mknod --mode=$mode "$dir/$file" $type $major $minor
216 chown $user:$group "$dir/$file"
217 addignorefile "$dir/$file"
218 done
222 function updatedirsymlinks()
224 CHECKIN=false
225 if [ "$1" = "-ci" ]
226 then
227 CHECKIN=true
228 shift
230 dir="$1"
232 echo checking $dir for symlinks
233 cp /dev/null $TMPFILE
235 # Obtain the list of symlinks in this directory
237 find "$dir" \( -type l -printf "file='%f' dest='%l'\n" \) -o -type d ! -name "`basename \"$dir\"`" -prune |
238 sort >$TMPFILE
241 # Make sure all the symlinks are being ignored.
243 cat $TMPFILE |while read line
245 file="`expr \"$line\" : \"file='\(.*\)' dest\"`"
246 addignorefile "$dir/$file"
247 done
250 # Obtain the currently defined symlinks
252 $SVN propget $SYM_PROP "$dir" >$TMPFILE1
255 # If the two list are the same then there is nothing to do.
257 if cmp $TMPFILE1 $TMPFILE >/dev/null
258 then
259 return
262 if [ -s $TMPFILE ]
263 then
264 # There are symlinks in this directory
265 if [ "$CHECKIN" = "true" ]
266 then
267 # Add the current symlinks to the property
268 $SVN propset $SYM_PROP "$dir" -F $TMPFILE
269 else
270 # Delete all the unwanted symlinks
271 cat $TMPFILE |while read line
273 file="`expr \"$line\" : \"file='\(.*\)' dest\"`"
274 efile="`echo \"$file\" |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
275 if ! grep -q "file='$efile'" $TMPFILE1
276 then
277 rm "$dir/$file"
278 deleteignorefile "$dir/$file"
280 done
282 else
283 # There are no symlinks in this directory
284 if [ "$CHECKIN" = "true" ]
285 then
286 $SVN propdel $SYM_PROP "$dir"
291 # If we are not a checkin then make sure all the symlinks are defined
293 if [ "$CHECKIN" != "true" ]
294 then
295 cat $TMPFILE1 |while read info
297 [ -z "$info" ] && continue
298 file="`expr \"$info\" : \"file='\(.*\)' dest\"`"
299 dest="`expr \"$info\" : \".*' dest='\(.*\)'$\"`"
301 if [ -L "$dir/$file" ]
302 then
303 [ "`find \"$dir/$file\" -printf '%l'`" = "$dest" ] && continue
305 rm -f "$dir/$file"
306 ln -s "$dest" "$dir/$file"
307 done
311 function recordpermissions()
313 CHECKIN=false
314 if [ "$1" = "-ci" ]
315 then
316 CHECKIN=true
317 shift
320 # Find all the directories and files
321 cp /dev/null $TMPFILE
323 eval "find $PCWD $SKIPSVN -o \( \( -type d ! -name .svn \) -o -type f \) $PRINTDETAILS" | while read info
325 device=`expr "$info" : "file='\(.*\)' mode"`
326 info=`expr "$info" : "file='.*' \(mode.*\)"`
328 if [ "$PCWD" = "$device" ]
329 then
330 dir="."
331 file=""
332 else
333 dir="`basedirname \"$PCWD\" \"$device\"`"
334 file="`basename \"$device\"`"
337 # see if the properties have changed.
338 if [ "`$SVN propget $FILE_PROP \"$dir/$file\"`" != "$info" ]
339 then
340 if [ "$CHECKIN" = "true" ]
341 then
342 $SVN propset $FILE_PROP "$info" "$dir/$file"
343 else
344 info=`$SVN propget $FILE_PROP "$dir/$file"`
345 mode=`expr "$info" : "mode=\([0-9]*\) "`
346 user=`expr "$info" : ".* user=\([^(]*\)("`
347 uid=`expr "$info" : ".* user=[^(]*(\([0-9]*\) "`
348 group=`expr "$info" : ".* group=\([^(]*\)("`
349 gid=`expr "$info" : ".* group=[^(]*(\([0-9]*\) "`
350 if [ "$user" = "" -o "$group" = "" -o "$mode" = "" ]
351 then
352 echo "property $FILE_PROP not set for $dir/$file"
353 else
354 chown $user:$group "$dir/$file"
355 chmod $mode "$dir/$file"
359 done
363 function pre_checkin()
365 echo this is the pre checkin process
366 recorddirinfo -ci
367 recordpermissions -ci
370 function post_checkout()
372 echo this is the post checkout process
373 if [ "$CHDIR" = "true" ]
374 then
375 shift $(($# -1))
376 cd "`basename \"$1\"`"
377 PCWD="$PCWD/`basename \"$1\"`"
379 recorddirinfo
380 recordpermissions
383 CHDIR=false
384 case "$1" in
385 checkout|co) CHDIR=true; ACTION="post";;
386 commit|ci) ACTION="pre";;
387 switch|sw) ACTION="post";;
388 update|up) ACTION="post";;
389 *);;
390 esac
392 [ "$ACTION" = "pre" ] && pre_checkin $@
394 $SVN $@
396 [ $? = 0 -a "$ACTION" = "post" ] && post_checkout $@
398 cleanup
400 # vim: set ai ts=8 sw=4