#!/bin/bash set -u #============================================================================== # Copyright and license info is available in the LICENSE file included with # this package. #------------------------------------------------------------------------------ #============================================================================== # Declarations and Environment declare -i ErrorCount=0 declare -i WarningCount=0 declare -i Debug=0 declare -i NoOp=1 declare ThisScript=${0##*/} declare ThisUser= declare ThisHost=${HOSTNAME%%.*} declare Version=1.0.1 declare CmdLine="$0 $*" declare LogsDir="${LOGS:-${HOME:-/tmp}}" declare LogDatestamp= declare LogLink= declare Log= declare H1="==============================================================================" declare H2="------------------------------------------------------------------------------" declare RequiredUtils="awk bc date grep id ls tail wc" #============================================================================== # Local Functions function msg () { echo -e "$*"; } function dbg () { [[ "$Debug" -eq 0 ]] || msg "DEBUG: $*"; } function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ErrorCount+=1; } function warnmsg () { msg "\\nWarning: ${1:-Unknown Warning}\\n"; WarningCount+=1; } function bail () { errmsg "${1:-Unknown Error}"; exit "$ErrorCount"; } #------------------------------------------------------------------------------ # Function: terminate function terminate { # Disable signal trapping. trap - EXIT SIGINT SIGTERM dbg "$ThisScript: EXITCODE: $ErrorCount" # Stop logging. [[ "$Log" == off ]] || msg "\\nLog is: $Log\\n${H1}" # With the trap removed, exit. exit "$ErrorCount" } #------------------------------------------------------------------------------ # Function: usage (documentation) # # Input: # $1 - style, '-h' (for short usage synopsis) or '-man' (for full man-page # documentation). Default is -h. # # $2 - error message (optional). Specify this if usage() is called due to # usage error, in which case the given message displayed first, followed by # the standard usage message (short or long depending on $1). If displaying an # error, usually $1 should be -h so that the longer usage message doesn't # obscure the supplied usage error message. # # Sample Usage: # usage # usage -h # usage -man # usage -h "Incorrect command line usage." #------------------------------------------------------------------------------ function usage { declare style=${1:--h} declare errorMessage=${2:-} [[ -n "$errorMessage" ]] && \ errmsg "\\n\\nUsage Error:\\n\\n$errorMessage\\n\\n" msg "USAGE for $ThisScript v$Version: $ThisScript -L <log>] [-y] [-d|-D] or $ThisScript [-h|-man] " if [[ $style == -man ]]; then msg " DESCRIPTION: This script will convert an edge server into a commit server. WARNING: THIS IS NOT A STANDARD OPERATION! This is only suitable in a server split scenario. It supports a method of server splitting that can be thought of as an alternative to using the perfsplit tool. The edge server can optionally be configured as a filtered edge server, using the RevisionDataFilter field of the the server spec to reduce set of files from the commit server that will be available on the edge server. The gist is: OPERATIONAL PROCEDURE: The start state for this script is: There is a commit server WHAT THIS DOES NOT HANDLE: * Authentication * Swarm * Impact on other integrated systems. OPTIONS: -L <log> Specify the path to a log file, or the special value 'off' to disable logging. By default, all output (stdout and stderr) goes to EDITME_DEFAULT_LOG $LogsDir/ NOTE: This script is self-logging. That is, all standard and error output displayed is also captured in the log file. Use of 'tee' and redirection with '>' and '2>&1' are unnecessary. -si Operate silently. All output (stdout and stderr) is redirected to the log only; no output appears on the terminal. This cannot be used with '-L off'. EDITME: This is useful when running from cron, as it prevents automatic email from being sent by cron directly, as it does when a script called from cron generates any output. This script is then responsible for email handling, if any is to be done. -n No-Op. Prints commands instead of running them. DEBUGGING OPTIONS: -d Enable additional debug output. -D Set extreme debugging verbosity using bash 'set -x' mode. Implies '-d'. HELP OPTIONS: -h Display short command line usage synopsis. -man Display this documentation manual page. EXAMPLES: SEE ALSO: " fi exit 2 } #------------------------------------------------------------------------------ # Function: get_old_log_timestamp ($log) # # Get the last modified timestamp of the old log in a cross-platform manner. # If we don't get a correct value using 'stat' (which varies across the # UNIX/Linux/MacOSX spectrum), use the current time as a fallback. In that # case, the timestamp will reflect the time the log was moved rather than when # it was last modified, but that's still reasonable. The file timestamp will # still have the correct last-modified time. #------------------------------------------------------------------------------ function get_old_log_timestamp () { local log=${1:-} local oldLogTimestamp= [[ -n "$log" ]] || return if [[ "$(uname -s)" == "Darwin" ]]; then oldLogTimestamp=$(stat -L -f %Sm -t '%Y-%m-%d-%H%M%S' "$log" 2>/dev/null) else oldLogTimestamp="$(stat -L -c '%10y' "$log" | sed -e 's@[.].*$@@g' -e 's@:@@g' -e 's@ @-@g')" fi [[ "$oldLogTimestamp" =~ ^[2-9]{1}[0-9]{3}- ]] || oldLogTimestamp=$(date +'%Y-%m-%d-%H%M%S') echo "$oldLogTimestamp" } #============================================================================== # Command Line Processing declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-h) usage -h;; (-V) msg "$ThisScript v$Version"; exit 2;; (-man) usage -man;; (-y) NoOp=0;; (-L) Log="$2"; shiftArgs=1;; (-d) Debug=1;; # Debug mode. (-D) Debug=1; set -x;; # Use bash 'set -x' extreme debugging mode. (*) usage -h "Unknown arg: $1)";; esac # Shift (modify $#) the appropriate number of times. shift; while [[ $shiftArgs -gt 0 ]]; do [[ $# -eq 0 ]] && usage -h "Incorrect number of arguments." shiftArgs=$shiftArgs-1 shift done done set -u #============================================================================== # Command Line Verification if [[ -z "$Log" ]]; then LogDatestamp=$(date +'%Y-%m-%d-%H%M%S') LogLink="${LogsDir}/${ThisScript%.sh}.log" Log="${LogsDir}/${ThisScript%.sh}.${LogDatestamp}.log" fi #============================================================================== # Main Program for u in $RequiredUtils; do [[ -n "$(command -v "$u")" ]] || errmsg "Missing required utility: $u" done [[ "$ErrorCount" -eq 0 ]] || bail "Aborted early due to missing required utilitiies." trap terminate EXIT SIGINT SIGTERM if [[ "$Log" != off ]]; then if [[ -e "$Log" ]]; then # shellcheck disable=SC2012 OldLogTimestamp="$(ls -l --time-style +'%Y%m%d-%H%M%S' "$Log" 2>/dev/null | awk '{print $6}')" # shellcheck disable=SC2012 [[ -n "$OldLogTimestamp" ]] ||\ OldLogTimestamp="$(ls -l -D '%Y%m%d-%H%M%S' "$Log" 2>/dev/null | awk '{print $6}')" [[ -n "$OldLogTimestamp" ]] ||\ OldLogTimestamp="$(date +'%Y%m%d-%H%M%S' "$Log" 2>/dev/null)" [[ -n "$OldLogTimestamp" ]] ||\ OldLogTimestamp="old" OldLog="${LogsDir}/${ThisScript%.sh}.${OldLogTimestamp}.log" mv -f "$Log" "$OldLog" || bail "Could not do: mv -f \"$Log\" \"$OldLog\"" dbg "Rotated $Log to $OldLog" fi if [[ -e "$LogLink" ]]; then if [[ -L "$LogLink" ]]; then rm -f "$LogLink" else # If the name that should be a symlink is not a symlink, move it aside before # creating the symlink. OldLogTimestamp=$(get_old_log_timestamp "$LogLink") mv -f "$LogLink" "${LogLink%.log}.${OldLogTimestamp}.log" ||\ bail "Could not move old log file aside; tried: mv -f \"$LogLink\" \"${LogLink%.log}.${OldLogTimestamp}.log\"" fi fi touch "$Log" || bail "Couldn't touch log file [$Log]." # Use a subshell so the 'cd' doesn't persist. ( cd "$LogsDir"; ln -s "${Log##*/}" "${LogLink##*/}"; ) ||\ bail "Couldn't initialize log symlink; tried: ln -s \"$Log\" \"$LogLink\"" # Redirect stdout and stderr to a log file. exec > >(tee "$Log") exec 2>&1 msg "${H1}\\nLog is: $Log\\n" fi ThisUser=$(id -n -u) msg "Started $ThisScript v$Version as $ThisUser@$ThisHost at $(date).\\nCommand Line was: $CmdLine" [[ "$NoOp" -eq 1 ]] && msg "NO_OP: Operating in DRY RUN mode." if [[ $ErrorCount -eq 0 && $WarningCount -eq 0 ]]; then msg "${H2}\\nAll processing completed successfully.\\n" elif [[ $ErrorCount -eq 0 ]]; then msg "${H2}\\nProcessing completed, but with $WarningCount warning. Review the output above carefully.\\n" else msg "${H2}\\nProcessing completed, but with $ErrorCount errors and $WarningCount warnings. Scan above output carefully.\\n" fi # Display runtime. msg "That took $((SECONDS/3600)) hours $((SECONDS%3600/60)) minutes $((SECONDS%60)) seconds.\\n" # See the terminate() function, where this script exits. exit "$ErrorCount"
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 31284 | Perforce maintenance |
Added initial files. Nothing working yet; this is just the start of development. Files included: * rename_edge_serverid.sh - Script to rename an edge ServerID. * convert_edge_to_commit.sh - Script to convert a filtered edge into a commit. * cli_test.cfg - Test Suite (using SDP run_cli_tests.sh script). * r - Test suite wrapper. * .p4ignore - Just a typical P4IGNORE file. |