# # File:: p4SyncToRevAfterPurge.rb # Description:: Takes any number of P4 depot paths and syncs any files without a local revision (i.e. rev 0/###) to the revision just above the last purged revision. # Useful if you have lost files locally due to a labelled revision being purged. # # Author:: John Ricchio # Date:: 09 March 2013 # #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- sUsage = 'usage: p4SyncToRevAfterPurge.rb [any number of valid P4 paths] [OPTIONAL: -noprompt]' doSync = "" #"1" means sync & "2" means no sync...set to "1" by -noprompt param sFileStatInfo = ENV['TEMP'] + '\p4SyncToRevAfterPurge_fstatInfo.txt' sCmd = 'p4 fstat -T "depotFile headRev haveRev headType" -F "headAction=edit" ' # Example sFileStatInfo format: #... depotFile //depot/gta5/build/dev/ps3/levels/gta5/_hills/country_06/cs6_02.rpf #... headType binary+S16w #... headRev 390 #... haveRev 378 # #... depotFile //depot/gta5/build/dev/ps3/levels/gta5/_hills/country_06/cs6_03.rpf #... headType binary+S16w #... headRev 456 # #----------------------------------------------------------------------------- # Functions #----------------------------------------------------------------------------- def sys(cmd) puts "\n(#{cmd})" res = system(cmd) raise "\nFATAL ERROR: (#{cmd}) did not complete successfully. EXITING." if not res end #----------------------------------------------------------------------------- # Entry #----------------------------------------------------------------------------- # get params abort "\n#{sUsage}\n" if ARGV.empty? #bail if we don't have any params aCleanParams = Array.new ARGV.each { |param| sParam = param.dup #needed in case we modify the param coming in case sParam when /-noprompt/i doSync = "1" #assume that they want to sync if they don't want a prompt next when /\/$/ sParam.gsub!(/\/$/,'/...') #assume "..." for any params that end in "/" (depot paths) when /\\$/ sParam.gsub!(/\\$/,'\...') #assume "..." for any params that end in "\" (workspace paths) end aCleanParams.push(sParam) } abort "\n#{sUsage}\n" if aCleanParams.empty? #bail if we don't have any directories to fstat puts "\nLooking in..." aCleanParams.sort!.each { |param| puts param } #find purged revisions sCmd = sCmd + aCleanParams.join(' ') + " > " + sFileStatInfo sys(sCmd) aP4Lines = IO.readlines("#{sFileStatInfo}") sFile = "" iRevLimit = iHaveRev = iHeadRev = 0 hSyncLines = Hash.new aP4Lines.each { |line| case line when /\.\.\.\sdepotFile\s([^\n]+)/ #get the depot path for the file sFile = $1 when /\.\.\.\sheadType\s[^\d]+(\d*)/ #get the revision limit iRevLimit = $1.to_i if ($1) when /\.\.\.\sheadRev\s([^\n]+)/ #get the head revision iHeadRev = $1.to_i if ($1) when /\.\.\.\shaveRev\s([^\n]+)/ #get the have revision iHaveRev = $1.to_i if ($1) when /^\s$/ #end of fstat section, setup the sync line, if necessary if (iHaveRev == 0) if (iHeadRev > 0) && (iRevLimit > 0) iLastUnpurged = (iHeadRev - iRevLimit) + 1 sSync = "p4 sync -f #{sFile}\##{iLastUnpurged}" hSyncLines[sFile] = sSync else raise "\nERROR: We don't have a local revision, but one of these is 0: Head Revision is (#{iHeadRev}) / Rev Limit is (#{iRevLimit})." end else # We already have a local revision end # reset variables for next fstat group sFile = "" iRevLimit = iHaveRev = iHeadRev = 0 end } #sync purged revisions to the version just after the purge iPurgeCnt = hSyncLines.values.count if (iPurgeCnt > 0) #check to see if they want to force sync puts "\nThe following files were found to have been deleted locally:" hSyncLines.keys.each { |key| puts key } until doSync.match /^[12]$/ #only match 1 or 2 puts "\nChoose an action:" puts "1 - Force sync to last unpurged revision" puts "2 - Exit without syncing" doSync = STDIN.gets.chomp end exit if doSync == "2" #bail if they chose to exit #sync em! hSyncLines.values.sort.each { |val| sys(val) } puts "\n(#{iPurgeCnt}) Purged file(s) synced to last unpurged revision(s).\n" else puts "\nNo purged revisions found.\n" end #clear out temp file File.delete(sFileStatInfo) if File.exist?(sFileStatInfo) # p4SyncToRevAfterPurge.rb