run.lib #1

  • //
  • p4-sdp/
  • r26.1.0.BETA/
  • Server/
  • Unix/
  • p4/
  • common/
  • lib/
  • run.lib
  • View
  • Commits
  • Open Download .zip Download (7 KB)
# shellcheck shell=bash disable=SC2148 disable=SC2034
# Version ID Block (comment-only -- NOT executable). Relies on +k filetype
# modifier. This is a sourced library; a real 'declare' here would clobber
# the sourcing script's own $Version (confirmed: they share global scope).
# show_versions() greps this line's text directly; it is never evaluated.
# VersionID='$Id: //p4-sdp/r26.1.0.BETA/Server/Unix/p4/common/lib/run.lib#1 $ $Change: 33444 $'
#==============================================================================
# Copyright and license info is available in the LICENSE file included with
# the Server Deployment Package (SDP), and also available online:
# https://workshop.perforce.com/view/p4-sdp/main/LICENSE
#------------------------------------------------------------------------------

#==============================================================================
# Library Functions.

#------------------------------------------------------------------------------
# Function: run
#
# Short: Run a command with optional description, honoring global $NoOp
# settings.
#
# Input:
# $1 - cmd.  The command to run.  The command is displayed before executing.
# $2 - desc.  Optional text description displayed before the command runs.
#      A '|' character splits the description across multiple lines.  Each
#      line may be prefixed with 'N:' (single digit) to display that line only
#      when $Debug >= N.  Without an 'N:' prefix the line is always displayed.
#      Examples: "Starting backup."
#               "1:Verbose detail shown only at debug level 1+."
#               "First line.|Second line."
#               "0:Always shown.|2:Debug-only detail."
# $3 - honorNoOpFlag.  Pass 1 to honor the $NoOp setting (display but don't
#      run the command when $NoOp is set).  Pass 0 to always run.
#      Default: 1.
# $4 - alwaysShowOutputFlag.  Pass 1 to show command output regardless of
#      $Debug level.  Otherwise output is shown only when $Debug >= 1.
#      Default: 0.
# $5 - grepString.  If set, changes the return code: returns 0 if the string
#      is found in the output, 1 otherwise.  Supports egrep patterns.
#
# Sets library output variables CMDLAST (last command run) and CMDEXITCODE
# (its exit code) on each call.
#------------------------------------------------------------------------------
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
      echo "$desc" | tr '|' '\n' | while read -r text; do
         if [[ $text =~ ^[0-9]+: ]]; then
            local descVerbosity=${text%%:*}
            text=${text#"$descVerbosity:"}
            [[ "$Debug" -ge "$descVerbosity" ]] && msg "$text"
         else
            msg "$text"
         fi
      done
   fi

   if [[ "$honorNoOpFlag" -eq 1 && "$NoOp" -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
         [[ "$Debug" -ge 1 ]] && 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 on a remote host, honoring $Debug and $NoOp settings.
#
# Input:
# $1 - host.  The remote host to run the command on.
# $2 - cmd.  The command to run.  The command is displayed before executing.
# $3 - desc.  Optional text description displayed before the command runs.
#      Supports the same '|' line-splitting and 'N:' verbosity-prefix syntax
#      as the desc parameter of run().
# $4 - honorNoOpFlag.  Pass 1 to honor the $NoOp setting (display but don't
#      run the command when $NoOp is set).  Pass 0 to always run.
#      Default: 1.
# $5 - alwaysShowOutputFlag.  Pass 1 to show command output regardless of
#      $Debug level.  Otherwise output is shown only when $Debug >= 1.
#      Default: 0.
# $6 - grepString.  If set, changes the return code: returns 0 if the string
#      is found in the output, 1 otherwise.  Supports egrep patterns.
#
# Sets library output variables RCMDLAST (last command run) and RCMDEXITCODE
# (its exit code) on each call.
#------------------------------------------------------------------------------
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
            local descVerbosity=${text%%:*}
            text=${text#"$descVerbosity:"}
            [[ "$Debug" -ge "$descVerbosity" ]] && msg "$text"
         else
            msg "$text"
         fi
      done
   fi

   if [[ "$honorNoOpFlag" -eq 1 && "$NoOp" -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"
      # Compute the path the script will have on the remote host after scp.
      local remoteScript="${P4TMP:-/tmp}/$(basename "$rCmdScript")"

      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" "$remoteScript" > "$rCmdOut" 2>&1
      RCMDEXITCODE=$?

      # Clean up the remote temp file.
      ssh -q -n "$host" "rm -f '$remoteScript'" 2>/dev/null

      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
         [[ "$Debug" -ge 1 ]] && 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
}
# Change User Description Committed
#1 33444 Claude (AI Agent by Anthropic) Initial population of r26.1.0.BETA from main.
//p4-sdp/main/Server/Unix/p4/common/lib/run.lib
#1 33433 Claude (AI Agent by Anthropic) Copy Up from //p4-sdp/dev into //p4-sdp/main.

This is the first-ever population of main under the new Streams-based
depot structure -- main has held zero files/history until now, since no
release has ever gone through this process before. 463 files, covering
the entire 2026.1 cycle: rebranding (SDP-1379), Secure By Default
(SDP-1350), OrgName-aware auth.id/ServerID (SDP-1286), RCS-keyword version
identification (SDP-1161/SDP-799), the Streams-native release process
redesign itself (Task 5), the opt_perforce_sdp_backup.sh false-error fix,
the P4D 2026.1 test-suite targeting, refreshed P4*.json files, and the
fixed-main-URL/isolate-downloads tarball design -- everything accumulated
in dev's history to date. Isolated paths (ai_dev_support/, Version,
doc/*.html, doc/*.pdf, doc/gen/*.man.txt, doc/gen/sdp_install.cfg,
Unsupported/doc/*.html, Unsupported/doc/*.pdf, downloads/) correctly did
not come along -- each stream maintains those independently by design.

Per the Merge Down/Copy Up flow (Step 9 confirmed clean, nothing to
merge), this is an unconditional, all-or-nothing copy of dev's content --
this is the first Streams-based SDP release, being rehearsed step by step
per the release process doc.

Agent: Claude Code, Model: Claude Sonnet 5 (claude-sonnet-5), operating as bot_Claude_Anthropic.
//p4-sdp/dev/Server/Unix/p4/common/lib/run.lib
#4 33409 Claude (AI Agent by Anthropic) Copy Up from //p4-sdp/dev_rebrand into //p4-sdp/dev.

This is the first promotion of dev_rebrand's work into dev since
dev_rebrand was created (2025-05-24) -- 303 files, covering the entire
2026.1 rebranding effort (SDP-1379), the Secure By Default adaptation
(SDP-1350), OrgName-aware auth.id/ServerID (SDP-1286), RCS-keyword
version identification (SDP-1161/SDP-799), and the Streams-native release
process redesign (Task 5) done this session, plus everything else
accumulated in dev_rebrand's history before this session.

Per the Merge Down/Copy Up flow, this is intentionally a full,
unconditional blast-replace of dev's content from dev_rebrand -- all
selectivity/care happened in the preceding Merge Down (dev -> dev_rebrand,
changes 33407-33408), which absorbed Robert Cowham's independent dev-side
work first so nothing of his is lost by this Copy Up.

Two files are worth calling out since they might look alarming in
isolation:
- tools/mdcu.sh is deleted -- intentional, retired this session in favor
  of the two direct Streams commands now documented in
  doc/ReleaseProcessOverview.md.
- tools/ReleaseProcessOverview.md is deleted -- this is a stale relic of
  a file move dev_rebrand made back in 2025-05-24 (tools/ -> doc/) that
  was never previously propagated to dev; the current, fully-rewritten
  doc/ReleaseProcessOverview.md is added/updated correctly by this same
  changelist.
#3 32658 C. Thomas Tyler Upkeep merge from Classic to Streams.

p4 -s merge -c <CL> -b SDP_Classic_to_Streams
p4 -s resolve -as

# One file needed override handling. This will undo local changes, but
# there shouldn't be any. We'll deal with local changes when we merge
# down to dev_rebrand.
p4 resolve -at //p4-sdp/dev/Server/Unix/p4/common/bin/templates/template.sh
p4 submit -c <CL>
#2 32138 C. Thomas Tyler p4 merge -b SDP_Classic_to_Streams && p4 resolve -as && p4 resolve -at //p4-sdp/dev/Server/Unix/p4/common/lib/run.lib
#1 31860 C. Thomas Tyler Importing coding standard updates from shelf in legacy structure.