Minecraft mine analysis – mian

The mian wiki is now up! Updates will be put there for your convenience.

Pepijn de Vos has made a tool to graph materials in Minecraft save games across heights, to see how deep one should mine to find for example diamond. As a propaganda minister Minecraft player with too much time on his hands, this was too cool. I just tweaked it a bit, we both contributed speed improvements, and now it looks like this:

Graph of block count for several materials across the height of the world

On Ubuntu, you can install it with the following command:
sudo apt-get install python-matplotlib && sudo easy_install mian
… and run it like this:
mian ~/.minecraft/saves/World1

Options include:
-b, --blocks – Specify block types to include as a comma-separated list, using either the block types or hex values from the list.
-l, --list – List available block types.
-n, --nether – Show Nether data instead of the normal world.

For example, run mian -b 01,dirt,09,sand ~/.minecraft/saves/World1 to get a map of the more common elements in the map, with the abrupt cutoff of stationary water showing the sea height:

Common materials in Minecraft

More information is available in the form of a Git repository (of course it’s open source) and Ohloh project.

Update: Now works with The Nether, included in today’s Halloween Update. To graph The Nether, make sure you visit it first, update mian with sudo easy_install -U mian, then add the parameter -n to your command. For example mian -b 56,57,58,59,5a,5b -n ~/.minecraft/saves/World1 to show all the new materials:

Graph of the new materials in an existing world

Beta update: mian 0.6 works fine with Minecraft Beta. If you have an older version, simply run sudo easy_install -U mian

Guest uploader setup script

Just slammed together a script to add users and give them access to the “upload” user directory.

Edit: Sorry for the updates, it turned out the first version was not optimal.

#!/bin/sh

# Usage: uploader [username ...]

error()
{
	test -t 1 && {
		tput setf 4
		echo "$1" >&2
		tput setf 7
	} || echo "$1" >&2
	exit 1
}

users="upload $*"

for user in $users
do
	# Create user if necessary
	id $user 1>/dev/null 2>&1
	if [ "$?" -ne "0" ]
	then
		useradd --groups upload --comment "Upload user" $user && \
		echo "Created upload user '${user}'." || \
		error "Could not create upload user '${user}'."
	fi
done

# Disable upload password
usermod --lock upload

# Files
chown -R upload:upload ~upload || \
error "Could not change owner of upload home dir"
chmod -R ug+rwX,o= ~upload || \
error "Could not change rights of upload home dir"

Sort blocks of text in files

Ever had to sort a file alphabetically, only to realize that you’d have to do it manually because every item that needs to be sorted is spread over more than one line? This just happened when I exported my Gmail contacts to vCard, which it turned out were sorted by formatted name (FN) instead of name (N). The result was the following script, which takes two pattern and some input, and returns the sorted output. The example returned by ./sort_blocks.py --help is exactly the code to re-sort Gmail contacts. I’d love to know if you find any bugs or possible improvements to this script. Enjoy:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
## Copyright (C) 2009 CERN.
##
## Sort any multi-line block text
##
## This file 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.
##
## CDS Invenio 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 CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

"""sort_blocks.py - Multiline sort of standard input

Default syntax:

./sort_blocks.py -b 'pattern' -s 'pattern' < input_file > result_file

Options:
-v,--verbose    Verbose mode
-h,--help       Print this message
-b,--bp         Block pattern (dotall multiline); used to extract blocks
-s,--sp         Sort pattern (dotall multiline); extracted to sort blocks

Example:

./sort_blocks.py -b 'BEGIN:VCARD.*?END:VCARD\\r\\n' -s '^N:(.*)$' \
< contacts.vcf > contacts2.vcf

Orders vCards in contacts.vcf by name, and puts the results in contacts2.vcf."""

import getopt
import re
import sys

class Usage(Exception):
    """Raise in case of invalid parameters"""
    def __init__(self, msg):
        self.msg = msg

def _compare_pattern(sort_pattern, text1, text2):
    """Function to sort by regex"""
    matches = [
        re.search(sort_pattern, text, re.DOTALL | re.MULTILINE)
        for text in [text1, text2]]
    text_matches = []
    for match in matches:
        if match is None:
            text_matches.append('')
        else:
            text_matches.append(match.group(1))

    return cmp(text_matches[0], text_matches[1])

