You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.5 KiB

#!/bin/bash
ENABLE_DEBUG_LOGS=true
ENABLE_ERROR_LOGS=true
ENABLE_DISCORD_LOGS=true
ENABLE_DISCORD_ERROR_LOGS=false
ENABLE_FILE_LOGS=true
# Source in user profile in case this is a non-interactive thingy; consider separating into a different thing
source "$HOME/.profile"
if [ -z "${script_locks_path}" ]; then
echo "ERROR: script_locks_path undefined! You can define this in your user profile."
exit
fi
if [ -z "${patches_root_path}" ]; then
echo "ERROR: patches_root_path undefined! You can define this in your user profile."
exit
fi
if [ -z "${patches_data_path}" ]; then
echo "ERROR: patches_data_path undefined! You can define this in your user profile."
exit
fi
if [ -z "$updaterepos_webhook_url" ]; then
echo "WARNING: updaterepos_webhook_url undefined! Nothing will be logged to discord/webhook."
ENABLE_DISCORD_LOGS=false
fi
if [ -z "$error_webhook_url" ]; then
echo "WARNING: error_webhook_url undefined! LOGERR will not be logged to discord/webhook."
ENABLE_DISCORD_ERROR_LOGS=false
fi
mkdir -p "${script_locks_path}"
lockfile="${script_locks_path}/updaterepos.lock"
{
if ! flock -n 9
then
exit 1
fi
#LOG_DIR="${script_logs_path}/updaterepos"
LOG_DIR="${patches_root_path%/}/logs"
LOG_FILE="${LOG_DIR%/}/updaterepos.log"
UPTODATE_FILE="${LOG_DIR}/UpToDate.txt"
UPDATED_FILE="${LOG_DIR}/Updated.txt"
UPDATEFAILED_FILE="${LOG_DIR}/UpdateFailed.txt"
# Ensure log and lock dirs exist
mkdir -p "$LOG_DIR"
# Cleanup previous runs
rm "$UPTODATE_FILE" "$UPDATED_FILE" "$UPDATEFAILED_FILE" "$LOG_FILE"
set -o pipefail
# Log a message to a webhook URL in Discord format
# @param $1 URL to log to
# @param $2 Username to log as
# @param $3 Message to log
DISCORD_LOG() {
WEBHOOK_URL=$1
USERNAME=$2
shift
shift
curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"${USERNAME}\", \"embeds\": [ { \"description\": \"${@}\"}]}" "${WEBHOOK_URL}"
}
# Log message to both console and Discord
# @param $1 Whether or not to log this message to discord
# @param $2 Whether or not to log this message to log file
# $param $3 Message to log
PRINT_LOG() {
LOG_TO_DISCORD=$1
LOG_TO_FILE=$2
shift
shift
echo "${@}"
if $LOG_TO_DISCORD; then
DISCORD_LOG "$updaterepos_webhook_url" "Patch" "$@"
fi
if $LOG_TO_FILE; then
echo "$@" >> ${LOG_FILE}
fi
}
LOGMSG() {
PRINT_LOG $ENABLE_DISCORD_LOGS $ENABLE_FILE_LOGS "$@"
}
LOGDBG() {
if $ENABLE_DEBUG_LOGS; then
PRINT_LOG false $ENABLE_FILE_LOGS "$@"
fi
}
LOGERR() {
if $ENABLE_ERROR_LOGS; then
PRINT_LOG false $ENABLE_FILE_LOGS "$@"
fi
if $ENABLE_DISCORD_ERROR_LOGS; then
DISCORD_LOG "${error_webhook_url}" "Patch" "$@"
fi
}
# Syncs a single mirror
SYNCMIRRORTHREAD() {
ADDRESS=$(echo "${2}" | awk -F@ '{print $2}' | awk -F: '{print $1}')
LOG_FILE=${LOG_FILE}.${ADDRESS}.log
rm "$LOG_FILE"
RSYNC_OUT=$(rsync -rptDhiz --timeout=30 --delete --delete-excluded ${3} -e "ssh -p ${1}" "${patches_data_path}/" ${2} | tee -a ${LOG_FILE})
RSYNC_STATUS=$?
if [ ${RSYNC_STATUS} -eq 0 ]
then
# Success
if [[ -z "${RSYNC_OUT}" ]]
then
# Success and no updates
LOGDBG "${ADDRESS} is already up to date"
echo -n "${ADDRESS} " >> "$UPTODATE_FILE"
else
# Success and updated
LOGMSG "Finished sync to: ${ADDRESS}"
echo -n "${ADDRESS} " >> "$UPDATED_FILE"
fi
else
# Failed
LOGERR "Failed to sync to: ${ADDRESS} (status code ${RSYNC_STATUS})"
echo -n "${ADDRESS} " >> "$UPDATEFAILED_FILE"
fi
}
# Kicks off a full sync to a background thread
SYNCMIRROR() {
SYNCMIRRORTHREAD "$@" &
let "++pidlen"
pids[${pidlen}]=$!
}
# Read in and sync each mirror
mirror_list=$(grep -vE "[[:space:]]*#" "${patches_root_path}/updaterepos.targets")
while read -r line
do
# File in format: 'PORT PATH'
ssh_port=$(echo "$line" | awk '{ print $1 }')
ssh_path=$(echo "$line" | awk '{ print $2 }')
exclude_from=$(echo "$line" | awk '{ print $3 }')
if [[ ! -z $exclude_from ]]; then
exclude_from="--exclude-from=${patches_root_path}/${exclude_from}"
fi
SYNCMIRROR "$ssh_port" "$ssh_path" "$exclude_from"
done < <(echo "$mirror_list")
# wait for all pids
for pid in ${pids[*]}; do
wait $pid
done
# Read in outputs
if [[ -f $UPTODATE_FILE ]]; then
UPTODATE="$(cat ${UPTODATE_FILE})"
fi
if [[ -f $UPDATED_FILE ]]; then
UPDATED="$(cat ${UPDATED_FILE})"
fi
if [[ -f $UPDATEFAILED_FILE ]]; then
UPDATEFAILED="$(cat ${UPDATEFAILED_FILE})"
fi
# We're done syncing; log/notify
if [[ -z ${UPDATED} ]]; then
LOGDBG "No patch repos successfully updated"
if [[ ! -z ${UPDATEFAILED} ]]; then
LOGERR "No patch repos updated; repos failed to update: ${UPDATEFAILED}"
fi
elif [[ ! -z ${UPDATEFAILED} ]]; then
LOGERR "The following repos are now up to date: ${UPDATED}; repos failed to update: ${UPDATEFAILED}; repos already up-to-date: ${UPTODATE}"
else
LOGMSG "All patch repos are now up to date; repos already up-to-date: ${UPTODATE}"
fi
} 9>"$lockfile"