142 lines
5.0 KiB
Python
142 lines
5.0 KiB
Python
from __future__ import generators
|
|
import py
|
|
from py.__.test.session import Session
|
|
from py.__.test.terminal.out import getout
|
|
from py.__.test.outcome import Failed, Passed, Skipped
|
|
|
|
def checkpyfilechange(rootdir, statcache={}):
|
|
""" wait until project files are changed. """
|
|
def fil(p):
|
|
return p.ext in ('.py', '.c', '.h')
|
|
#fil = lambda x: x.check(fnmatch='*.py')
|
|
def rec(p):
|
|
return p.check(dotfile=0)
|
|
changed = False
|
|
for path in rootdir.visit(fil, rec):
|
|
oldstat = statcache.get(path, None)
|
|
try:
|
|
statcache[path] = curstat = path.stat()
|
|
except py.error.ENOENT:
|
|
if oldstat:
|
|
del statcache[path]
|
|
print "# WARN: race condition on", path
|
|
else:
|
|
if oldstat:
|
|
if oldstat.mtime != curstat.mtime or \
|
|
oldstat.size != curstat.size:
|
|
changed = True
|
|
print "# MODIFIED", path
|
|
else:
|
|
changed = True
|
|
return changed
|
|
|
|
def getfailureitems(failures):
|
|
l = []
|
|
for rootpath, names in failures:
|
|
root = py.path.local(rootpath)
|
|
if root.check(dir=1):
|
|
current = py.test.collect.Directory(root).Directory(root)
|
|
elif root.check(file=1):
|
|
current = py.test.collect.Module(root).Module(root)
|
|
# root is fspath of names[0] -> pop names[0]
|
|
# slicing works with empty lists
|
|
names = names[1:]
|
|
while names:
|
|
name = names.pop(0)
|
|
try:
|
|
current = current.join(name)
|
|
except NameError:
|
|
print "WARNING: could not find %s on %r" %(name, current)
|
|
break
|
|
else:
|
|
l.append(current)
|
|
return l
|
|
|
|
class RemoteTerminalSession(Session):
|
|
def __init__(self, config, file=None):
|
|
super(RemoteTerminalSession, self).__init__(config=config)
|
|
self._setexecutable()
|
|
if file is None:
|
|
file = py.std.sys.stdout
|
|
self._file = file
|
|
self.out = getout(file)
|
|
|
|
def _setexecutable(self):
|
|
name = self.config.option.executable
|
|
if name is None:
|
|
executable = py.std.sys.executable
|
|
else:
|
|
executable = py.path.local.sysfind(name)
|
|
assert executable is not None, executable
|
|
self.executable = executable
|
|
|
|
def main(self):
|
|
rootdir = self.config.topdir
|
|
wasfailing = False
|
|
failures = []
|
|
while 1:
|
|
if self.config.option.looponfailing and (failures or not wasfailing):
|
|
while not checkpyfilechange(rootdir):
|
|
py.std.time.sleep(4.4)
|
|
wasfailing = len(failures)
|
|
failures = self.run_remote_session(failures)
|
|
if not self.config.option.looponfailing:
|
|
break
|
|
print "#" * 60
|
|
print "# looponfailing: mode: %d failures args" % len(failures)
|
|
for root, names in failures:
|
|
name = "/".join(names) # XXX
|
|
print "Failure at: %r" % (name,)
|
|
print "# watching py files below %s" % rootdir
|
|
print "# ", "^" * len(str(rootdir))
|
|
return failures
|
|
|
|
def _initslavegateway(self):
|
|
print "* opening PopenGateway: ", self.executable
|
|
topdir = self.config.topdir
|
|
return py.execnet.PopenGateway(self.executable), topdir
|
|
|
|
def run_remote_session(self, failures):
|
|
gw, topdir = self._initslavegateway()
|
|
channel = gw.remote_exec("""
|
|
from py.__.test.terminal.remote import slaverun_TerminalSession
|
|
slaverun_TerminalSession(channel)
|
|
""", stdout=self.out, stderr=self.out)
|
|
try:
|
|
print "MASTER: initiated slave terminal session ->"
|
|
repr = self.config._makerepr(conftestnames=[])
|
|
channel.send((str(topdir), repr, failures))
|
|
print "MASTER: send start info, topdir=%s" % (topdir,)
|
|
try:
|
|
return channel.receive()
|
|
except channel.RemoteError, e:
|
|
print "*" * 70
|
|
print "ERROR while waiting for proper slave startup"
|
|
print "*" * 70
|
|
print e
|
|
return []
|
|
finally:
|
|
gw.exit()
|
|
|
|
def slaverun_TerminalSession(channel):
|
|
""" we run this on the other side. """
|
|
print "SLAVE: initializing ..."
|
|
topdir, repr, failures = channel.receive()
|
|
print "SLAVE: received configuration, using topdir:", topdir
|
|
config = py.test.config
|
|
config._initdirect(topdir, repr, failures)
|
|
config.option.session = None
|
|
config.option.looponfailing = False
|
|
config.option.usepdb = False
|
|
config.option.executable = None
|
|
if failures:
|
|
config.option.verbose = True
|
|
|
|
session = config.initsession()
|
|
session.shouldclose = channel.isclosed
|
|
print "SLAVE: starting session.main()"
|
|
session.main()
|
|
failures = session.getitemoutcomepairs(Failed)
|
|
failures = [config.get_collector_trail(item) for item,_ in failures]
|
|
channel.send(failures)
|