def split_and_sort(text, block_pattern, sort_pattern):
    """Split into blocks, sort them, and join them up again
    @param text: String of blocks to sort
    @param block_pattern: Regular expression corresponding to the border between
    the blocks
    @param sort_pattern: Gets a subset of each block to sort by"""

    text_blocks = re.findall(block_pattern, text, re.DOTALL | re.MULTILINE)
    #print text_blocks

    text_blocks.sort(lambda x, y: _compare_pattern(sort_pattern, x, y))

    return ''.join(text_blocks)

def main(argv = None):
    """Argument handling"""

    if argv is None:
        argv = sys.argv

    # Defaults
    block_pattern = ''
    sort_pattern = ''

    try:
        try:
            opts, args = getopt.getopt(
                argv[1:],
                'hb:s:',
                ['help', 'bp=', 'sp='])
        except getopt.GetoptError, err:
            raise Usage(err.msg)

        for option, value in opts:
            if option in ('-h', '--help'):
                print(__doc__)
                return 0
            elif option in ('-b', '--bp'):
                block_pattern = value
            elif option in ('-s', '--sp'):
                sort_pattern = value
            else:
                raise Usage('Unhandled option ' % option)

        if block_pattern == '' or sort_pattern == '' or args:
            raise Usage(__doc__)

        text = sys.stdin.read()

        print split_and_sort(text, block_pattern, sort_pattern)

    except Usage, err:
        sys.stderr.write(err.msg + '\n')
        return 2

if __name__ == '__main__':
    sys.exit(main())

WordPress update script

This is a script to update a WordPress blog with the latest stable version from Subversion.

How to use:

  1. Download update-wordpress.sh.
  2. chmod u+x path/to/update-wordpress.sh
  3. path/to/update-wordpress.sh -fs ftp_server -wp /path/to/WordPress/on/FTP -ms mysql_server

Some features:

  • Works with plain /bin/sh, so it should work on any Linux / BSD distribution.
  • Flexible – There are input parameters for user names, passwords, and lots more.
  • It will ask for FTP and MySQL passwords (-FP and -MP parameters) only if these are not provided

update-wordpress.sh

#!/bin/sh
#
# $Id: update-wordpress.sh 393 2008-06-19 10:29:18Z vengmark $
#
# NAME
#    update-wordpress.sh - Update WordPress to latest stable version.
#
# SYNOPSIS
#    update-wordpress.sh [options]
#
# DESCRIPTION
#    Backs up the database and the most relevant files (.htaccess, robots.txt
#    and wp-config.php) before updating.
#
#    Uses instructions from
#    http://codex.wordpress.org/Installing/Updating_WordPress_with_Subversion to
#    get the latest stable version of WordPress and copy it to an FTP server.
#
#    For security reasons, the script will ask for all necessary passwords if
#    you don't provide them on the command line.
#
# OPTIONS
#    -v     Verbose output
#    -q     Quiet (non-interactive)
#    -fs    FTP server host name (mandatory)
#    -wp    WordPress path on FTP server (mandatory)
#    -fp    FTP server port
#    -fu    FTP user
#    -FP    FTP password
#    -ms    MySQL server host name (mandatory)
#    -mp    MySQL server port
#    -mu    MySQL user
#    -MP    MySQL password
#    -wd    WordPress database name
#    -wv    WordPress version
#    -b     Where to put the WordPress backup files
#
# BUGS
#    Should detect the newest security release (i.e., highest X for versions
#    2.5.X), perhaps from http://svn.automattic.com/wordpress/tags/.
#
#    Email bugs to victor dot engmark at gmail dot com. Please include the
#    output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
#    Copyright (C) 2008 Victor Engmark
#
#    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 3 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, see <http://www.gnu.org/licenses/>.
#
################################################################################

# Init
PATH="/usr/bin:/bin"

# Hard-code values here if you don't want to provide parameters
backup_dir="${HOME}/.backup/WordPress"

# FTP
ftp_host=
ftp_port=21
ftp_user=`whoami`

# MySQL
mysql_host=
mysql_port=3306
mysql_user=`whoami`

# WordPress
wordpress_repository=http://svn.automattic.com/wordpress/tags/
wordpress_version="2.5.1"
wordpress_path=
wordpress_database=wordpress

cmdname=`basename $0`

