#!/bin/bash #------------------------------------------------------------------------------ set -u # Track 'p4 move' operations over a range of changelists, by detecing them # and adding move operations to a branch spec, thus enabling merges using the # branch spec to properly track moves/renames, e.g. with: # # p4 merge -n -b r1_to_r2 # # This script can be called via change-commit trigger to track moves for a # single changle changelist, or called in 'auto' mode, in which case it tracks # all changes starting from the last time changes were tracked. A 'p4 key' # tracks the last time moves were tracked for the branch spec. # The first entry in the View: field of the branch spec is the actual path; # all subseuqent entries track moves/renames. # Limitation: This works only for Stream depots with StreamDepth=1 (the # default) or Classic Depots with a fixed 2-level directory structure of # //<Depot>/<StreamRoot> #------------------------------------------------------------------------------ # Function: track_moves_in_change() #------------------------------------------------------------------------------ # Input: $1 - Changelist. # Uses globals $BranchSpec, $BranchSpecFile, $SourceStream, $TargetStream, # and $StartingChangeKey. function track_moves_in_change() { dbg "CALL track_moves_in_change($*)" declare change=${1:-} declare file= declare action= declare -i i=0 declare -i moveCount=0 [[ -z "$change" ]] && return 1 file=$(p4 -ztag -F %depotFile${i}% describe -s $change) while [[ -n "$file" ]]; do action=$(p4 -ztag -F %action${i}% describe -s $change) if [[ $action == "move/add" ]]; then fromFile=$(p4 -ztag -F %file0,0% filelog -m1 ${file}@$change,@$change) # Trim leading stream root path, e.g. //stream/main or //stream/r2, so # we can apply the stream roots from our branch spec instead. Apply # the stream root $SourceStream to $fromFile and $TargetStream to $file. fromFileRelPath=${fromFile#//} fromFileRelPath=${fromFileRelPath#*/} fromFileRelPath=${fromFileRelPath#*/} fromFileDepotPath="$SourceStream/$fromFileRelPath" fileRelPath=${file#//} fileRelPath=${fileRelPath#*/} fileRelPath=${fileRelPath#*/} fileDepotPath="$TargetStream/$fileRelPath" echo -e "\t\"$fromFileDepotPath\" \"$fileDepotPath\"" >> $BranchSpecFile moveCount=$((moveCount+1)) fi i=$((i+1)) file=$(p4 -ztag -F %depotFile${i}% describe -s $change) done dbg "Found $moveCount renames among $i file actions in change $change." dbg "Updated Branch Spec:\n$(grep -v '^#' $BranchSpecFile)\nEND_FILE\n" dbg "Updating key $StartingChangeKey to changelist $change." ### Silence output here later. p4 branch -i < $BranchSpecFile p4 key $StartingChangeKey $change } #------------------------------------------------------------------------------ # Micro functions. function msg () { echo -e "${1:-Hi}"; } function dbg () { [[ $MT_DEBUG -eq 1 ]] || return 0; msg "${1:-Hi}"; } function bail () { msg "Error: ${1:-Unknown Error}"; exit ${2:-1}; } function cmd () { msg "${2:-Executing command: $1}"; $1; return $?; } function usage () { msg "Usage:\n\tMoveTracker.sh <branch_spec> auto|<changelist>\n"; exit 1; } declare Version=1.0.1 declare -i MT_DEBUG=${MT_DEBUG:-0} declare BranchSpec=${1:-Unset} declare Changelist=${2:-Unset} declare ChangesToProcess= declare BranchSpecFile=/tmp/tmp.bspec.$$.$RANDOM declare StartingChangeKey= declare StartingChange= declare EndingChange= declare TargetPath= declare SourceStream= declare TargetStream= declare -i Updated=0 [[ $Changelist == Unset || $BranchSpec == Unset ]] && usage p4 branch -o $BranchSpec > $BranchSpecFile ||\ bail "Failed to display branch spec." dbg "Branch Spec:\n$(grep -v '^#' $BranchSpecFile)\nEND_FILE\n" StartingChangeKey=MoveTracker.LastChecked.$BranchSpec # The target path is right-side of the first entry in the View: field of the # branch spec. TargetPath=$(p4 -ztag -F %View0% branch -o $BranchSpec) SourceStream=$TargetPath TargetStream=$TargetPath TargetPath=//${TargetPath##*//} SourceStream=${SourceStream%%/... //*} TargetStream=//${TargetStream##* //} TargetStream=${TargetStream%/...} dbg "TP=[$TargetPath] SS=[$SourceStream] TS=[$TargetStream]" if [[ $Changelist == auto ]]; then StartingChange=$(p4 key $StartingChangeKey) dbg "Starting change key $StartingChangeKey value is $StartingChange." EndingChange=$(p4 -ztag -F %change% changes -m 1 $TargetPath) dbg "Looking for list of changes $TargetPath between changes @$StartingChange and @$EndingChange." ChangesToProcess=$(p4 -ztag -F %change% changes $TargetPath@$StartingChange,@$EndingChange) dbg "Processing changelists: $ChangesToProcess" for c in $ChangesToProcess; do dbg "Auto Tracking moves in change $c." track_moves_in_change "$c" done elif [[ $Changelist =~ ^[1-9]+$ ]]; then dbg "Tracking moves in change $Changelist." track_moves_in_change "$Changelist" else dbg "Unrecognized changelist $Changelist." exit 1 fi # Clean up temp files. /bin/rm -f "$BranchSpecFile" exit 0
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19286 | C. Thomas Tyler |
Added Scenario 5, Move tracking via branch spec, including re-usable StreamMoveTracker.sh script. Added env.sh with convenience alias. Reran test suite to capture slight output normalization tweaks. Removed '-i' flag for toying with dm.integ.tweaks, as it has no effect on the given repro scenarios. |