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