#!/bin/bash # SVN pre-commit hook for "svn-read-only" ############################################################## # # FEATURES: # # 1) Introduces the "svn-read-only" property for SVN. # # If the "svn-read-only" property is set on a FILE, then no # change to this file (except for a property change) can be # committed into the repository until after the property is # deleted. # # If the "svn-read-only" property is set on a DIRECTORY, # then no change to an item inside the directory or inside # the subdirectories can be committed. # # 2) Checks the SPELLING of the property being set # against the complete list of known properties. # # This is to prevent user from unintentional spelling # errors while setting properties. Trying to set the # properties "svn-rea-nly" for example, will trigger an # error message. This feature is optional and is controlled # by variable SPELLCHK in the script below. # # PLATFORMS CURRENTLY SUPPORTED: Tested on Linux and Cygwin # under Windows. Should work on a Macs as well, but not # tested. No support for native Windows so far. # # SETTING UP: Copy this file into the hooks directory # (located right inside your svn repository) and modify the # value of SVNLOOK below. If using a Linux platform, make # this file executable with chmod. # ############################################################## # # EXAMPLE OF USE: Assuming your "Project-1.0.0" directory # is located at /home/user/projects/tags/Project-1.0.0 on # your machine. Open the bash terminal and type: # # cd /home/user/projects/tags # # Ensure that your working copy does not have any local # modifications by typing "svn st". If it does have # modifications, they should either be committed or # reverted before proceeding. Now, set the property and # commit the property change by # # svn ps svn-read-only on Project-1.0.0 # svn ci -m "Making the project read only" Project-1.0.0 # # You can still make any local changes within the # "Project-1.0.0" directory at this point. They however can # not be committed. Your "Project-1.0.0" directory is now # safe from any unintentional commits. In order to undo # this behavior, type # # svn pd svn-read-only Project-1.0.0 # svn ci -m "Making the project modifiable again" Project-1.0.0 # ############################################################## # # AUTHOR: This program is designed and written by Alexander # Shirokov in Toronto Canada on a personal initiative. Its # first copy was made available on December 5, 2011 at # http://www.cita.utoronto.ca/~shirokov/soft/svn-hooks/svn-read-only # # LICENSE & DISCLAIMER: The program is available for anyone # who wishes to use it, without any restrictions. There is # no explicit or implied warranty for its use. # ############################################################## # Please make sure to set SVNLOOK to an existing path SVNLOOK=/usr/bin/svnlook # Set SPELLCHK to "yes" or "no". SPELLCHK=yes # Do not modify this, unless you want to change the name of the property. SVNREADONLY=svn-read-only # If you use any additional svn properties, please add them # to the list below. KNOWNPROPERTIES=( $SVNREADONLY svn:ignore \ svn:keywords \ svn:executable \ svn:eol-style \ svn:mime-type \ svn:externals \ svn:needs-lock ) REPOS="$1" TXN="$2" typeset -i blockcnt=0 typeset -i contentchangecnt=0 if [ ! -f "$SVNLOOK" ]; then echo "Error: file missing: $SVNLOOK" 1>&2 echo "To correct this error, please fix the SVNLOOK in your pre-commit hook." 1>&2 exit 3 fi while IFS= read -r line do status="${line:0:2}" filepath="${line:4}" # valid property change is always allowed if [ "$status" != "_U" ]; then contentchangecnt+=1 fi while IFS= read -r property do # Strip property of whitespaces to get property property=`echo "$property" | awk '{$1=$1;print}'` # Check for nocommit property if [ "$property" == "$SVNREADONLY" ] && [ "$status" != "_U" ]; then echo "Property \"$property\" is set on path being changed: \"$filepath\"" 1>&2 blockcnt+=1 fi # Alternatively, check spelling. if [ "$SPELLCHK" != "yes" ]; then typeset -i block=1 for svnproperty in ${KNOWNPROPERTIES[*]}; do if [ "$property" == "$svnproperty" ]; then block=0 break fi done if [ "$block" != "0" ]; then echo "Invalid property svn:* : \"$property\" on path $filepath" 1>&2 blockcnt+=$block fi unset block fi done < <("$SVNLOOK" proplist -t "$TXN" "$REPOS" "$filepath") done < <("$SVNLOOK" changed -t "$TXN" "$REPOS") if [ $blockcnt != 0 ]; then echo "Commit blocked by changed item check" 1>&2 exit 1 fi # If the content is changed on an item that does not bear the # SVNREADONLY, investigate upper directories for this property. if [ "$contentchangecnt" != "0" ]; then while IFS= read -r line do dirpath="$line" upperdir="$dirpath" while [ 1 ]; do while IFS= read -r property do # Strip the line of leading and trailing blankspaces property=`echo "$property" | awk '{$1=$1;print}'` if [ "$property" == "$SVNREADONLY" ]; then echo "Property \"$property\" is set on the superdirectory \"$upperdir\" of an item changed \"$dirpath\"" 1>&2 blockcnt+=1 fi done < <("$SVNLOOK" proplist -t "$TXN" "$REPOS" "${upperdir}") if [ "$upperdir" == "." ] || [ "$upperdir" == "/" ] || [ "$upperdir" == "" ] ; then break fi upperdir=`dirname $upperdir` done done < <($SVNLOOK dirs-changed -t "$TXN" "$REPOS" ) if [ $blockcnt != 0 ]; then echo "Commit blocked by superdirectory check" 1>&2 exit 2 fi fi # All checks passed, so allow the commit. exit 0