[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Svn add issue

From: Ross Mark <rossm_at_controllingedge.com.au>
Date: 2003-08-12 03:09:24 CEST

Sander Striker wrote:

>>From: Ross Mark [mailto:rossm@controllingedge.com.au]
>>Sent: Tuesday, August 12, 2003 12:53 AM
>>
>>
>>Well there is but it takes a small wrapper script around svn to save the
>>symlink as a property of the directory plus add it to the ignore file. I
>>use subversion for maintaining entire filesystems so my wrapper takes
>>care of symlinks, devices plus ownership and permissions. If updates
>>only set the modification time on the file to what was in the repository
>>I would be very happy.
>>
>>
>
>Would you be willing to include that script in contrib/ ?
>
>Sander
>
>
>
Sure I would be happy to share it around. All I know is that it works on
mine and a few other machines from RH7.2 to 8.0 so there may be some
portability issues. Plus I don't know how it will handle different
filenames ie spaces and extended character sets. It also assumes that
every file and directory is under version control..

I've attached it to this email. I called it asvn for Archive SVN. Seemed
good at the time. It is run as a direct replacement for svn. The only
mistake I have made is that I didn't choose a very good name space for
the properties that I used but since I already have a number of
repositories that are using it I can't be bothered to change them.

Hope someone gets some use from this.

Ross

#!/bin/bash
#-------------------------------------------------------------------------
# Author: Ross Mark (rossm@controllingedge.com.au)
# Date: Tue Mar 11 10:02:57 EST 2003
#
# Document Id: 104.733.737
#
# Copyright (C) 2003 Controlling Edge Pty Ltd
#
#-------------------------------------------------------------------------
#
# Description:
# Archive SVN (asvn) will allow the recording of file types not
# normally handled by svn. Currently this includes devices,
# symlinks and file ownership/permissions.
#
# Every file and directory has a 'file:permissions' property set and
# every directory has a 'dir:devices' and 'dir:symlinks' for
# recording the extra information.
#
# Run this script instead of svn with the normal svn arguments.
#
# This script worked for me yesterday on my machine and I hope it will
# continue to work tomorrow. If you run this program then
# risk and blame are yours.
#
#-------------------------------------------------------------------------
SVN=/usr/local/bin/svn
ACTION=""
DEV_PROP="dir:devices"
SYM_PROP="dir:symlinks"
FILE_PROP="file:permissions"
TMPFILE=/tmp/asvn.tmp.$$
TMPFILE1=/tmp/asvn.tmp1.$$
TMPFILE2=/tmp/asvn.tmp2.$$
PCWD=`/bin/pwd`
SKIPSVN='\( -name .svn -prune -false \)'
PRINTDETAILS="-printf \"file='%p' mode=%m user=%u(%U) group=%g(%G)\n\""

trap cleanup 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

function cleanup()
{
    rm -f $TMPFILE $TMPFILE1 $TMPFILE2
}

function basedirname()
{
    refname="$1"
    dir="`dirname $2`"
    ref=`expr "$dir" : "$refname/\(.*\)"`
    if [ -z "$ref" ]
    then
        echo .
    else
        echo $ref
    fi
}

#
# Modifies TMPFILE2
#
function addignorefile()
{
    file=`basename $1`
    dir=`dirname $1`

    efile="`echo $file |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
    gefile="`echo $efile |sed -e 's!\(\\\\\)!\\\\\\\\\1!g'`"
    if ! ($SVN propget svn:ignore "$dir" | grep -q "^$gefile\$")
    then
        $SVN propget svn:ignore "$dir" |sed -e '/^$/d' >$TMPFILE2
        echo "$efile" >>$TMPFILE2
        $SVN propset svn:ignore -F $TMPFILE2 "$dir"
        echo setting ignore
#cat $TMPFILE2 >&2
    fi
}

function deleteignorefile()
{
    file=`basename $1`
    dir=`dirname $1`
    efile="`echo $file |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
    gefile="`echo $efile |sed -e 's!\(\\\\\)!\\\\\\\\\1!g'`"
    echo "deleting ignore setting for '$file'"
    if ($SVN propget svn:ignore "$dir" | grep -q "^$gefile\$")
    then
        $SVN propget svn:ignore "$dir" |sed -e '/^$/d' |grep -v "^$gefile\$" >$TMPFILE2
        $SVN propset svn:ignore -F $TMPFILE2 "$dir"
#cat $TMPFILE2 >&2
    fi
}

function recorddirinfo
{
    eval "find $PCWD $SKIPSVN -o \( -type d ! -name .svn -print \)" |while read dirlist
    do
        updatedirsymlinks $1 $dirlist
        updatedirdevices $1 $dirlist
    done
}

function updatedirdevices()
{
    CHECKIN=false
    if [ "$1" = "-ci" ]
    then
        CHECKIN=true
        shift
    fi
    dir="$1"

    echo checking $dir for devices
    #
    # Obtain the list of devices in this directory
    #
    find "$dir" \( \( -type b -o -type c -o -type p \) -print \) -o -type d ! -name "`basename $dir`" -prune | while read file
    do
        echo -n `find $file -printf "file='%f' mode=%m user=%u(%U) group=%g(%G)"`
        [ -b $file ] && echo -n ' type=b'
        [ -c $file ] && echo -n ' type=c'
        [ -p $file ] && echo ' type=p'
        if [ -b $file -o -c $file ]
        then
            ls -l $file |
                sed -e 's/^[-lcpbrdwxXstugoTS]* *[0-9] [^ ]* *[^ ]* *\([0-9]*\), *\([0-9]*\) .*/ major=\1 minor=\2/'
        fi
        # In this case file is the full path.
        addignorefile "$file"

    done | sort >$TMPFILE

    #
    # Obtain the currently defined devices
    #
    $SVN propget $DEV_PROP $dir >$TMPFILE1

    #
    # If the two list are the same then there is nothing to do.
    #
    if /usr/bin/cmp $TMPFILE1 $TMPFILE >/dev/null
    then
        return
    fi

    if [ -s $TMPFILE ]
    then
        # There are devices in this directory
        if [ "$CHECKIN" = "true" ]
        then
            # Add the current devices to the property
            $SVN propset $DEV_PROP $dir -F $TMPFILE
        else
            # Delete all the unwanted devices ie not in TMPFILE1
            cat $TMPFILE |while read line
            do
                file=`expr "$line" : "file='\(.*\)' mode"`
                if ! grep -q "file='$file'" $TMPFILE1
                then
                    rm $file
                    deleteignorefile $file
                fi
            done
        fi
    else
        # There are no devices in this directory
        if [ "$CHECKIN" = "true" ]
        then
            $SVN propdel $DEV_PROP $dir
        fi
    fi

    #
    # If we are not a checkin then make sure all the devices are defined
    #
    if [ "$CHECKIN" != "true" ]
    then
        cat $TMPFILE1 |while read info
        do
            #echo info = $info
            [ -z "$info" ] && continue
            grep -q "$info" $TMPFILE && continue # This line still matches
            file=`expr "$info" : "file='\(.*\)' "`
            mode=`expr "$info" : ".*' mode=\([0-9]*\) "`
            user=`expr "$info" : ".* user=\([^(]*\)("`
            uid=`expr "$info" : ".* user=[^(]*(\([0-9]*\) "`
            group=`expr "$info" : ".* group=\([^(]*\)("`
            gid=`expr "$info" : ".* group=[^(]*(\([0-9]*\) "`
            type=`expr "$info" : ".* type=\(.\)"`
            major=`expr "$info" : ".* major=\([0-9]*\)"`
            minor=`expr "$info" : ".* minor=\([0-9]*\)"`
            #
            # This file is either missing or wrong
            # Delete the old and create it anew.
            #
            rm -f $dir/$file
            mknod --mode=$mode $dir/$file $type $major $minor
            chown $user:$group $dir/$file
            addignorefile $dir/$file
        done
    fi
}

function updatedirsymlinks()
{
    CHECKIN=false
    if [ "$1" = "-ci" ]
    then
        CHECKIN=true
        shift
    fi
    dir="$1"

    echo checking $dir for symlinks
    cp /dev/null $TMPFILE
    #
    # Obtain the list of symlinks in this directory
    #
    find "$dir" \( -type l -printf "file='%f' dest='%l'\n" \) -o -type d ! -name "`basename $dir`" -prune |
        sort >$TMPFILE
    
    #
    # Make sure all the symlinks are being ignored.
    #
    cat $TMPFILE |while read line
    do
        file=`expr "$line" : "file='\(.*\)' dest"`
        addignorefile "$dir/$file"
    done
    
    #
    # Obtain the currently defined symlinks
    #
    $SVN propget $SYM_PROP $dir >$TMPFILE1

    #
    # If the two list are the same then there is nothing to do.
    #
    if cmp $TMPFILE1 $TMPFILE >/dev/null
    then
        return
    fi

    if [ -s $TMPFILE ]
    then
        # There are symlinks in this directory
        if [ "$CHECKIN" = "true" ]
        then
            # Add the current symlinks to the property
            $SVN propset $SYM_PROP $dir -F $TMPFILE
        else
            # Delete all the unwanted symlinks
            cat $TMPFILE |while read line
            do
                file=`expr "$line" : "file='\(.*\)' dest"`
                efile="`echo $file |sed -e 's!\([\[\(\$]\)!\\\\\1!g'`"
                if ! grep -q "file='$efile'" $TMPFILE1
                then
                    rm $dir/$file
                    deleteignorefile $dir/$file
                fi
            done
        fi
    else
        # There are no symlinks in this directory
        if [ "$CHECKIN" = "true" ]
        then
            $SVN propdel $SYM_PROP $dir
        fi
    fi

    #
    # If we are not a checkin then make sure all the symlinks are defined
    #
    if [ "$CHECKIN" != "true" ]
    then
        cat $TMPFILE1 |while read info
        do
            [ -z "$info" ] && continue
            file=`expr "$info" : "file='\(.*\)' dest"`
            dest=`expr "$info" : ".*' dest='\(.*\)'$"`

            if [ -L $dir/$file ]
            then
                [ "`find $dir/$file -printf '%l'`" = "$dest" ] && continue
            fi
            rm -f $dir/$file
            ln -s $dest $dir/$file
        done
    fi
}

function recordpermissions()
{
    CHECKIN=false
    if [ "$1" = "-ci" ]
    then
        CHECKIN=true
        shift
    fi

    # Find all the directories and files
    cp /dev/null $TMPFILE
    eval "find $PCWD $SKIPSVN -o \( \( -type d ! -name .svn \) -o -type f \) $PRINTDETAILS" | while read info
    do
        device=`expr "$info" : "file='\(.*\)' mode"`
        info=`expr "$info" : "file='.*' \(mode.*\)"`
        if [ "$PCWD" = "$device" ]
        then
            dir="."
            file=""
        else
            dir="`basedirname $PCWD $device`"
            file="`basename $device`"
        fi
        # see if the properties have changed.
        if [ "`$SVN propget $FILE_PROP $dir/$file`" != "$info" ]
        then
            if [ "$CHECKIN" = "true" ]
            then
                $SVN propset $FILE_PROP "$info" $dir/$file
            else
                info=`$SVN propget $FILE_PROP "$dir/$file"`
                mode=`expr "$info" : "mode=\([0-9]*\) "`
                user=`expr "$info" : ".* user=\([^(]*\)("`
                uid=`expr "$info" : ".* user=[^(]*(\([0-9]*\) "`
                group=`expr "$info" : ".* group=\([^(]*\)("`
                gid=`expr "$info" : ".* group=[^(]*(\([0-9]*\) "`
                chown $user:$group $dir/$file
                chmod $mode $dir/$file
            fi
        fi
    done
}

function pre_checkin()
{
    echo this is the pre checkin process
    recorddirinfo -ci
    recordpermissions -ci
}

function post_checkout()
{
    echo this is the post checkout process
    if [ "$CHDIR" = "true" ]
    then
        shift $(($# -1))
        cd $1
    PCWD="$PCWD/$1"
    fi
    recorddirinfo
    recordpermissions
}

CHDIR=false
case "$1" in
checkout|co) CHDIR=true; ACTION="post";;
commit|ci) ACTION="pre";;
switch|sw) ACTION="post";;
update|up) ACTION="post";;
*);;
esac

[ "$ACTION" = "pre" ] && pre_checkin $@

$SVN $@

[ $? = 0 -a "$ACTION" = "post" ] && post_checkout $@

cleanup

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org
Received on Tue Aug 12 03:11:03 2003

This is an archived mail posted to the Subversion Users mailing list.