#!/bin/bash #============================================================================== # 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 #------------------------------------------------------------------------------ #============================================================================== # Declarations and Environment export P4U_HOME=${P4U_HOME:-/p4/common/bin} export P4U_LIB=${P4U_LIB:-/p4/common/lib} export P4U_ENV=$P4U_LIB/p4u_env.sh export P4U_LOG=Unset export VERBOSITY=${VERBOSITY:-3} # Environment isolation. For stability and security reasons, prepend # PATH to include dirs where known-good scripts exist. # known/tested PATH and, by implication, executables on the PATH. export PATH=$P4U_HOME:$PATH:~/bin:. [[ -r "$P4U_ENV" ]] || { echo -e "\nError: Cannot load environment from: $P4U_ENV\n\n" exit 1 } declare BASH_LIBS=$P4U_ENV BASH_LIBS+=" $P4U_LIB/libcore.sh" BASH_LIBS+=" $P4U_LIB/libp4u.sh" for bash_lib in $BASH_LIBS; do source $bash_lib ||\ { echo -e "\nFATAL: Failed to load bash lib [$bash_lib]. Aborting.\n"; exit 1; } done declare Version=1.0.4 declare -i SilentMode=0 export VERBOSITY=3 #============================================================================== # Local Functions # Function: find_evil_twins function find_evil_twins () { declare p1=${1:-Unset} declare p2=${2:-Unset} declare s2= declare -i count [[ $p1 == Unset || $p2 == Unset ]] && bail "find_evil_twins(): BAD USAGE." s2=${p2%/...} vmsg "Switching workspace to stream $s2" p4 client -f -s -S "$s2" msg "Searching for evil twins between [$p1] and [$p2]:" vmsg "Executing: p4 integ -Ro -n $p1 $p2" p4 -s integ -Ro -n "$p1" "$p2" | grep "without -i flag" > $TmpFile 2>&1 || return 1 count=0 if [[ -s "$TmpFile" ]]; then count=$(wc -l $TmpFile | cut -d ' ' -f 1) msg "Found $count evil twins here:" cat $TmpFile EvilTwinCount=$((EvilTwinCount+count)) fi return 0 } #------------------------------------------------------------------------------ # Function: terminate function terminate { # Disable signal trapping. trap - EXIT SIGINT SIGTERM # Don't litter. cleanTrash vvmsg "$THISSCRIPT: EXITCODE: $OverallReturnStatus" # Stop logging. [[ "${P4U_LOG}" == off ]] || stoplog # With the trap removed, exit. exit $OverallReturnStatus } #------------------------------------------------------------------------------ # Function: usage (required function) # # Input: # $1 - style, either -h (for short form) or -man (for man-page like format). #------------------------------------------------------------------------------ function usage { declare style=${1:--h} echo "USAGE for $THISSCRIPT v$Version: $THISSCRIPT -d <stream_depot> [-s //source/stream] [-t //target/stream] [-i <instance>] [-L <log>] [-si] [-v<n>] [-n] [-D] or $THISSCRIPT [-h|-man|-V] " if [[ $style == -man ]]; then echo -e " DESCRIPTION: Detect \"evil twins\" in a given stream depot. OPTIONS: -d <stream_sdepot> Specify a stream depot to process, e.g. -d fgs to process the //fgs stream depot. This argument is required. -s //source/stream Specify a particular source stream to search. By default, all non-virtual streams are checked. Be aware that if neither -s nor -t are given, a very large numbers of streams may be checked, as all possible combinations of source and target stream are checked. -t //target/stream Specify a particular target stream to search. By default, all non-virtual streams are checked. Be aware that if neither -s nor -t are given, a very large numbers of streams may be checked, as all possible combinations of source and target stream are checked. -i <instance> Specify the SDP instance name. This is required unless the SDP environment has previously been loaded in the current shell, i.e. by sourcing the SDP p4_vars file and specifying the instance. -v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest). -L <log> Specify the path to a log file, or the special value 'off' to disable logging. All output (stdout and stderr) are captured in the log. NOTE: This script is self-logging. That is, output displayed on the screen is simultaneously captured in the log file. Do not run this script with redirection operators like '> log' or '2>&1', and do not use 'tee.' -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'. -n No-Op. Prints commands instead of running them. -D Set extreme debugging verbosity. HELP OPTIONS: -h Display short help message -man Display man-style help message -V Dispay version info for this script and its libraries. EXAMPLES: Search for evil twins between streams //fgs/DevA and //fgs/DevB. $THISSCRIPT -s //fgs/DevA -t //fgs/DevB Search for all possible evil twins in the //fgs stream depot: $THISSCRIPT -d fgs " fi exit 1 } #============================================================================== # Command Line Processing declare StreamListFile=/tmp/tmp.StreamList.$$.$RANDOM declare SearchedPathsFile=/tmp/tmp.SearchedPaths.$$.$RANDOM declare TmpFile=/tmp/tmp.EvilTwins.$$.$RANDOM declare StreamDepot=Unset declare SourceStream=Unset declare SourcePath= declare TargetStream=Unset declare TargetPath= declare DepotTypeCheck=Unset declare -i PathwayCount=0 declare -i EvilTwinCount=0 GARBAGE+=" $StreamListFile $SearchedPathsFile $TmpFile" declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-s) SourceStream=$2; shiftArgs=1;; (-t) TargetStream=$2; shiftArgs=1;; (-d) StreamDepot=$2; shiftArgs=1;; (-h) usage -h;; (-man) usage -man;; (-V) show_versions; exit 1;; (-v1) export VERBOSITY=1;; (-v2) export VERBOSITY=2;; (-v3) export VERBOSITY=3;; (-v4) export VERBOSITY=4;; (-v5) export VERBOSITY=5;; (-i) export SDP_INSTANCE=$2; shiftArgs=1;; (-L) export P4U_LOG=$2; shiftArgs=1;; (-si) SilentMode=1;; (-n) export NO_OP=1;; (-D) set -x;; # Debug; use 'set -x' mode. (*) usageError "Unknown arg ($1).";; esac # Shift (modify $#) the appropriate number of times. shift; while [[ $shiftArgs -gt 0 ]]; do [[ $# -eq 0 ]] && usageError "Bad usage." shiftArgs=$shiftArgs-1 shift done done set -u #============================================================================== # Command Line Verification [[ $SilentMode -eq 1 && $P4U_LOG == off ]] && \ usageError "Cannot use '-si' with '-L off'." if [[ "$SourceStream" != Unset ]]; then [[ "$SourceStream" != "//"* ]] && \ usageError "The source stream specified with '-s' must be of the form //depot/stream." # Determine stream depot from source stream if it wasn't provided with '-d'. if [[ $StreamDepot == Unset ]]; then StreamDepot=${SourceStream#//} StreamDepot=${StreamDepot%%/*} fi fi if [[ "$TargetStream" != Unset ]]; then [[ "$TargetStream" != "//"* ]] && \ usageError "The target stream specified with '-t' must be of the form //depot/stream." # Determine stream depot from target stream if it wasn't provided with '-d'. if [[ $StreamDepot == Unset ]]; then StreamDepot=${TargetStream#//} StreamDepot=${StreamDepot%%/*} fi fi [[ $StreamDepot == Unset ]] && \ usageError "The '-d <stream_depot>' paramter is required." export SDP_INSTANCE=${SDP_INSTANCE:-Unset} [[ $SDP_INSTANCE == Unset ]] && \ usageError "The SDP environment must be loaded, or the '-i <instance>' parameter provided." # Load and then tweak SDP environment. source p4_vars "$SDP_INSTANCE" export P4ENVIRO=/dev/null/.p4enviro unset P4CONFIG [[ $P4U_LOG == Unset ]] && \ export P4U_LOG="${LOGS}/${THISSCRIPT%.sh}.$(date +'%Y%m%d-%H%M').log" #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM declare -i OverallReturnStatus=0 if [[ "${P4U_LOG}" != off ]]; then touch ${P4U_LOG} || bail "Couldn't touch log file [${P4U_LOG}]." # Redirect stdout and stderr to a log file. if [[ $SilentMode -eq 0 ]]; then exec > >(tee ${P4U_LOG}) exec 2>&1 else exec >${P4U_LOG} exec 2>&1 fi initlog fi msg "$THISSCRIPT v$Version started at $(date)." # If depot was specified as '//x', normalize to 'x'. [[ "$StreamDepot" == "//"* ]] && StreamDepot=${StreamDepot#//} DepotTypeCheck=$(p4 -ztag -F %Type% depot -o $StreamDepot 2>/dev/null) if [[ -n "$DepotTypeCheck" ]]; then [[ "$DepotTypeCheck" != "stream" ]] && \ bail "The depot specified by '-d' must be of type 'stream', not $DepotTypeCheck." else bail "Could not determine depot type for depot $StreamDepot. Aborting." fi msg "Getting list of streams in //$StreamDepot." p4 -ztag -F "%Type%:%Stream%" streams "//$StreamDepot/*" > $StreamListFile export P4CLIENT=tmp.auto.$P4USER.${THISSCRIPT%.sh} echo -e "Client: $P4CLIENT\n\nOwner: $P4USER\n\nDescription:\n\tUsed by $THISSCRIPT\n\nRoot: $P4TMP/${THISSCRIPT%.sh}\n\nView:\n\t//spec/... //$P4CLIENT/spec/..." > $TmpFile msg "Using generated temporary workspace $P4CLIENT." p4 -s client -i < $TmpFile || bail "Failed to create temp client using this spec:\n$(cat $TmpFile)\n" if [[ $SourceStream == Unset && $TargetStream == Unset ]]; then touch $SearchedPathsFile || bail "Could not touch temp file $SearchedPathsFile." while read SourceStream; do [[ $SourceStream == "virtual:"* ]] && continue SourceStream=${SourceStream##*:} SourcePath="$SourceStream/..." while read TargetStream; do [[ "$TargetStream" == "virtual:"* ]] && continue TargetStream=${TargetStream##*:} [[ "$SourceStream" == "$TargetStream" ]] && continue TargetPath="$TargetStream/..." # Direction doesn't matter for evil twin detection, so we only need to search # in a single direction. Avoid redundant checking by checknig the # "searched paths" temp file, which contains a list of already searched paths. grep "${SourceStream#//}:${TargetStream#//}\$" $SearchedPathsFile > /dev/null 2>&1 [[ $? -eq 0 ]] && continue grep "${TargetStream#//}:${SourceStream#//}\$" $SearchedPathsFile > /dev/null 2>&1 [[ $? -eq 0 ]] && continue find_evil_twins "$SourcePath" "$TargetPath" ||\ OverallReturnStatus=1 PathwayCount=$((PathwayCount+1)) echo "${SourceStream#//}:${TargetStream#//}" >> $SearchedPathsFile done < $StreamListFile done < $StreamListFile elif [[ $SourceStream != Unset && $TargetStream != Unset ]]; then SourcePath="$SourceStream/..." TargetPath="$TargetStream/..." find_evil_twins "$SourcePath" "$TargetPath" ||\ OverallReturnStatus=1 PathwayCount=1 else bail "Specify only '-s' or '-t', but not both, is not (yet?) supported." fi if [[ $OverallReturnStatus -eq 0 ]]; then msg "${H}\nAll processing completed successfully.\n" else msg "${H}\nProcessing completed, but with errors. Scan above output carefully.\n" fi # Illustrate using $SECONDS to display runtime of a script. msg "Found $EvilTwinCount evil twins searching $PathwayCount pathway(s) in $(($SECONDS/3600)) hours $(($SECONDS%3600/60)) minutes $(($SECONDS%60)) seconds.\n" # See the terminate() function, which is really where this script exits. exit $OverallReturnStatus
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 24675 | Russell C. Jackson (Rusty) |
Fixed bugs in sdputils.py and scripts using it. Converted to standard 2 space spacing, removed copyright stuff. |
||
#1 | 22693 | Russell C. Jackson (Rusty) |
Branched a Unix only version of the SDP. Removed extra items to create a cleaner tree. Moved a few items around to make more sense without Windows in the mix. |
||
//guest/perforce_software/sdp/dev/Maintenance/EvilTwinDetector.sh | |||||
#1 | 20062 | C. Thomas Tyler | Added Evil Twin Detector maintenance script. |