SvnImportSnapshots

Bash script to commit snapshots to SVN branch

Algorithm

  • For each snapshot
    • Update working copy
    • Delete all non-directory files, leaving .svn meta-data intact
    • Mark empty directories for SVN deletion
    • Mark missing files for SVN deletion
    • Mark new files for SVN addition
    • Check that the working directory matches the snapshot exactly
    • Commit changes
    • Tag changes

Input

  • LABELS: Path to text file containing ordered list of snapshots to process
  • REPO_URL: SVN URL to project root
  • WORKING_BRANCH: SVN branch to commit changes to
  • TAG_BRANCH: SVN branch to create tags on
  • ROOT: Local path to directory of snapshots
  • WORKING: Local path to SVN working directory

Initial Conditions

  • The WORKING directory contains a checkout of the WORKING_BRANCH (this would be trivial to add to the script)

Script

!/bin/sh

REPO_URL="http://path/to/project"
WORKING_BRANCH="trunk"
TAG_BRANCH="tags"

ROOT="/path/to/snapshots" # root of snapshot dir
WORKING="$ROOT/svn/working/copy" # working copy
LABELS="$ROOT/snapshot_list"

VERBOSE=1

die() {
echo ERROR: $1 ; exit 1
}

labels pre-check

cat "$LABELS" | while read LABEL
do
[ -d "$ROOT/$LABEL" ] || die "no label"
done

cat "$LABELS" | while read LABEL
do
cd "$ROOT" || break

[ -d "$ROOT/$LABEL" ] || die "no label"  
(($VERBOSE)) && echo $LABEL: found  

# update  
svn update $(cygpath -m "$WORKING") || die "svn update"  
(($VERBOSE)) && echo $LABEL: updated  

# clean working  
find "$WORKING" -name '.svn' -prune -o -type f -exec rm -f {} \;  
(($VERBOSE)) && echo $LABEL: cleaned  
# copy new snapshot  
cp -r "$ROOT/$LABEL"/* "$WORKING/"  || die "new snapshot"  
(($VERBOSE)) && echo $LABEL: new snapshot  

# Resolve  
#  Prune empty directories  
find "$WORKING" -name '.svn' -prune -o -type d -print | while read DIR  
do  
    DIRCOUNT=$(find "$DIR" -mindepth 1 -maxdepth 1 -name '.svn' -prune -o -print | wc -l)  
    if ! (($DIRCOUNT))  
    then  
        svn delete $(cygpath -m "$DIR")  
    fi  
done  
(($VERBOSE)) && echo $LABEL: pruned empty  
# Delete missing  
svn status $(cygpath -m "$WORKING") | grep '\!' | awk '{print "\"" $2 "\"" ;}' | xargs svn rm  
(($VERBOSE)) && echo $LABEL: deleted missing  
# Add non-versioned  
svn status $(cygpath -m "$WORKING") | grep '\?' | awk '{print "\"" $2 "\"" ;}' | xargs svn add  
(($VERBOSE)) && echo $LABEL: added new  

# Sanity check  
diff -x .svn -r "$ROOT/$LABEL" "$WORKING/"  || (echo "diff failed: exit to continue" ; /bin/sh)  

# commit  
svn commit $(cygpath -m "$WORKING") -m "\"Import VSS_$LABEL\"" || die "commit failed"  
(($VERBOSE)) && echo $LABEL: committed  

#COMMIT_REV=$(svn log $(cygpath -m "$WORKING") --revision "HEAD" | head -2 | tail -1 | awk '{print $1}' | cut -c 2-)  
# tag  
svn copy -m "Tag VSS_$LABEL" "$REPO_URL/$WORKING_BRANCH" "$REPO_URL/$TAG_BRANCH/VSS_$LABEL" || die "tag failed"  
(($VERBOSE)) && echo $LABEL: tagged  

done

$[Get Code]1