#Error messages
errm_unknown="Unknown error in $cmdname" #Code 1
#Code 2 is reserved: http://www.faqs.org/docs/abs/HTML/exitcodes.html
usage="Usage: ${cmdname} [-v] [-q] -fs ftp_server -wp wordpress_path [-fp ftp_port] [-fu ftp_user] [-FP ftp_password] -ms mysql_server [-mp mysql_port] [-mu mysql_user] [-MP mysql_password] [-wd wordpress_database] [-wv wordpress_version] [-b backup_dir]" #Code 3

# Process parameters
until [ $# -eq 0 ]
do
  case $1 in
    -v)
      verbose=1
      shift
      ;;
    -q)
      quiet=1
      shift
      ;;
    -fs)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      ftp_host=$2
      shift 2
      ;;
    -fp)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      ftp_port=$2
      shift 2
      ;;
    -fu)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      ftp_user=$2
      shift 2
      ;;
    -FP)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      ftp_password=$2
      shift 2
      ;;
    -ms)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      mysql_host=$2
      shift 2
      ;;
    -mp)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      mysql_port=$2
      shift 2
      ;;
    -mu)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      mysql_user=$2
      shift 2
      ;;
    -MP)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      mysql_password=$2
      shift 2
      ;;
    -wp)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      wordpress_path="${2%\/}"
      shift 2
      ;;
    -wd)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      wordpress_database=$2
      shift 2
      ;;
    -wv)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      wordpress_version=$2
      shift 2
      ;;
    -b)
      if [ -z "$2" ]
      then
        echo "$usage" >&2
        exit 3
      fi
      backup_dir="${2%\/}"
      shift 2
      ;;
    *)
      #Unknown parameter
      if [ $verbose ]
      then
        echo "Unknown parameter: $1" >&2
      fi
      echo "$usage" >&2
      exit 3
      ;;
  esac
done

# Check input values
if [ ! $ftp_host ] || [ ! $mysql_host ] || [ ! $wordpress_path ]
then
  echo "$usage" >&2
  exit 3
fi

if [ -z "$mysql_password" ] && [ $quiet ]
then
  echo "Please provide the database password with the \"-MP\" parameter" >&2
  echo "$usage" >&2
  exit 3
fi

if [ -z "$ftp_password" ] && [ $quiet ]
then
  echo "Please provide the FTP password with the \"-FP\" parameter" >&2
  echo "$usage" >&2
  exit 3
fi

# Check for necessary programs
for application in bzip2 mysqldump ncftp svn
do
  if [ ! `which $application` ]
  then
    echo "Please install application '$application' first." >&2
    error_found=1
  fi
done
if [ $error_found ]
then
  exit 1
fi

# Build necessary variables from input
wordpress_repository="${wordpress_repository}${wordpress_version}"

# Summarize settings
if [ $verbose ]
then
  echo "Running $cmdname at `date`."
  echo
  echo "Backup directory: ${backup_dir}"
  echo
  echo "FTP connection: ${ftp_user}@${ftp_host}:${ftp_port}"
  echo "WordPress FTP path: ${wordpress_path}"
  echo
  echo "MySQL connection: ${mysql_user}@${mysql_host}:${mysql_port}"
  echo "WordPress database: ${wordpress_database}"
  echo
  echo "New WordPress version: ${wordpress_version}"
  echo "WordPress repository: ${wordpress_repository}"
  echo
fi

clean_up()
{
  if [ $verbose ]
  then
    echo "Cleaning up."
  fi
  rm -Rf $temp_dir
}

debug()
{
  if [ -z "$1" ]
  then
    echo "debug function syntax: debug \$command_name \$error_code"
    clean_up
    exit 1
  fi
  if [ $2 -ne 0 ]
  then
    echo "$1 failed with error code $2."
    exit 1
  elif [ $verbose ]
  then
    echo "$1 succeeded."
  fi
}

if [ $verbose ]
then
  echo "Creating the temporary folder."
fi

temp_dir=`mktemp -t -d ${cmdname}.XXXXXXXXXX` || debug "mktemp" $?

if [ ! -e $backup_dir ]
then
  if [ $verbose ]
  then
    echo "Creating the backup folder."
  fi
  mkdir -p $backup_dir
  debug "mkdir" $?
fi

# Back up database
if [ -z "$mysql_password" ]
then
  echo -n "Enter MySQL password: "
  stty -echo
  read mysql_password
  stty echo
  echo
fi

