# # p4wrap # Python wrapper and utility routines for interacting # with Perforce. # # Copyright (c) 2000 by Thomas Quinot # # $Id: //guest/thomas_quinot/perforce/utils/genreview/p4wrap.py#2 $ # import string, re, rfc822 # Translate a file specification into a compiled regexp. def fs2re (fs): tab = re.split ("(\*|\.\.\.)", fs) tab2 = [] for i in tab: if i == '*': tab2.append ('[^/]*') elif i == '...': tab2.append ('.*') else: tab2.append (re.escape (i)) regexp = "^" + string.join (tab2, "") + "$" return re.compile (regexp) # Parse the output of 'p4 describe' into a dictionnary with the # following entries: # 'change': the changelist number # 'user': the Perforce user name # 'client': the client workspace name # 'date': the changelist timestamp as 'yyyy/mm/dd hh:mm:ss' # 'msg': the check-in message (a list of strings) # 'files': the affected files as list of triples of the form # (depot file spec, revision, action) def parse_p4_describe (lines): desc = {} msg = [] files = [] state = 'init' for l in lines: if state == 'init': m = re.match \ ('^Change ([0-9]+) by (\S+)@(\S+) on ([0-9/]+ [0-9:]+)$', l) if m: desc['change'], desc['user'], \ desc['client'], desc['date'] = \ m.groups () continue if re.match ('^Affected files', l): state = 'files' continue msg.append (l[1:-1]) else: # state = 'files' m = re.match ('^\.\.\. ([^#]+)#(\d+) (\w+)$', l) if m: files.append (m.groups ()) continue if re.match ('^Differences', l): break while len (msg) > 0: if msg[0] == '': msg = msg[1:] continue if msg[-1] == '': msg = msg[:-1] continue break desc['files'] = files desc['msg'] = msg return desc # Parse the output of 'p4 review' into an rfc822.AddressList. # If ignore_author is a user name, then that user will not be # added to the list. def parse_p4_review(lines,ignore_author=None): reviewers = rfc822.AddressList ("") for line in lines: (user, email) = re.match( r'^(\S+) (<\S+> \(.+\))$', line).groups() if user != ignore_author: reviewers = reviewers + \ rfc822.AddressList (email) return reviewers # Parse the output of "p4 job -o JOB" def parse_p4_job (lines): state = '' job = { 'job': '', 'status': '', 'user': '', 'date': '', 'description': '' } for l in lines: if l[0] == '#': continue if l[0] == '\t': job[state] = job[state] + l[1:] continue if l[0] == '\n': continue for k in job.keys (): m = re.match ("(?i)^(" + k + "):\t?(.*)$", l) if m: state = string.lower (m.group (1)) if m.group (2): job[state] = m.group (2) break return job # Parse the output of "p4 integrate" into a list of # (toSpec, toRev, fromSpec, fromRev, action) tuples def parse_p4_integrate (lines): res = [] for l in lines: m = re.match \ ("^([^#]+)(#[0-9#,]+) - (\S+) from ([^#]+)(#[0-9#,]+)$", l) if not m: print l res.append (m.group (1), m.group (2), m.group (4), m.group (5), m.group (3)) return res # Substitute Perforce keywords in a string, according # to a change or job description. def sub_keywords (s, desc): keywords = { '%user%': "desc['user']", '%change%': "desc['change']", '%changelist%': "desc['change']", '%client%': "desc['client']", '%date%': "desc['date']", '%summary%': "string.join (desc['msg'], '')[:32]" } for k in keywords.keys(): while 1: m = re.search ('(' + k + ')', s) if not m: break s = s[0:m.start(1)] \ + eval (keywords[k]) \ + s[m.end(1):] return s