# shellcheck disable=SC2148 disable=SC2034
declare Version=2.4.0
#==============================================================================
# Copyright and license info is available in the LICENSE file included with
# the Server Deployment Package (SDP), and also available online:
# https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE
#------------------------------------------------------------------------------
#==============================================================================
# Library Functions.
#------------------------------------------------------------------------------
# Function: run
#
# Short: Run a command with optional description, honoring global $VERBOSITY
# and $NO_OP settings. Simpler than runCmd().
#
# Input:
# $1 - cmd. The command to run. The command is displayed first
# if $VERBOSITY > 3.
# $2 - desc. Text description of command to run.
# Optionally, the text string can be prefixed with 'N:', where N is
# a one-digit integer, the minimum verbosity at which the description is to
# be displayed.
# Optionally, a series of text strings can be provided, delimited by '|',
# allowing multiple descriptions to be provided, each with a different
# minimum verbosity setting.
# This parameter is optional. If the N: prefix is omitted, it is
# equivalent to "3:". Sample values: "5:Cool command here:",
# and "3:Regular verbosity message|4:Higher verbosity message."
# and "This is a very|long description."
# $3 - honorNoOpFlag. Pass in 1 to mean "Yes, honor the $NO_OP setting
# and display (but don't run) commands if $NO_OP is set." Otherwise
# $NO_OP is ignored, and the command is always run.
# This parameter is optional; the default value is 1.
# $4 - alwaysShowOutputFlag. If set to 1, show output regardless of $VERBOSITY
# value. Otherwise, only show output if VERBOSITY > 4.
# This parameter is optional; the default value is 0.
# $5 - grepString. If set, this changes the exit code behavior.
# If the specified string exists in the output, a 0 is returned, else 1.
# Strings suitable for use with 'egrep' are allowed.
#
# Description:
# Display an optional description of a command, and then run the
# command. This is affected by $NO_OP and $VERBOSITY. If $NO_OP is
# set, the command is shown, but not run, provided $honorNoOpFlag is 1.
# The description is not shown if $VERBOSITY < 3.
#
# The variables CMDLAST and CMDEXITCODE are set each time runCmd is called.
# CMDLAST contains the last command run. CMDEXITCODE contains its exit code.
#
# Output is shown if either $AlwaysShowOutputFlag is 1 or $VERBOSITY >= 4.
#------------------------------------------------------------------------------
function run () {
dbg "CALL: run ($*)"
local cmd=${1:-}
local desc=${2:-}
local -i honorNoOpFlag=${3:-1}
local -i alwaysShowOutputFlag=${4:-0}
local grepString=${5:-}
local cmdScript=
local cmdOut=
local -i grepExit
CMDLAST=$cmd
CMDEXITCODE=0
if [[ -n "$desc" ]]; then
# Descriptions intended to be multi-line contain a '|' char.
# Each entry may contain an optional 'N:' prefix where N is the
# verbosity level at or above which the message is displayed.
echo "$desc" | tr '|' '\n' | while read -r text; do
if [[ $text =~ ^[0-9]+: ]]; then
descVerbosity=${text%%:*}
text=${text#$descVerbosity:}
if [[ $VERBOSITY -ge $descVerbosity ]]; then
echo -e "$text"
fi
else
msg "$desc"
fi
done
fi
if [[ $honorNoOpFlag -eq 1 && $NO_OP -eq 1 ]]; then
msg "NO-OP: Would run: \"$cmd\"\n"
else
msg "Running: \"$cmd\"."
cmdScript="$(mktemp -t run.XXXXXX).cmd.sh"
cmdOut="${cmdScript%.cmd.sh}.out"
echo -e "#!/bin/bash\n$cmd\n" > "$cmdScript"
chmod +x "$cmdScript"
$cmdScript > "$cmdOut" 2>&1
CMDEXITCODE=$?
if [[ -n "$grepString" ]]; then
# shellcheck disable=SC2196
egrep "$grepString" "$cmdOut" > /dev/null 2>&1
grepExit=$?
CMDEXITCODE="$grepExit"
fi
if [[ $alwaysShowOutputFlag -eq 1 ]]; then
cat "$cmdOut"
else
[[ $VERBOSITY -gt 3 ]] && cat "$cmdOut"
fi
# Be clean and tidy.
/bin/rm -f "$cmdScript" "$cmdOut"
# If a grep was requested, return the exit code from the egrep,
# otherwise return the exit code of the command executed. In
# any case, $CMDEXITCODE contains the exit code of the command.
if [[ -n "$grepString" ]]; then
return $grepExit
else
return $CMDEXITCODE
fi
fi
return 0
}
#------------------------------------------------------------------------------
# Function: rrun
#
# Short: Run a command with on a remote host optional description, honoring
# $VERBOSITY and $NO_OP settings. Simpler than runRemoteCmd().
#
# Input:
# $1 - host. The remote host to run the command on.
# $2 - cmd. The command to run. The command is displayed first
# if $VERBOSITY > 3.
# $3 - desc. Text description of command to run.
# Optionally, the text string can be prefixed with 'N:', where N is
# a one-digit integer, the minimum verbosity at which the description is to
# be displayed.
# Optionally, a series of text strings can be provided, delimited by '|',
# allowing multiple descriptions to be provided, each with a different
# minimum verbosity setting.
# This parameter is optional. If the N: prefix is omitted, it is
# equivalent to "3:". Sample values: "5:Cool command here:"
# $4 - honorNoOpFlag. Pass in 1 to mean "Yes, honor the $NO_OP setting
# and display (but don't run) commands if $NO_OP is set." Otherwise
# $NO_OP is ignored, and the command is always run.
# This parameter is optional; the default value is 1.
# $5 - alwaysShowOutputFlag. If set to 1, show output regardless of $VERBOSITY
# value. Otherwise, only show output if VERBOSITY > 4.
# This parameter is optional; the default value is 0.
# $6 - grepString. If set, this changes the exit code behavior.
# If the specified string exists in the output, a 0 is returned, else 1.
# Strings suitable for use with 'egrep' are allowed.
#
# Description:
# Display an optional description of a command, and then run the
# command. This is affected by $NO_OP and $VERBOSITY. If $NO_OP is
# set, the command is shown, but not run, provided $honorNoOpFlag is 1.
# The description is not shown if $VERBOSITY < 3.
#
# The variables RCMDLAST and RCMDEXITCODE are set each time runCmd is called.
# RCMDLAST contains the last command run. RCMDEXITCODE contains its exit code.
#
# Output is shown if either $AlwaysShowOutputFlag is 1 or $VERBOSITY >= 4.
#------------------------------------------------------------------------------
function rrun () {
dbg "CALL: rrun ($*)"
local host=${1:-Unset}
local cmd=${2:-Unset}
local desc=${3:-}
local -i honorNoOpFlag=${4:-1}
local -i alwaysShowOutputFlag=${5:-0}
local grepString=${6:-}
local rCmdScript=
local rCmdOut=
local -i grepExit
RCMDLAST="$cmd"
RCMDEXITCODE=0
if [[ -n "$desc" ]]; then
echo "$desc" | tr '|' '\n' | while read -r text; do
if [[ $text =~ ^[0-9]+: ]]; then
descVerbosity=${text%%:*}
text=${text#$descVerbosity:}
if [[ $VERBOSITY -ge $descVerbosity ]]; then
echo -e "$text"
fi
else
msg "$desc"
fi
done
fi
if [[ $honorNoOpFlag -eq 1 && $NO_OP -eq 1 ]]; then
msg "NO-OP: Would run: \"$cmd\" on host $host.\n"
else
msg "Running: \"$cmd\" on host $host."
rCmdScript="$(mktemp -t rrun.XXXXXX).cmd.sh"
rCmdOut="${rCmdScript%.cmd.sh}.out"
echo -e "#!/bin/bash\n$cmd\n" > "$rCmdScript"
chmod +wx "$rCmdScript"
if ! scp -pq "$rCmdScript" "$host:${P4TMP:-/tmp}/."; then
RCMDEXITCODE=-1
errmsg "rrun(): Failed to copy temp command script to $host."
return 1
fi
ssh -q -n "$host" "$rCmdScript" > "$rCmdOut" 2>&1
RCMDEXITCODE=$?
if [[ -n "$grepString" ]]; then
# shellcheck disable=SC2196
egrep "$grepString" "$rCmdOut" > /dev/null 2>&1
grepExit=$?
RCMDEXITCODE="$grepExit"
fi
if [[ $alwaysShowOutputFlag -eq 1 ]]; then
cat "$rCmdOut"
else
[[ $VERBOSITY -gt 3 ]] && cat "$rCmdOut"
fi
# Be clean and tidy.
/bin/rm -f "$rCmdScript" "$rCmdOut"
# If a grep was requested, return the exit code from the egrep,
# otherwise return the exit code of the command remotely executed.
# In any case, $RCMDEXITCODE contains the exit code of the command.
if [[ -n "$grepString" ]]; then
return $grepExit
else
return $RCMDEXITCODE
fi
fi
return 0
}