# Enable showing the string to the user before executing
dummy_password=PASSWORD
mysqldump_command="mysqldump --host=$mysql_host --opt --password="$dummy_password" --port=$mysql_port --user=$mysql_user $(if [ $verbose ]; then echo '-v'; fi;) --result-file=${backup_dir}/WordPress.sql $wordpress_database"
if [ $verbose ]
then
  echo "MySQLdump command:\n$mysqldump_command"
fi
mysqldump_command=$(echo $mysqldump_command | sed "s/${dummy_password}/${mysql_password}/") # Insert password in command

# Run backup
$mysqldump_command
debug "mysqldump" $?

# Download latest stable WordPress release
svn_dir=${temp_dir}/svn
svn_command="svn export $(if [ ! $verbose ]; then echo '--quiet'; fi;) $wordpress_repository $svn_dir"
if [ $verbose ]
then
  echo "Subversion command:\n$svn_command"
fi

$svn_command
debug "svn" $?

# Back up user files
if [ -z "$ftp_password" ]
then
  echo -n "Enter FTP password: "
  stty -echo
  read ftp_password
  stty echo
  echo
fi

ncftp <<EOD
open -u "$ftp_user" -p "$ftp_password" -P $ftp_port "$ftp_host"
lcd $backup_dir
cd $wordpress_path
get .htaccess
get robots.txt
get wp-config.php
lmkdir wp-content
lcd wp-content
lmkdir uploads
lcd uploads
cd wp-content/uploads
get -R *
quit
EOD
debug "ncftp" $?

# Make sure the site is ready to update
if [ ! $quiet ]
then
  echo -n "Please deactivate all your WordPress plugins, then press Enter to continue."
  read dummy
fi

# Update WordPress installation
ncftp <<EOD
open -u "$ftp_user" -p "$ftp_password" -P $ftp_port "$ftp_host"
lcd $svn_dir
cd $wordpress_path
put -R *
quit
EOD
debug "ncftp" $?

echo "Backup and update finished. To complete the installation, please go to the upgrade page (e.g., http://example.com/wordpress/wp-admin/upgrade.php)"
clean_up

# End
if [ $verbose ]
then
	echo "${cmdname} completed at `date`."
fi

exit 0

Subversion checkout script

Here’s a simple script to check out all subversion repositories on a remote host. It requires that you have SSH access on the host, to be able to fetch the repository names (otherwise you can hardcode them in $repositories). You’ll also need to have Perl installed.

How to use:

  1. Download checkout-all-svn.sh.
  2. chmod u+x path/to/checkout-all-svn.sh
  3. path/to/checkout-all-svn.sh -r http://example.org/svn/

Some features:

  • Works with plain /bin/sh, so it should work on any Linux / BSD distribution.
  • Works with repository names with spaces, but not yet with unusual characters.

checkout-all-svn.sh

#!/bin/sh
#
# $Id: checkout-all-svn.sh 387 2008-06-07 20:36:08Z vengmark $
#
# NAME
#    checkout-all-svn.sh - Check out all Subversion repositories.
#
# SYNOPSIS
#    checkout-all-svn.sh [options]
#
# OPTIONS
#    -v     Verbose output
#    -p     Target host SSH port
#    -u     Target host SSH user name
#    -d     Subversion repository directory on target host
#    -r     URL part before the repository name,
#           e.g. https://example.org/svn/
#
# EXAMPLE
#    ./checkout-all-svn.sh -v -p 1234 -u ssh-admin -d /var/lib/svn -r
#    https://example.com/reps/
#
# DESCRIPTION
#    Gets all your subversion repositories. If they are already
#    present, they will be updated.
#
#    The current (or specified with -u) user must have SSH access to the remote
#    host. To circumvent this you can specify the repository names in
#    $repositories, separated by newlines.
#
#    To avoid having to type your password several times, you can setup SSH
#    keys - See e.g. https://help.ubuntu.com/community/SSHHowto
#
# BUGS
#    Email bugs to victor dot engmark at gmail dot com. Please include the
#    output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
#    Copyright (C) 2008 Victor Engmark
#
#    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 3 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, see <http://www.gnu.org/licenses/>.
#
################################################################################

# Init
ifs_original="$IFS" # Reset when done

PATH="/usr/bin:/bin"
cmdname=`basename $0`
directory=`dirname $0`
target_dir=~

# Remote host
target_port=22
target_user=`whoami`

# Subversion
svn_root="/var/lib/svn"

