1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
#!/bin/bash
#-------------------------------------------------------------------------------
# Copyright (C) 2006-2021 British Crown (Met Office) & Contributors.
#
# This file is part of FCM, tools for managing and building source code.
#
# FCM 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.
#
# FCM 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 FCM. If not, see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------------
# NAME
# post-commit-bg
#
# SYNOPSIS
# post-commit-bg REPOS REV
#
# ARGUMENTS
# REPOS - the path to the Subversion repository
# REV - the revision of the commit
# TXN - the commit transaction that becomes the revision
#
# DESCRIPTION
# This script performs the post-commit tasks of a Subversion repository in
# the background.
#
# The script does the following:
# 1. Creates an incremental revision dump of the current revision.
# 2. Update corresponding Trac environment, if relevant.
# 3. Size check. Warn if transaction exceeds 2MB, or the number of
# MB specified in "$REPOS/hooks/post-commit-size-threshold.conf".
# 4. If this changeset has a change to "^/svnperms.conf", install its HEAD
# revision at "$REPOS/hooks/", or remove it from "$REPOS/hooks/" if it is
# removed from the HEAD.
# 5. Runs "$REPOS/hooks/post-commit-bg-custom" and/or
# "$REPOS/hooks/post-commit-background-custom", if available.
# 6. E-mails the host user account on error.
#
# ENVIRONMENT VARIABLES
# FCM_SITE_HOME
# The root location of site configuration.
# FCM_SVN_HOOK_COMMIT_DUMP_DIR
# The path to dump commit deltas. Generate a commit delta if specified.
# FCM_SVN_HOOK_TRAC_ROOT_DIR
# The root directories of Trac environments. Update corresponding Trac
# environment if specified.
# FCM_SVN_HOOK_REPOS_SUFFIX
# A suffix that should be removed from the basename of REPOS to get the
# name of the Trac environment. (Default is "".)
#
# FILES
# $REPOS/hooks/post-commit-bg-custom
# $REPOS/hooks/post-commit-background-custom
#-------------------------------------------------------------------------------
set -eu
. "$(dirname $0)/trac_hook"
REPOS=$1
REV=$2
TXN=$3
export PATH=${PATH:-'/usr/local/bin:/bin:/usr/bin'}:$(dirname $0)
THIS=$(basename $0)
USER=${USER:-$(whoami)}
LOG_REV="$REPOS/log/$THIS-$REV.log"
main() {
local RET_CODE=0
local NOW=$(date -u +%FT%H:%M:%SZ)
local AUTHOR=$(svnlook author -r "$REV" "$REPOS")
echo "$NOW+ $REV by $AUTHOR"
# Dump revision delta
if [[ -n ${FCM_SVN_HOOK_COMMIT_DUMP_DIR:-} ]]; then
if [[ ! -d "$FCM_SVN_HOOK_COMMIT_DUMP_DIR" ]]; then
mkdir -p "$FCM_SVN_HOOK_COMMIT_DUMP_DIR" || true
fi
local NAME=$(basename "$REPOS")
local DUMP="$FCM_SVN_HOOK_COMMIT_DUMP_DIR/$NAME-$REV.gz"
local TMP_DUMP="$FCM_SVN_HOOK_COMMIT_DUMP_DIR/$NAME-$REV-tmp.gz"
echo "svnadmin dump -r$REV --incremental --deltas $REPOS | gzip \\"
echo " | (dd 'conv=fsync' \"of=$TMP_DUMP\" 2>/dev/null)"
svnadmin dump "-r$REV" --incremental --deltas "$REPOS" | gzip \
| (dd 'conv=fsync' "of=$TMP_DUMP" 2>/dev/null) || RET_CODE=$?
if [[ -s "${TMP_DUMP}" ]]; then
echo "mv \"${TMP_DUMP}\" \"${DUMP}\""
mv "${TMP_DUMP}" "${DUMP}" || RET_CODE=$?
else
echo "[WARN] ${NAME}-${REV}: zero dump size" >&2
rm -f "${TMP_DUMP}"
fi
fi
# Resync Trac
trac_hook "$REPOS" "$REV" added || RET_CODE=$?
# Check size - send warning email if threshold exceeded
local MB=1048576
local THRESHOLD=2
local SIZE_THRESHOLD_FILE="${REPOS}/hooks/post-commit-size-threshold.conf"
if [[ -f "${SIZE_THRESHOLD_FILE}" && -r "${SIZE_THRESHOLD_FILE}" ]]; then
THRESHOLD=$(<"${SIZE_THRESHOLD_FILE}")
fi
local REV_FILE="${REPOS}/db/revs/$((${REV} / 1000))/${REV}"
local REV_FILE_SIZE=$(du -b -s "${REV_FILE}" | cut -f 1)
if ((${REV_FILE_SIZE} > ${THRESHOLD} * ${MB})); then
echo "REV_FILE_SIZE=${REV_FILE_SIZE} # >${THRESHOLD}MB"
RET_CODE=1
else
echo "REV_FILE_SIZE=${REV_FILE_SIZE} # <${THRESHOLD}MB"
fi
# Install commit.conf and svnperms.conf, if necessary
local NAME=$(basename "${REPOS}")
if [[ -n "${FCM_SVN_HOOK_REPOS_SUFFIX:-}" ]]; then
NAME="${NAME%${FCM_SVN_HOOK_REPOS_SUFFIX}}"
fi
local CHANGED=$(svnlook changed -r "${REV}" "${REPOS}")
local FILE=
for FILE in 'commit.conf' 'svnperms.conf'; do
# Ignore if there is a site override
if [[ -n "${FCM_SITE_HOME:-}" \
&& -e "${FCM_SITE_HOME:-}/svn-hooks/${NAME}/${FILE}" ]]
then
continue
fi
if grep -q "^....${FILE}\$" <<<"${CHANGED}"; then
# Don't specify revision, so always look at latest.
if svnlook filesize "${REPOS}" "${FILE}" >/dev/null 2>&1; then
echo "svnlook cat ${REPOS} ${FILE} >${REPOS}/hooks/${FILE}"
svnlook cat "${REPOS}" "${FILE}" >"${REPOS}/hooks/${FILE}"
else
echo "rm -f ${REPOS}/hooks/${FILE}"
rm -f "${REPOS}/hooks/${FILE}"
fi
fi
done
# If relevant, notify owners
local COMMIT_CONFIG="${REPOS}/hooks/commit.conf"
if grep -q 'notify-owner' "$COMMIT_CONFIG" 2>/dev/null; then
local ADDRS=$('post-commit-bg-notify-who' "$REPOS" "$REV" "$TXN")
if [[ -n $ADDRS ]]; then
SUBJECT="-s$(basename $REPOS)@$REV by $AUTHOR"
FROM=
if [[ -n ${FCM_SVN_HOOK_NOTIFICATION_FROM:-} ]]; then
FROM="-r${FCM_SVN_HOOK_NOTIFICATION_FROM:-}"
fi
echo -n "svn log -v -r \"$REV\" \"file://$REPOS\""
echo " | mail \"$FROM\" \"$SUBJECT\" \"$ADDRS\""
svn log -v -r "$REV" "file://$REPOS" \
| mail "$FROM" "$SUBJECT" "$ADDRS"
fi
fi
# Custom hook
local CUSTOM_HOOK=
for CUSTOM_HOOK in \
"$REPOS/hooks/$THIS-custom" \
"$REPOS/hooks/post-commit-background-custom"
do
if [[ -x "$CUSTOM_HOOK" ]]; then
echo "$CUSTOM_HOOK $REPOS $REV $TXN"
"$CUSTOM_HOOK" "$REPOS" "$REV" "$TXN" || RET_CODE=$?
fi
done
echo "RET_CODE=$RET_CODE"
return $RET_CODE
}
if ! main 1>$LOG_REV 2>&1; then
if [[ -n ${FCM_SVN_HOOK_ADMIN_EMAIL:-} ]]; then
mail -s "[$THIS] $REPOS@$REV" "$FCM_SVN_HOOK_ADMIN_EMAIL" <"$LOG_REV" \
|| true
fi
fi
cat "$LOG_REV"
rm -f "$LOG_REV"
exit
|