Heya Folks,
I've been using the following script for backing up Subversion repositories at
home and in a number of different organizations for quite some time now and
want to share it in the hope it might be useful for some of you.
It will pick up all Subversion repositories under the directory one specifies
and write the svnadmin dump output to a mktemp generated directory by default,
or the directory one specifies. Backups will be created as either full or
incremental backups based on the subcommand one specifies. The subcommand
restore takes a backup and restores it under the directory one specifies.
It also be configured to run as a cron job.
In case the repositories or backups need their ownership set to a specific user
or group simply specify these in the appropriate variable.
Mazzel,
Martijn.
#!/bin/sh
#
# ------------------------------------------------------------------------
#
# Copyright (C) 2007 Martijn Ras
#
# ------------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ------------------------------------------------------------------------
#
#
#
# Set the following variables if you do not want to specify them on
the command line.
#
#
# All repositories under this directory will be backed up.
#
#ROOTDIRECTORY=''
#
# All backups will be written into this directory (defaults to a
mktemp generated directory).
#
#BACKUPDIRECTORY=''
#
# The default subcommand to be performed (defaults to 'help', except
when run from a cron directory where it defaults to 'full').
#
#SUBCOMMAND=''
#
# The name of the user and group to be set as the owner of the backups.
# This might be necessary to have the items packed up by an archiving tool.
#
#BACKUPDIRECTORYUSER=''
#BACKUPDIRECTORYGROUP="${BACKUPDIRECTORYUSER}"
#
# The name of the user and group to be set as the owner of the repositories.
# When run as root in a cron job it might be necessary to reset the ownership.
#
#SUBVERSIONDIRECTORYUSER=''
#SUBVERSIONDIRECTORYGROUP="${SUBVERSIONDIRECTORYUSER}"
#
# check_commands ()
#
# Checks the existence of the specified commands.
#
# Parameters:
# @) A space separated list of all commands of which to check the existence.
#
function check_commands () {
for COMMAND in "$@"
do
execute_command "which '${COMMAND}'" "Cannot find: ${COMMAND}!"
done
}
#
# error ()
#
# Print the specified error message and exit the program.
#
# Parameters:
# 1) The error message to print before exiting the program.
#
function error () {
echo -e "\nERROR:\n\n$1\n" 2> /dev/null
exit 1
}
#
# execute_command ()
#
# Execute a command and print an error message if needs be.
#
# Parameters:
# 1) The command to execute.
# 2) The error message to print if needs be.
#
function execute_command () {
sh -c "$1" > /dev/null 2>&1
if test $? -ne 0
then
error "$2"
fi
}
#
# make_directories ()
#
# Make the directories specified.
#
# Parameters:
# 1) An array with the directories to make.
#
function make_directories () {
for DIRECTORY in "$@"
do
if ! test -d "${DIRECTORY}"
then
execute_command "mkdir --parents '${DIRECTORY}'" "Failed to make
directory: ${DIRECTORY}!"
fi
done
}
#
# processsubcommand ()
#
# Works out which subcommand was specified on the command line or sets
the default.
#
# Parameters:
# 1) The subcommand specified on the command line.
#
function processsubcommand () {
if test "$1" = 'full' -o "$1" = 'f'
then
SUBCOMMAND='full'
elif test "$1" = 'help' -o "$1" = 'h' -o "$1" = '?'
then
SUBCOMMAND='help'
elif test "$1" = 'incremental' -o "$1" = 'i' -o "$1" = 'incr'
then
SUBCOMMAND='incremental'
elif test "$1" = 'list' -o "$1" = 'l' -o "$1" = 'ls'
then
SUBCOMMAND='list'
elif test "$1" = 'restore' -o "$1" = 'r' -o "$1" = 'rest'
then
SUBCOMMAND='restore'
else
if test "${0:0:9}" == '/etc/cron'
then
SUBCOMMAND='full'
elif test -z "${SUBCOMMAND}"
then
SUBCOMMAND='help'
fi
fi
}
#
# processsubcommandparameters ()
#
# Works out which parameters have been specified for the subcommand.
#
# Parameters:
# *) Depended on the subcommand specified.
#
function processsubcommandparameters () {
if test "${SUBCOMMAND}" = 'full' -o "${SUBCOMMAND}" = 'incremental'
then
if test -n "$2"
then
ROOTDIRECTORY="$1"
BACKUPDIRECTORY="$2"
elif test -n "$1"
then
ROOTDIRECTORY="$1"
fi
if test -z "${BACKUPDIRECTORY}"
then
BACKUPDIRECTORY="$(mktemp -d)"
if test $? -ne 0
then
error "Failed to create temporary directory for backup!"
fi
fi
make_directories "${BACKUPDIRECTORY}"
elif test "${SUBCOMMAND}" = 'help'
then
SUBCOMMAND="$1"
usage
elif test "${SUBCOMMAND}" = 'list'
then
ROOTDIRECTORY="$1"
elif test "${SUBCOMMAND}" = 'restore'
then
if test -n "$2"
then
ROOTDIRECTORY="$1"
BACKUPFILE="$2"
elif test -n "$1"
then
BACKUPFILE="$1"
fi
fi
}
#
# processparameters ()
#
# Processes all parameters specified on the command line.
#
# Parameters:
# @) The parameters specified on the command line.
#
function processparameters () {
processsubcommand "$@"
shift
processsubcommandparameters "$@"
}
#
# remove_tempfile ()
#
# Remove a temporary file used by the program.
#
# Parameters:
# None
#
function remove_tempfile () {
if test -n "${TEMPFILE}" -a -f "${TEMPFILE}"
then
execute_command "rm '${TEMPFILE}'" "\nERROR:\n\nFailed to remove
temporary file: ${TEMPFILE}!"
fi
}
#
# tempfile ()
#
# Create a new temporary file for use by the program.
#
# Parameters:
# None
#
function tempfile () {
TEMPFILE="$(mktemp -q -t 2> /dev/null)"
if test $? -ne 0
then
error "Failed to create temporary file!"
fi
}
#
# usage ()
#
# Prints the usage information.
#
function usage () {
echo 'usage:'
echo ''
if test "${SUBCOMMAND}" = 'full' -o "${SUBCOMMAND}" = 'f'
then
echo ' SubversionBackup f <subversionroot> <backupdirectory>'
echo ' SubversionBackup full <subversionroot> <backupdirectory>'
echo ''
echo 'SubversionBackup will create full backups of all repositories
under subversionroot in the backupdirectory.'
elif test "${SUBCOMMAND}" = 'incremental' -o "${SUBCOMMAND}" = 'i' -o
"${SUBCOMMAND}" = 'incr'
then
echo ' SubversionBackup i <subversionroot> <backupdirectory>'
echo ' SubversionBackup incr <subversionroot> <backupdirectory>'
echo ' SubversionBackup incremental <subversionroot> <backupdirectory>'
echo ''
echo 'SubversionBackup will create incremental backups of all
repositories under the subversionroot in the backupdirectory.'
elif test "${SUBCOMMAND}" = 'list' -o "${SUBCOMMAND}" = 'l' -o
"${SUBCOMMAND}" = 'ls'
then
echo ' SubversionBackup l <subversionroot>'
echo ' SubversionBackup ls <subversionroot>'
echo ' SubversionBackup list <subversionroot>'
echo ''
echo 'SubversionBackup will list all repositories under the subversionroot.'
elif test "${SUBCOMMAND}" = 'restore' -o "${SUBCOMMAND}" = 'r' -o
"${SUBCOMMAND}" = 'rest'
then
echo ' SubversionBackup r <subversionroot> <backup>'
echo ' SubversionBackup rest <subversionroot> <backup>'
echo ' SubversionBackup restore <subversionroot> <backup>'
echo ''
echo 'Restores a backup, created by svnadmin dump, of a subversion
repository under the subversionroot.'
else
echo ' SubversionBackup [subcommand] <subversionroot>
[<backupdirectory>|<backup>]'
echo ''
echo 'Type "SubversionBackup help <subcommand>" for help on a
specific subcommand.'
echo ''
echo 'SubversionBackup will either create backups of all
repositories under the subversionroot in the backupdirectory or
restore a backup in the subversionroot.'
echo ''
echo 'Available subcommands:'
echo ' full (f)'
echo ' help (h, ?)'
echo ' incremental (i, incr)'
echo ' list (l, ls)'
echo ' restore (r, rest)'
fi
echo ''
exit
}
check_commands 'basename' 'bzip2' 'chown' 'date' 'dirname' 'find'
'head' 'ls' 'mkdir' 'mktemp' 'sed' 'sort' 'svnadmin' 'svnlook' 'wc'
'which'
processparameters "$@"
START=$(date +%s)
if test $? -ne 0
then
START=''
fi
execute_command "umask 077" "Failed to set umask!"
if test "${ROOTDIRECTORY: -1}" != '/'
then
ROOTDIRECTORY="${ROOTDIRECTORY}/"
fi
if test "${SUBCOMMAND}" = 'restore'
then
REPOSITORY="${ROOTDIRECTORY}$(basename "${BACKUPFILE}" | sed
's#^\(.*\)\.backup\.[0-9]*-[0-9]*#\1#')"
if test $? -ne 0
then
error "Failed to determine repository to restore!"
fi
echo "Restoring repository: ${BACKUPFILE} under ${REPOSITORY}"
make_directories "$(dirname "${REPOSITORY}")"
execute_command "svnadmin create '${REPOSITORY}'" "Failed to create
repository ${REPOSITORY}!"
execute_command "bzip2 -dc '${BACKUPFILE}' | svnadmin load
'${REPOSITORY}'" "Failed to load backup (${BACKUPFILE}) into
repository ${REPOSITORY}!"
else
if test -d "${ROOTDIRECTORY}"
then
cd "${ROOTDIRECTORY}"
else
echo 'Invalid default or specified subversionroot:'
echo ''
echo " ${ROOTDIRECTORY}"
echo ''
exit 1
fi
if test "${SUBCOMMAND}" = 'list'
then
echo 'SubversionBackup will create backups of the following repositories:'
echo ''
fi
for REPOSITORY in $(find . -maxdepth 1 -mindepth 1 -type d | sed 's#\./##')
do
if test -d "${REPOSITORY}" -a -f "${REPOSITORY}/format"
then
if test "${SUBCOMMAND}" = 'list'
then
echo " ${ROOTDIRECTORY}${REPOSITORY}"
else
echo "Starting ${SUBCOMMAND} backup of repository:"
echo -n " ${ROOTDIRECTORY}${REPOSITORY}"
LAST='0'
if test "${SUBCOMMAND}" = 'incremental'
then
LAST="$(ls ${BACKUPDIRECTORY}/${REPOSITORY}.backup.* 2>/dev/null
| sort --reverse | head --lines=1 | sed
's#.*\.backup\.[0-9]*-\([0-9]*\).*#\1#')"
if test "${LAST}" = ''
then
LAST='0'
fi
fi
HEAD="$(svnlook youngest "${REPOSITORY}")"
if test $? -ne 0
then
error "Failed to determine youngest revision of repository ${REPOSITORY}!"
fi
if test ${LAST} -lt ${HEAD}
then
COMMAND="svnadmin dump --quiet"
if test "${SUBCOMMAND}" = 'incremental'
then
COMMAND="${COMMAND} --${SUBCOMMAND}"
fi
COMMAND="${COMMAND} --revision ${LAST}:${HEAD} ${REPOSITORY}"
${COMMAND} | bzip2 >
"${BACKUPDIRECTORY}/${REPOSITORY}.backup.${LAST}-${HEAD}"
if test $? -eq 0
then
echo ' - SUCCEEDED'
else
echo " - FAILED: range (${LAST}:${HEAD})"
fi
elif test ${LAST} -gt ${HEAD}
then
echo " - ERROR: Invalid range (${LAST}:${HEAD})"
else
echo " - WARNING: Skipping ${SUBCOMMAND} backup of repository
${REPOSITORY} (${LAST}:${HEAD})"
fi
fi
else
if test "${SUBCOMMAND}" != 'list'
then
echo "Not a subversion repository: ${ROOTDIRECTORY}${REPOSITORY}" 1>&2
fi
fi
done
fi
if test "${SUBCOMMAND}" != 'list'
then
if test -n "${SUBVERSIONDIRECTORYUSER}"
then
echo "Setting ownership of repositories to
${SUBVERSIONDIRECTORYUSER}:${SUBVERSIONDIRECTORYGROUP}"
execute_command "chown --recursive
${SUBVERSIONDIRECTORYUSER}:${SUBVERSIONDIRECTORYGROUP}
'${ROOTDIRECTORY}'" "Failed to set ownership of repositories to
${SUBVERSIONDIRECTORYUSER}:${SUBVERSIONDIRECTORYGROUP}"
fi
if test -n "${BACKUPDIRECTORYUSER}" -a "${SUBCOMMAND}" != 'restore'
then
echo ''
echo "Setting ownership of backups of repositories to
${BACKUPDIRECTORYUSER}:${BACKUPDIRECTORYGROUP}"
execute_command "chown --recursive
${BACKUPDIRECTORYUSER}:${BACKUPDIRECTORYGROUP} '${BACKUPDIRECTORY}'"
"Failed to set ownership of backups of repositories to
${BACKUPDIRECTORYUSER}:${BACKUPDIRECTORYGROUP}"
fi
if test "${START}" != ''
then
echo ''
echo "SubversionBackup completed in $(($(date +%s) - ${START})) seconds"
fi
fi
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=1065&dsMessageId=2362164
To unsubscribe from this discussion, e-mail: [users-unsubscribe_at_subversion.tigris.org].
Received on 2009-06-15 15:17:43 CEST