369 lines
11 KiB
Ruby
Executable File
369 lines
11 KiB
Ruby
Executable File
#
|
|
# P4 Utility Class around the RSG.SourceControl.Perforce
|
|
#
|
|
# Author:: Mark Harrison-Ball <Mark.Harrison-Ball@rockstargames.com>
|
|
# Date:: 20 May 2013 (AP3)
|
|
# Purpose:
|
|
# Used to generate a html report
|
|
# contains a list of functions to generate tablles and shit and return shit back
|
|
#
|
|
#
|
|
#
|
|
#
|
|
=begin
|
|
p4 fstat -T headRev //depot/gta5/assets/cuts/Armenian_2_MCS_6/data.cutxml
|
|
... headRev
|
|
|
|
|
|
=end
|
|
|
|
|
|
require 'RSG.SourceControl.Perforce'
|
|
require 'RSG.Base.Configuration.dll'
|
|
require 'RSG.Base.dll'
|
|
|
|
include RSG::SourceControl::Perforce
|
|
include RSG::Base::Configuration
|
|
|
|
RSG_CHANGELIST = RSG::SourceControl::Perforce::Changelist
|
|
|
|
|
|
class P4fileinfo
|
|
attr_reader :user
|
|
attr_writer :user
|
|
attr_reader :fullname
|
|
attr_writer :fullname
|
|
attr_reader :time
|
|
attr_writer :time
|
|
attr_reader :filename
|
|
attr_writer :filename
|
|
attr_reader :revision
|
|
attr_writer :revision
|
|
attr_reader :email
|
|
attr_writer :email
|
|
attr_reader :changelist
|
|
attr_writer :changelist
|
|
|
|
def initialize(change = nil)
|
|
@user = ''
|
|
@time = '01-01-01'
|
|
@filename = ''
|
|
@revision = ''
|
|
@email = ''
|
|
@changelist = 0
|
|
if change.class == RSG_CHANGELIST then
|
|
_setHeaderInfo(change)
|
|
end
|
|
end
|
|
|
|
private
|
|
# Basic Header Info
|
|
def _setHeaderInfo(change)
|
|
@user = change.username
|
|
@time = change.time
|
|
@changelist = change.number
|
|
end
|
|
|
|
end
|
|
|
|
|
|
#
|
|
# Generic list of utils to wrap around the p4 c# dll
|
|
#
|
|
#
|
|
#
|
|
class P4Utils
|
|
def initialize(log)
|
|
# Perforce initialisation.
|
|
g_Config = RSG::Base::Configuration::ConfigFactory::CreateConfig( )
|
|
#branch = g_Config.Project.DefaultBranch
|
|
@p4 = g_Config.Project.SCMConnect(log)
|
|
@g_log = log
|
|
end
|
|
|
|
public
|
|
# Find FileName/wildcard extension in single Change record
|
|
#---------------------------------------------------------
|
|
def findFilesinChange( change, file = nil )
|
|
fileList = []
|
|
change.files.each do | filename |
|
|
file_name = File.basename(filename).downcase
|
|
|
|
# Match every file
|
|
if file == "*" or file == nil then
|
|
fileList.push(filename)
|
|
# Match the extension
|
|
elsif File.extname(file_name) == File.extname(file) then
|
|
fileList.push(filename)
|
|
# explicit match Test
|
|
elsif file_name == file.downcase then
|
|
fileList.push(filename)
|
|
end
|
|
end
|
|
fileList
|
|
end
|
|
|
|
|
|
|
|
# Return Changelist objects from a set of Change records.
|
|
#---------------------------------------------------------
|
|
def get_changelists_from_changes( change_records )
|
|
changelists = []
|
|
change_records.each do |change_record|
|
|
changelist = Changelist::Create( @p4, change_record['change'].to_i )
|
|
changelists << changelist[0]
|
|
end
|
|
changelists
|
|
end
|
|
|
|
# return record of list of files in a pending changelist number
|
|
def get_changelistDescribe( currentCL )
|
|
change_records = @p4.Run( 'describe' , false, currentCL.to_s)
|
|
end
|
|
|
|
# return record of list of files in a pending changelist number
|
|
def get_changelistOpened( currentCL )
|
|
change_records = @p4.Run( 'opened' , false, '-c', currentCL.to_s)
|
|
end
|
|
|
|
# Returns currnet worksapce/users Pending chnagelists
|
|
def get_PendingChangeLists(max = 2)
|
|
change_records = @p4.Run( 'changes', true, '-c', @p4.Client, '-u', @p4.User, '-s', 'pending', '-m' ,max.to_s)
|
|
changes = get_changelists_from_changes( change_records )
|
|
end
|
|
|
|
# Returns a list of changes that needs to be sync to on the local workspace
|
|
def get_changes_toSync( depotpath = '//...', lastCL = nil)
|
|
change_records = @p4.Run( 'cstat', true, depotpath)
|
|
change_need_records = []
|
|
change_records.each do | change |
|
|
if lastCL == nil then
|
|
if not change['status'].include?('have')
|
|
change_need_records << change
|
|
end
|
|
else
|
|
if change['change'] > lastCL then
|
|
change_need_records << change
|
|
end
|
|
end
|
|
|
|
end
|
|
changes = get_changelists_from_changes( change_need_records )
|
|
|
|
end
|
|
|
|
# return a CHnage from a passed in Changelist number/string
|
|
def get_Change_from_CL( cl )
|
|
change_records = get_changelistDescribe( cl )
|
|
changes = get_changelists_from_changes( change_records )
|
|
changes[0]
|
|
end
|
|
|
|
# Return the last submitted changelist number in perforce
|
|
# Add check for p4 server disconnected
|
|
# NOTE: Can use p4 counter Change
|
|
#--------------------------------------------------------
|
|
def get_current_changelistnumber(depotpath = '//...')
|
|
change_records = @p4.Run( 'changes', true, '-m', 1.to_s, '-s', 'submitted', depotpath )
|
|
changes = get_changelists_from_changes( change_records )
|
|
changes[0].Number
|
|
end
|
|
|
|
# Returns the clients last sync'd changelist
|
|
#
|
|
#--------------------------------------------------------------------------------
|
|
def get_current_clientchangelist(depotpath = '//...')
|
|
change_records = @p4.Run( 'changes', true, '-m', '1', depotpath+'@'+@p4.Client )
|
|
changes = get_changelists_from_changes( change_records )
|
|
changes[0]
|
|
end
|
|
|
|
# Return list of changes from last changlist
|
|
#---------------------------------------------------------------------------------
|
|
def parse_p4_review(depotpath, currentCL, head = '#head')
|
|
if @g_log then
|
|
@g_log.message( "Scanning for changes since last Changelist = #{currentCL}.....")
|
|
end
|
|
|
|
g_Status = 'submitted'
|
|
|
|
change_records = @p4.Run( 'changes', true, '-s', g_Status, depotpath+'@'+currentCL.to_s+','+head.to_s )
|
|
changes = get_changelists_from_changes( change_records )
|
|
changes.each do |change|
|
|
|
|
#@g_log.message( "Changelist: #{change.Number} by #{change.Username}" )
|
|
if change.Number > currentCL
|
|
currentCL = (change.Number+1)
|
|
if @g_log then
|
|
@g_log.message( "Last Changelist = #{currentCL}")
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
return currentCL, changes
|
|
end
|
|
|
|
|
|
# Return Information about file in perforce
|
|
# Single INfo retrevval
|
|
# Need to parse in filters, i'e. 'depotFile, fileSize'
|
|
# FIELDS:
|
|
# attr-<name> -- attribute value for <name>
|
|
#attrProp-<name> -- set if attribute <name> is propagating
|
|
#clientFile -- local path (host or Perforce syntax)
|
|
#depotFile -- name in depot
|
|
#movedFile -- name in depot of moved to/from file
|
|
#path -- local path (host syntax)
|
|
#isMapped -- set if file is mapped in the client
|
|
#shelved -- set if file is shelved
|
|
#headAction -- action at head rev, if in depot
|
|
#headChange -- head rev changelist#, if in depot
|
|
#headRev -- head rev #, if in depot
|
|
#headType -- head rev type, if in depot
|
|
#headCharset -- head charset, for unicode type
|
|
#headTime -- head rev changelist time, if in depot
|
|
#headModTime -- head rev mod time, if in depot
|
|
#movedRev -- head rev # of moved file
|
|
#haveRev -- rev had on client, if on client
|
|
#desc -- change description (if -e specified)
|
|
#digest -- MD5 digest (fingerprint)
|
|
#fileSize -- file size
|
|
#action -- open action, if opened
|
|
#type -- open type, if opened
|
|
#charset -- open charset, for unicode type
|
|
#actionOwner -- user who opened file, if opened
|
|
#change -- open changelist#, if opened
|
|
#resolved -- resolved integration records
|
|
#unresolved -- unresolved integration records
|
|
#reresolvable -- reresolvable integration records
|
|
#otherOpen -- set if someone else has it open
|
|
#otherOpen# -- list of user@client with file opened
|
|
#otherLock -- set if someone else has it locked
|
|
#otherLock# -- user@client with file locked
|
|
#otherAction# -- open action, if opened by someone else
|
|
#otherChange# -- changelist, if opened by someone else
|
|
#openattr-<name> -- attribute value for <name>
|
|
#openattrProp-<name> -- set if attribute <name> is propagating
|
|
#ourLock -- set if this user/client has it locked
|
|
#resolveAction# -- pending integration record action
|
|
#resolveBaseFile# -- pending integration base file
|
|
#resolveBaseRev# -- pending integration base rev
|
|
#resolveFromFile# -- pending integration from file
|
|
#resolveStartFromRev# -- pending integration from start rev
|
|
#resolveEndFromRev# -- pending integration from end rev
|
|
#totalFileCount -- total no. of files, if sorted
|
|
#---------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
def get_file_info(depotpath, filter='depotFile')
|
|
file_records = @p4.Run( 'fstat', false, '-T',filter, depotpath)
|
|
record_info = nil
|
|
if file_records.count == 1 then
|
|
# return our first record
|
|
record_info = file_records[0]
|
|
end
|
|
record_info
|
|
end
|
|
|
|
# RSG LIBS Source Control does not support user detail info so need to use standard p4 parsing
|
|
def get_user_info( fileinfo )
|
|
if fileinfo.user != '' then
|
|
file_records = @p4.Run( 'user', false, '-o',fileinfo.user)
|
|
file_records.each do |record|
|
|
fileinfo.email = record.fields['Email']
|
|
fileinfo.fullname = record.fields['FullName']
|
|
end
|
|
end
|
|
fileinfo
|
|
|
|
end
|
|
|
|
|
|
|
|
# ===== To Depreciate Function =======
|
|
# Get user Email
|
|
def get_user_email( user )
|
|
email = nil
|
|
file_records = @p4.Run( 'user', false, '-o',user)
|
|
file_records.each do |record|
|
|
email = record.fields['Email']
|
|
end
|
|
email
|
|
end
|
|
|
|
def Client()
|
|
return @p4.Client
|
|
end
|
|
|
|
def User()
|
|
return @p4.User
|
|
end
|
|
|
|
# Retunrs the number of seconds a user has before their login expires
|
|
def expires()
|
|
seconds = nil
|
|
file_records = @p4.Run( 'login', false, '-s')
|
|
file_records.each do |record|
|
|
seconds = record.fields['TicketExpiration']
|
|
end
|
|
seconds.to_i
|
|
end
|
|
|
|
# Connects to p4 with user Password, this will rest the ticket
|
|
def login(password)
|
|
@p4.Login(password)
|
|
end
|
|
|
|
|
|
# Return a pending changelist, pass in a description
|
|
def CreatePendingChangelist( desc )
|
|
@p4.create_pending_changelist( desc )
|
|
end
|
|
|
|
def DeleteChangelist(object)
|
|
@p4.Run( 'change' ,false, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
# Simple Sync Method, we allow arrasy so can batch up commands into one call
|
|
def sync(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'sync', true, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def integ(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'integ', false, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def copy(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'copy', false, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def resolve(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'resolve', false, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def revert(object)
|
|
@p4.Run( 'revert', true, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def submit(object)
|
|
@p4.Run( 'submit', true, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def describe(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'describe', true, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
def files(object, args='')
|
|
object.unshift(args)
|
|
@p4.Run( 'files', true, System::Array[System::String].new(object) )
|
|
end
|
|
|
|
|
|
end |