#Error messages
errm_unknown="Unknown error in $cmdname" #Code 1
#Code 2 is reserved: http://www.faqs.org/docs/abs/HTML/exitcodes.html
usage="Usage: ${cmdname} [-v] [-p port] [-u user] [-d svn_directory] -r repositories_url" #Code 3

# Process parameters
until [ $# -eq 0 ]
do
	case $1 in
		-v)
			verbose=1
			shift
			;;
		-p)
			if [ -z "$2" ]
			then
				echo "$usage" >&2
				exit 3
			fi
			target_port=$2
			shift 2
			;;
		-u)
			if [ -z "$2" ]
			then
				echo "$usage" >&2
				exit 3
			fi
			target_user=$2
			shift 2
			;;
		-d)
			if [ -z "$2" ]
			then
				echo "$usage" >&2
				exit 3
			fi
			svn_root=$2
			shift 2
			;;
		-r)
			if [ -z "$2" ]
			then
				echo "$usage" >&2
				exit 3
			fi
			base_url=$2
			shift 2
			;;
		*)
			#Unknown parameter
			if [ $verbose ]
			then
				echo "Unknown parameter: $1" >&2
			fi
			echo "$usage" >&2
			exit 3
			;;
	esac
done

if [ ! $base_url ]
then
	echo "$usage" >&2
	exit 3
fi
base_url=`echo $base_url | sed "s/ /%20/g"` # To avoid problems with spaces

