#!/bin/bash
set -u

#------------------------------------------------------------------------------
# This broker filter script limits commands of a given type to one process
# running at a time for the same user.  It relies on 'p4 monitor' having been
# enabled with 'p4 configure set monitor=1' ( or higher than 1).
#
# This is called by the 'p4broker' process.  The p4broker provides an array
# of fields on STDIN, e.g. "command: populate" and "user: joe", which get
# parsed to inform the business logic of this script.
#
# This is enabled by adding a block like the following to a broker config
# file, with this example limiting the 'p4 populate' command:
#------------------------------------------------------------------------------
# command: ^populate$
# {
#     action  = filter;
#     execute = /p4/common/bin/broker/one_per_user.sh;
# }
#------------------------------------------------------------------------------
#
# If this script encounters errors, such as not being able to parse the input
# properly, it logs the errors and silently exits, so as not to interrupt
# user interactions with the server unduly.
function log () { echo -e "$ThisScript version $Version $Timestamp: $*" >> "$Log"; }

# Version ID Block. Relies on +k filetype modifier.
#------------------------------------------------------------------------------
# shellcheck disable=SC2016
declare VersionID='$Id: //p4-sdp/r26.1.0.BETA/Unsupported/Samples/broker/one_per_user.sh#1 $ $Change: 33444 $'
declare VersionStream=${VersionID#*//}; VersionStream=${VersionStream#*/}; VersionStream=${VersionStream%%/*};
declare VersionCL=${VersionID##*: }; VersionCL=${VersionCL%% *}
declare Version=${VersionStream}.${VersionCL}
[[ "$VersionStream" == r* ]] || Version="${Version^^}"

declare ThisScript=${0##*/}
declare Cmd=Unset
declare User=Unset
declare Timestamp=
declare Log=
declare RunningCmd=

Log="${LOGS:-/tmp}/one_per_user.log"
Timestamp="$(date +'%Y/%m/%d:%H:%M:%S')"

while read -r line; do
   [[ "$line" == "command:"* ]] && Cmd="${line#command: }"
   [[ "$line" == "user:"* ]] && User="${line#user: }"
done

if [[ "$Cmd" == Unset || "$User" == Unset ]]; then
   log "Error: Couldn't get cmd/user ($Cmd/$User) from input. Ignoring."
   echo -e "action: PASS\\n"
   exit 0
fi

# Use 'p4 monitor show -ael' to determine if the given user has another command of the
# same type running.
log "Info: Looking for command $Cmd by user $User in this output:"
RunningCmd="$("$P4BIN" monitor show -ael 2>/dev/null | grep -E " R $User .* populate " 2>/dev/null)"

if [[ -z "$RunningCmd" ]]; then
   log "PASS for $Cmd command by user $User."
   echo -e "action: PASS\\n"
   exit 0
else
   log "REJECT for $Cmd command by user $User, another command is already running."
   echo -e "action: REJECT"
   echo -e "message: There is already one $Cmd command running for user $User. Please wait until that completes before starting another."
   exit 1
fi

exit 0
