#!/usr/local/bin/python """A Python version of the Perforce "p4" client. This uses the Python type P4Client, which is a wrapper for the Perforce ClientApi object. It includes the "ClientUser" class, which is a Python version of the default ClientUser from Perforce. Portions Copyright 1999, Mike Meyer. All rights reserved. Portions Copyright 2004-2005, Robert Cowham. All rights reserved. License: See accompanying LICENSE.txt including for redistribution permission. """ import sys, os, string import P4Client class P4ClientHandler: """Class to wrap P4Client.""" p4attributes = ["cwd", "charset", "port", "client", "user", "password", "host", "language", "os"] connected = 0 exception_level = 1 # raise exceptions tagged = 0 parse_forms = 0 def __init__(self, **options): "Create the P4Client object I'm wrapping." self.p4c = P4Client.P4Client(self) self._reset() def __getattr__(self, name): "Handles requests for attributes." if name in self.p4attributes: return getattr(self.p4c, name) elif name.startswith('fetch_'): self.__dict__["_fetch"] = name[len('fetch_'):] return self.run elif name.startswith('save_'): self.__dict__["_save"] = name[len('save_'):] return self.run elif name.startswith('delete_'): self.__dict__["_delete"] = name[len('delete_'):] return self.run elif name.startswith('run_'): self.__dict__["_run"] = name[len('run_'):] return self.run elif not self.__dict__.has_key(name): raise AttributeError else: return self.__dict__[name] def __setattr__(self, name, value): if name in self.p4attributes: setattr(self.p4c, name, value) else: self.__dict__[name] = value def connect(self): "Connect to the P4Client." self.connected = 1 return self.p4c.Init() def dropped(self): "Check to see if the P4Client connection has been dropped." return self.p4c.Dropped() def disconnect(self): "Close the connection to the P4Client." self.connected = 0 return self.p4c.Final() def _reset(self): self.output = [] self.warnings = [] self.errors = [] def tagged(self): "Set tag protocol" self.tagged = 1 self.p4c.SetProtocol("tag", "") def parse_forms(self): "Set appropriat protocol" self.tagged() self.parse_forms = 1 self.p4c.SetProtocol("specstring", "") def _flatten(self, args): "Flatten potentiall recursive tuples/lists into one list." result = [] if len(args): if isinstance(args[0], tuple) or isinstance(args[0], list): for i in range(len(args)): result.extend(self._flatten(args[i])) else: result.extend(args) return result def run(self, *args): "Run the given command, parsing output with the named parser." if not self.connected: msg = "Can't run a command without running connect() first" self.errors.append(msg) if self.exception_level > 0: raise msg return [] self._reset() # Check if we have been called via special fetch_/save_ methods pop_output = False cmd_args = self._flatten(args) if self.__dict__.has_key("_fetch"): pop_output = True cmd = self.__dict__["_fetch"] del self.__dict__["_fetch"] cmd_args.insert(0, "-o") elif self.__dict__.has_key("_save"): cmd = self.__dict__["_save"] del self.__dict__["_save"] self.__dict__["input"] = cmd_args.pop() cmd_args.insert(0, "-i") elif self.__dict__.has_key("_delete"): pop_output = True cmd = self.__dict__["_delete"] del self.__dict__["_delete"] cmd_args.insert(0, "-d") elif self.__dict__.has_key("_run"): cmd = self.__dict__["_run"] del self.__dict__["_run"] else: cmd = cmd_args.pop(0) self.p4c.SetArgv(cmd_args) self.p4c.Run(cmd) if len(self.errors) > 0 and self.exception_level > 0: raise "Errors during command execution" if len(self.warnings) > 0 and self.exception_level > 1: raise "Warnings during command execution" if pop_output: return self.output[0] else: return self.output def InputData(self): "Return any input that the user has provided to API." if not self.__dict__.has_key("input"): # Save error for later use self.errors.append("No input provided and API wanted it") return None return self.input def Prompt(self, msg): "Return any input that the user has provided to API." # Used for passwords etc. if not self.__dict__.has_key("input"): # Save error for later use self.errors.append("No input provided and API wanted it") return None return self.input def OutputInfo(self, data, level): "Parse the given data, adding it to self data." for line in string.split(data, '\n'): self.output.append(line) def OutputText(self, text): "Adds text lines to the output data." for line in string.split(text, '\n'): self.output.append(line) def StartDict(self): "Create new dictionary into which items will be put" self._dict = {} def _array_insert(self, arr, index, val): "Recursively insert into array." if len(index) == 1: while len(arr) < index[0]: arr.append(None) arr.append(val) else: while len(arr) < index[0]: arr.append(None) if len(arr) == index[0]: arr.append([]) self._array_insert(arr[index[0]], index[1:], val) def InsertItem(self, base, index, val): "Handle outputting of items into an array" if len(index): if not self._dict.has_key(base): self._dict[base] = [] arr = self._dict[base] ## print base, index, val indices = map(int, string.split(index, ',')) self._array_insert(arr, indices, val) else: if self._dict.has_key(base): key = base + "s" else: key = base self._dict[key] = val def EndDict(self): "Save dictionary away" self.output.append(self._dict) def OutputStat(self, dict): "Process dictionary of file status info" text = "otherOpen" test = len(text) for key, value in dict.items(): if len(key) > test and key[:test] == text: self.OutputInfo("%s %s" % (key, value), '2') else: self.OutputInfo("%s %s" % (key, value), '1') def HandleError(self, text, severity = None): "Raise an error from P4." # raise P4Client.error(text) if severity in [P4Client.ERROR_EMPTY, P4Client.ERROR_INFO]: self.output.append(text) elif severity == P4Client.ERROR_WARN: self.warnings.append(text) else: self.errors.append(text) class P4: """Class to provide nice interface to P4.""" our_attributes = ["p4client"] # Direct attributes as opposed to ones from client def __init__(self): self.p4client = P4ClientHandler() def connect(self): return self.p4client.connect() def disconnect(self): return self.p4client.disconnect() def tagged(self): "Set protocol" self.p4client.tagged() def parse_forms(self): "Set protocol" self.p4client.parse_forms() def __getattr__(self, name): if not name in self.our_attributes: return getattr(self.p4client, name) else: return self.__dict__[name] def __setattr__(self, name, value): "Allow user to set things like 'port' etc." if not name in self.our_attributes: setattr(self.p4client, name, value) else: self.__dict__[name] = value def run(self, *args): return self.p4client.run(args) if __name__ == "__main__": p4 = P4() p4.connect() try: ret = p4.run(sys.argv[1:]) for line in ret: if isinstance(line, dict): print "-----" for k in line.keys(): print k, "=", line[k] else: print line except: for e in p4.errors: print e