target_host=$base_url
target_host=${target_host#*//}
target_host=${target_host%%/*}
if [ $verbose ]
then
	echo "Target host: ${target_host}"
fi

repositories=`ssh -p ${target_port} ${target_user}@${target_host} $(if [ $verbose ]; then echo '-v'; else echo '-q'; fi;) -x "ls '${svn_root}'"`
error=$?
if [ $error -ne 0 ]
then
	echo "Failed to get repository names. Error code $error" >&2
	exit 1
fi
if [ $verbose ]
then
	echo "Repositories:\n${repositories}"
fi

IFS="
" # Make sure paths with spaces don't make any trouble when looping

# Concatenate URLs
rep_urls=""
for repository in $repositories
do
	repository=`echo $repository | sed "s/ /%20/g"`
	rep_urls="${rep_urls} ${base_url}${repository}"
done

IFS="$ifs_original"

svn co $rep_urls --non-interactive -r 'HEAD' `if [ ! $verbose ]; then echo '--quiet'; fi;` "${target_dir}"

# End
exit 0

Subversion backup script

Following up on the good work of Jean-Francois Roy, here’s my slightly extended version of his script to backup all Subversion repositories to a remote host.

How to use:

  1. Download backup-all-svn.sh
  2. chmod u+x path/to/backup-all-svn.sh
  3. ./backup-all-svn.sh -h target_host (can also set target port and user name)

Some features:

  • Works with plain /bin/sh, so it should work on any Linux / BSD distribution.
  • Works with repository names with spaces and non-ASCII characters.

backup-all-svn.sh

#!/bin/sh
#
# $Id: backup-all-svn.sh 387 2008-06-07 20:36:08Z vengmark $
#
# NAME
#    backup-all-svn.sh - Backup all Subversion repositories
#
# SYNOPSIS
#    backup-all-svn.sh [options]
#
# OPTIONS
#    -v     Verbose output
#    -h     Target host name (mandatory)
#    -p     Target host port
#    -u     Target host user name
#
# EXAMPLE
#    ./backup-all-svn.sh -v -h example.com -p 1234 -u johndoe
#
# DESCRIPTION
#    Backups all your subversion repositories to a remote machine.
#
#    The current user must have access to the subversion repositories.
#    To work around this, you should `sudo adduser <username> <svn-group>`
#    and `sudo chmod -R g+w /path/to/repos`.
#
#    To avoid having to type your password several times, you can setup SSH
#    keys - See e.g. https://help.ubuntu.com/community/SSHHowto
#
# BUGS
#    Email bugs to victor dot engmark at gmail dot com. Please include the
#    output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
#    Copyright (C) 2005 Jean-Francois Roy
#    Copyright (C) 2008 Victor Engmark
#
#    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 3 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, see <http://www.gnu.org/licenses/>.
#
################################################################################

# Init
ifs_original="$IFS" # Reset when done

PATH="/usr/bin:/bin"
cmdname=`basename $0`
directory=`dirname $0`

# Remote host
target_dir=".svn-backup/`date +%G-%m-%d`"
target_port=22
target_user=`whoami`

# Subversion
svn_root="/var/lib/svn"
svn_install_root="/usr/bin"

# Error messages from /usr/include/sysexits.h, recommended by
# http://www.faqs.org/docs/abs/HTML/exitcodes.html
EX_OK=0
EX_USAGE=64
EX_CANT_CREATE=73

# Custom errors
EX_NO_SUCH_DIR=91
EX_NO_SUCH_EXEC=92

usage_error()
{
	echo "Usage: ${cmdname} [-v] -h host [-p port] [-u user]" #Code 3 
	exit $EX_USAGE
}

# Process parameters
until [ $# -eq 0 ]
do
	case $1 in
		-v)
			verbose=1
			shift
			;;
		-h)
			if [ -z "$2" ]
			then
				usage_error
			fi
			target_host=$2
			shift 2
			;;
		-p)
			if [ -z "$2" ]
			then
				usage_error
			fi
			target_port=$2
			shift 2
			;;
		-u)
			if [ -z "$2" ]
			then
				usage_error
			fi
			target_user=$2
			shift 2
			;;
		*)
			#Unknown parameter
			usage_error
			;;
	esac
done

if [ -z ${target_host} ]
then
	usage_error
fi

# Use for mandatory directory checks
# $1 is the directory path
# $2 is the (optional) error message
check_directory()
{
	if [ ! -d $1 ]
	then
		echo "No such directory: '${1}'" >&2
		echo $2 >&2
		exit $EX_NO_SUCH_DIR
	fi
}

check_directory $svn_root "Please change \$svn_root to point to the directory where your Subversion repositories are."

check_directory $svn_install_root "Please change \$svn_install_root to point to the directory where Subversion is installed."

# Make sure an executable is available
# $1 is the path to the executable
# $2 is the (optional) error message
check_executable()
{
	if [ ! -x $1 ]
	then
		echo "No such executable: '${1}'" >&2
		echo $2 >&2
		exit $EX_NO_SUCH_EXEC
	fi
}

svn_install_missing="Please change \$svn_install_root to point to the directory where Subversion is installed."
check_executable ${svn_install_root}/svnlook $svn_software_missing
check_executable ${svn_install_root}/svnadmin $svn_software_missing

# Create the temporary folder
temp_dir=`mktemp -t -d ${cmdname}.XXXXXXXXXX` || exit $?

verbose_echo()
{
	if [ $verbose ]
	then
		echo "$*"
	fi
}

# Announce that we're running
verbose_echo "Running $cmdname at `date`."

# Create target directory
ssh -p ${target_port} ${target_user}@${target_host} "mkdir -p \"${target_dir}\"" || exit $?

# Loop over repositories
cd "${svn_root}"
IFS="
" # Make sure paths with spaces don't make any trouble when looping
for repository in *
do
	# Get the last revision
	revision=`${svn_install_root}/svnlook youngest "${repository}"`
	verbose_echo "Backing up repository \"${repository}\" revision ${revision}."

	# Make sure the repo is OK
	verbose_echo "Recovering the repository."
	${svn_install_root}/svnadmin recover --wait "${repository}" > /dev/null

	# Did the recover operation fail?
	if [ $? -ne 0 ]
	then
		echo "Backup failed because recovery failed." >&2
		break
	fi

	# Hotcopy
	verbose_echo "Hot-copying the repository."
	${svn_install_root}/svnadmin hotcopy --clean-logs "${repository}" "$temp_dir/${repository}"

	# Did the hotcopy fail?
	if [ $? -ne 0 ]
	then
		echo "Backup failed because hotcopy failed." >&2
		rm -Rf "$temp_dir"
		break
	fi

	# Compress the hotcopy
	verbose_echo "Compressing the repository in a tar.bz2 archive."
	archive="${repository}-r${revision}.tar.bz2"
	tar -cjpf "$temp_dir/${archive}" -C "$temp_dir" "${repository}"

	# Send it over
	verbose_echo "Copying repository archive to remote host."
	scp -P ${target_port} "$temp_dir/${archive}" "${target_user}@${target_host}:\"${target_dir}/${archive}\""

done

verbose_echo "Cleaning up."
rm -Rf $temp_dir
IFS="$ifs_original"

# End
verbose_echo "${cmdname} completed at `date`."

exit $EX_OK