#!/bin/bash # alfplayer # 2014-06-12 # # Mirror the whole Parabola repository using rsync and keep snapshots set -e script_filename="$(basename "$0")" # Default configuration values. # They can be overridden by setting the variables in the calling environment. # 1 to set, 0 to unset : ${repo:=rsync://repo.parabola.nu:875/repos} : ${base_dir:=/srv/http} : ${parabola_dir:=${base_dir}/parabola} : ${oldest_version:=10} # snapshots older than this one will be deleted (see also no_delete above) #: ${date_exclude:=2014.06.19} # disable running this script this date (see next line) : ${forcerun:=0} # force running on excluded date #: ${terminal:=1} # outputs to stdout using rsync --progress (and logs to a file) : ${no_delete:=0} # disable deletion of oldest snapshots #: ${TZ:=UTC} # set time zone export TZ # Lock with flock (provided by util-linux) LOCKFILE="/var/lock/${script_filename}" LOCKFD=99 _lock() { flock -$1 $LOCKFD; } _no_more_locking() { set +e # Save exit status es=$? if [[ -e ${parabola_dir}.tmp ]] ; then echo "=> WARNING: Directory with partial transfer ${LOCAL}.tmp remains in file system" fi if [[ $es != 0 ]] ; then echo "=> ERROR: Unsuccessful script termination. Exit status: $es" fi fi _lock u _lock xn && \ rm -f $LOCKFILE } _prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; } _prepare_locking # Lock now. The lock is disabled automatically when the script exits (with any error code). if ! _lock xn ; then echo "=> ERROR: Could not obtain lock. Exiting." >&2 exit 1 fi date="$(date +%Y.%m.%d)" current="${parabola_dir}-${date}" local_useful=0 if [[ ${date_exclude} && ${forcerun} != 1 ]] ; then if [[ $DATE == ${date_exclude} ]] ; then echo "Manually disabled: ${date}. Exiting." exit 0 fi fi # Test if ${parabola_dir} is an existing symlink pointing to an existing directory if [[ -h ${parabola_dir} ]] ; then last_path="$(readlink -f "${parabola_dir}")" if [[ -d ${last_path} ]] ; then last="${last_path##*/}" local_useful=1 else echo "=> ERROR: ${parabola_dir} is a symlink which does not point to an existing directory." >&2 exit 1 fi else echo "=> ERROR: ${parabola_dir} does not exist or is not a symlink." >&2 exit 1 fi echo echo "=> Creating snapshot for date ${date}" if [[ -e "${current}" ]] ; then echo "${current} already exists. Exiting." >&2 exit 1 fi if [[ -e "${parabola_dir}".tmp ]] ; then echo "${parabola_dir}.tmp already exists. Resuming." else cp -al "${last_path}" "${parabola_dir}".tmp fi rsync "${repo}"/ -rtvlH ${terminal:+--progress} --safe-links --delete --link-dest="$base_dir"/archlinux/ --link-dest="$parabola_dir" "$parabola_dir".tmp cd "$base_dir" echo "=> Delete versions older than the ${oldest_version} oldest version" delete_list=( $(for dir in parabola-* ; do echo "$(find "$dir" -type f -printf '%T@\n' | sort -n | tail -1) $dir" ; done | awk '{print $2}' | head -n -"${oldest_version}") ) for dir in ${delete_list[@]} ; do if [[ ${no_delete} != 1 ]] ; then echo "$dir" rm -rf "$dir" else echo "DRY-RUN: rm -rf $dir" fi done echo "=> Start serving the new repository version" mv "${parabola_dir}.tmp" "${current}" if [[ ${local_useful} == 1 ]] ; then echo " => Deleting ${parabola_dir} symlink" rm -rf "${parabola_dir}" fi # Create symlink echo " => Creating symlink ${current} to ${parabola_dir}" ln -s ${current##*/} ${parabola_dir} echo "=> Disk space report" df -h "${base_dir}" echo "=> ${script_filename} finished successfully. Finish time: $(date --rfc-3339=seconds)"