summaryrefslogtreecommitdiff
path: root/parabola-mirror
diff options
context:
space:
mode:
authorEsteban Carnevale <alfplayer@mailoo.org>2014-11-05 11:34:31 -0300
committerEsteban Carnevale <alfplayer@mailoo.org>2014-11-05 11:34:31 -0300
commitb22abc87dfd204f5667a418fd251863226a00655 (patch)
tree61d140f92c045819be87c421a04651bf431f3f97 /parabola-mirror
parent02cf9a83034daed51ee7df83b8973ea1cafee9eb (diff)
parabola-mirror: Add script
Diffstat (limited to 'parabola-mirror')
-rwxr-xr-xparabola-mirror183
1 files changed, 183 insertions, 0 deletions
diff --git a/parabola-mirror b/parabola-mirror
new file mode 100755
index 0000000..28b4c75
--- /dev/null
+++ b/parabola-mirror
@@ -0,0 +1,183 @@
+#!/bin/bash
+
+# alfplayer
+# 2014-06-12
+#
+# Mirror the whole Parabola repository using rsync and keep snapshots
+
+set -e
+
+script_filename="$(basename "$0")"
+
+# Create temporary log file
+log_tmp="$(mktemp -p /var/tmp)"
+
+# Default configuration values.
+# They can be overridden by setting the variables in the calling environment.
+# 1 to set, 0 to unset
+: ${repo:=rsync://repo.parabolagnulinux.org: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)
+: ${log_file:=${script_filename}.log}
+#: ${mail_to:=your@mail.com} # comment out to disable
+#: ${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), save to log file and send email on exit
+LOCKFILE="/var/lock/${script_filename}"
+LOCKFD=99
+
+_lock() { flock -$1 $LOCKFD; }
+
+# Wait until there is no process writing to ${log_tmp}
+# Waiting can be necessary if command groups are not executed until the end
+_wait_log_tmp() {
+ if [[ -e "${log_tmp}" ]] ; then
+ while fuser "${log_tmp}" > /dev/null ; do
+ sleep 0.2
+ done
+ fi
+}
+
+_no_more_locking() {
+ set +e
+
+ # Save exit status
+ es=$?
+
+ _wait_log_tmp
+ cat "${log_tmp}" >> "${log_file}"
+
+ if [[ $? == 0 ]] ; then
+ log_written=1
+ else
+ echo "=> ERROR: Failed to write to log file: ${log_file}" >&2
+ fi
+
+ if [[ -e ${parabola_dir}.tmp ]] ; then
+ echo "=> WARNING: Directory with partial transfer ${LOCAL}.tmp remains in file system"
+ fi
+
+ if [[ ${mail_to} ]] ; then
+ echo "=> Sending output to ${mail_to}"
+ mail -s "[$(hostname)] ${script_filename}" "${mail_to}" < "${log_tmp}"
+ fi
+
+ if [[ ${log_written} == 1 ]] ; then
+ rm -f "${log_tmp}"
+ fi
+
+ if [[ $es != 0 ]] ; then
+ echo "=> WARNING: Unsuccessful script termination. Exit status: $es"
+ if [[ ${mail_to} ]] ; then
+ echo "=> Sending error notification to ${mail_to}"
+ mail -s "[$(hostname)] ${script_filename} failed. See logged output." "${mail_to}" < /dev/null
+ 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
+
+} &> >(tee -a "${log_tmp}")
+
+_wait_log_tmp
+
+rsync "${repo}"/ -rtvlH ${terminal:+--progress} --log-file="${log_tmp}" --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 /
+
+echo "=> ${script_filename} finished successfully. Finish time: $(date --rfc-3339=seconds)"
+
+} &> >(tee -a "${log_tmp}")
+
+_wait_log_tmp