## ## Copyright (c) 2006 Jason Dillon ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## ## ## $Id: __init__.py 78 2009-08-25 12:21:04Z mindwanderer $ ## import os, sys, popen2, marshal from p4spam import log, config # Logger for the create() factory method _log = log.getLogger("p4spam.perforce.commands") def create(name, p4): assert name != None try: mod_name = "p4spam.perforce.commands.%s" % name _log.debug("Loading: %s" % mod_name) mod = __import__(mod_name, globals(), locals(), [ "create" ]) assert mod != None _log.debug("Loaded: %s" % mod) except ImportError: raise Exception("Unconfigured command: %s" % name) factory = getattr(mod, "create") _log.debug("Factory: %s" % factory) return factory(p4); ## ## ResultSupport ## class ResultSupport: def toString(this): raise "Abstract method" def __str__(this): return this.toString() def __repr__(this): return this.toString() ## ## CommandSupport ## class CommandSupport: def __init__(this, name, p4): this.log = log.getLogger(this) this.name = name this.p4 = p4 this.p4flags = "-G" this.pipeMode = 'b' def createCommandLine(this, args): cmdline = [] for arg in config.P4_CMDLINE: cmdline.append(str(arg)) if this.p4flags != None and len(this.p4flags.strip()) != 0: cmdline.append(this.p4flags) # Only append command name if this is not a special raw command if this.name not in ("raw", "rawstream"): cmdline.append(this.name) for arg in args: cmdline.append(str(arg)) # If this is not a posix system, then need to convert cmdline to a string if os.name != 'posix': buff = cmdline[0] # don't quote for arg in cmdline[1:]: buff = '%s "%s"' % (buff, str(arg)) cmdline = buff this.log.debug("Converted cmdline sequence into string for non-posix os: %s" % cmdline) return cmdline def processOutput(this, stream): raise "Abstract method" def execute(this, args): cmdline = this.createCommandLine(args) this.log.debug("Executing: %s" % str(cmdline)) (fromchild, tochild, childerr) = popen2.popen3(cmdline, mode=this.pipeMode ) # Try and detect early failure if anything has been written to the childs stderr # # NOTE: This is less than ideal, as the errors might not have poped out yet # #errors = childerr.readlines() #if len(errors): # for line in errors: # this.log.error(line) # # raise "Child process spat out some errors: %s" % str(errors) result = this.processOutput(fromchild) this.log.debug("Result: %s" % result) return result ## ## SingleResultCommand ## class SingleResultCommand(CommandSupport): def createResult(this, entry): raise "Abstract method" def processOutput(this, stream): entry = marshal.load(stream) assert entry != None this.log.debug("Entry: %s" % entry) return this.createResult(entry) ## ## RawResultCommand ## class RawResultCommand(SingleResultCommand): def __init__(this, name, p4): SingleResultCommand.__init__(this, name, p4) this.p4flags = "" # Clear the -G flag this.pipeMode = 't' def isValid(this, lines): return True def validate(this, lines): if not this.isValid(lines): raise Exception("Raw content does not look like output from `p4 %s`: %s" % (this.name, lines)) def processOutput(this, stream): lines = stream.readlines() for line in lines: this.log.debug(line.rstrip()) this.validate(lines) return lines ## ## StreamedResultCommand ## class StreamedResultCommand(CommandSupport): def createResult(this, entry): raise "Abstract method" def processOutput(this, stream): return StreamedResultIterator(stream, this) ## ## StreamedResultIterator ## class StreamedResultIterator: def __init__(this, stream, resultFactory): this.log = log.getLogger(this) this.stream = stream this.resultFactory = resultFactory def __iter__(this): return this def next(this): try: entry = marshal.load(this.stream) assert entry != None this.log.debug("Entry: %s" % entry) return this.resultFactory.createResult(entry) except EOFError: raise StopIteration