[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Shell script to make or restore backups of repositories

From: Martijn Ras <Martijn.Ras_at_GMail.com>
Date: Mon, 15 Jun 2009 15:07:30 +0200

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

This is an archived mail posted to the Subversion Users mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.