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