# # P4 Utility Class around the RSG.SourceControl.Perforce # # Author:: Mark Harrison-Ball # 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- -- attribute value for #attrProp- -- set if attribute 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- -- attribute value for #openattrProp- -- set if attribute 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