Subversionリポジトリのバックアップをとるシェルスクリプト

僕は作成物をSubversionで管理している。そのリポジトリは大事なので、ちゃんとバックアップをとりたい。リポジトリをバックアップするツールとして、svn-hot-backup というものがある。Subversionに同梱されている公式ツール(?)で、運悪く誰かがコミット中でもちゃんとバックアップできる。

Ubuntuの場合、subversion-tools というパッケージの中に入っている。最新のソースコードは以下から取れる。また、実行するにはpythonが必要だ。

hot-backup.py.in

ただし、僕の場合はいくつかリポジトリを持っているので、簡単なシェルスクリプトを作って一度に全部バックアップできるようにした。ソースコードは長いので一番下に書いておく。

僕の環境

OS
Ubuntu 8.04
Subversion
1.4.6 (r28521)
subversion-tools
1.4.6dfsg1-2ubuntu1
python
2.5.2

使い方

まず、ソースコード中の定数を変更する。

SVN_BACKUP_CMD
svn-hot-backupコマンドのフルパス
REPOSITORY_DIR
リポジトリが格納されているディレクトリ。このディレクトリ直下にバックアップをとりたいリポジトリを全て置く。
BACKUP_DIR
バックアップ先のディレクトリ。

その後、BACKUP_DIRを作成してから以下のコマンドを実行する(svnbakという名前でシェルスクリプトを作成した場合の例)。

# バックアップ対象となるリポジトリを全て出力する
% svnbak list
/var/local/mollifier/svnrepos/_vim
/var/local/mollifier/svnrepos/etc
/var/local/mollifier/svnrepos/mozilla

# リポジトリのバックアップをgzip圧縮形式でとる
# 通常はこれのみで良いだろう
% svnbak gz

# リポジトリのバックアップを圧縮しない形式でとる
% svnbak backup

何日か使いつづけた例

% ls /home/mollifier/.backup/svn/
_vim-52.tar.gz    etc-249.tar.gz  mozilla-134.tar.gz    mozilla-37.tar.gz
_vim-53.tar.gz    etc-250.tar.gz  mozilla-135-1.tar.gz  mozilla-38.tar.gz
_vim-55.tar.gz    etc-254.tar.gz  mozilla-135.tar.gz    mozilla-41.tar.gz
_vim-56.tar.gz    etc-263.tar.gz  mozilla-16.tar.gz     mozilla-43.tar.gz
_vim-58.tar.gz    etc-267.tar.gz  mozilla-19.tar.gz     mozilla-54.tar.gz
_vim-59.tar.gz    etc-271.tar.gz  mozilla-22.tar.gz     mozilla-7.tar.gz
_vim-60.tar.gz    etc-278.tar.gz  mozilla-23.tar.gz     mozilla-72.tar.gz
_vim-61-1.tar.gz  etc-279.tar.gz  mozilla-24.tar.gz     mozilla-99.tar.gz
_vim-61.tar.gz    etc-284.tar.gz  mozilla-26.tar.gz
etc-246.tar.gz    etc-286.tar.gz  mozilla-31.tar.gz
etc-247.tar.gz    etc-287.tar.gz  mozilla-33.tar.gz
etc-248.tar.gz    etc-289.tar.gz  mozilla-35.tar.gz

こんな風にリポジトリ名にリビジョン番号をつけてアーカイブが作られる。

注意点

  • 同じリビジョンのリポジトリを何度もバックアップすると、mozilla-135.tar.gz, mozilla-135-1.tar.gz, mozilla-135-2.tar.gz という風に通し番号付きでどんどんバックアップが作られます。
  • 一つのリポジトリごとに、バックアップの数が増えると古いものから削除されます(svn-hot-backup が削除する)。デフォルトでは64個を越えると古いものが削除されます。本当はmozilla-135-1.tar.gz, mozilla-135-2.tar.gz のような重複したバックアップを優先して削除してほしいわけですが、ソースコードを見る限りそうはなっていません。リビジョンの古いものが先に削除されます。
  • リポジトリ名が. (ドット)で始まる場合はバックアップされません。

ソースコード

#!/bin/bash

##########################################################
# subversionリポジトリのバックアップを行う
# hot-backupを使用する
##########################################################

#####################
#定数
#####################
declare -r SCRIPT_NAME=${0##*/}

#バックアップコマンド
declare -r SVN_BACKUP_CMD="/usr/bin/svn-hot-backup"

#リポジトリが格納されているディレクトリ
#このディレクトリの直下のディレクトリをリポジトリと扱う
#最後に'/'を付加すること
declare -r REPOSITORY_DIR="/var/local/${LOGNAME}/svnrepos/"

#バックアップ先のディレクトリ
declare -r BACKUP_DIR="${HOME}/.backup/svn/"


#####################
#関数
#####################

#ヘルプを出力する
print_usage()
{
    cat << EOF
Usage: $SCRIPT_NAME backup|gz|list|help
Backup all subversion repositories.

Backup command: $SVN_BACKUP_CMD
Repository directory: $REPOSITORY_DIR
Backup directory: $BACKUP_DIR

  backup             backup all repositories
  gz                 create gzip compressed tar archives of the backups
  list               list all repositories
  help, -h, --help   display this help and exit
EOF
}

#エラーを出力する
print_error()
{
    echo "$SCRIPT_NAME: $@" 1>&2
    echo "Try '$SCRIPT_NAME help' for more information." 1>&2
}


#####################
#メイン処理
#####################

#変数
#実行モード
#backup: リポジトリをバックアップする
#list: リポジトリをリスト出力する
execute_mode=''
#バックアップコマンドのオプション
backup_opt=''

#引数解析
case "$1" in
backup)
    execute_mode='backup'
    ;;
gz)
    execute_mode='backup'
    backup_opt='--archive-type=gz'
    ;;
list)
    execute_mode='list'
    ;;
help|-h|--help)
    print_usage
    exit 0
    ;;
*)  #エラー
    print_error "unknown argument -- $1"
    exit 1
    ;;
esac

#コマンド、ディレクトリのチェック
if [ ! -x "$SVN_BACKUP_CMD" ]; then
    print_error "can't execute backup command: $SVN_BACKUP_CMD"
    exit 1
fi

if [ ! -d "$REPOSITORY_DIR" ]; then
    print_error "not found repository directory: $REPOSITORY_DIR"
    exit 1
fi

if [ ! -d "$BACKUP_DIR" ]; then
    print_error "not found backup directory: $BACKUP_DIR"
    exit 1
fi

#バックアップ実行
for trydir in $REPOSITORY_DIR*; do
    #ディレクトリのみを対象とする
    if [ -d "$trydir" ]; then
        if [ "$execute_mode" == "backup" ]; then
            #バックアップモードの場合
            "$SVN_BACKUP_CMD" $backup_opt "$trydir" "$BACKUP_DIR"
        else
            #リスト出力モードの場合
            ls -d "$trydir"
        fi
    fi
done

exit $?