1
from __future__ import generators
3
from py.__.test.session import Session
4
from py.__.test.terminal.out import getout
5
from py.__.test.outcome import Failed, Passed, Skipped
7
def checkpyfilechange(rootdir, statcache={}):
8
""" wait until project files are changed. """
10
return p.ext in ('.py', '.c', '.h')
11
#fil = lambda x: x.check(fnmatch='*.py')
13
return p.check(dotfile=0)
15
for path in rootdir.visit(fil, rec):
16
oldstat = statcache.get(path, None)
18
statcache[path] = curstat = path.stat()
19
except py.error.ENOENT:
22
print "# WARN: race condition on", path
25
if oldstat.mtime != curstat.mtime or \
26
oldstat.size != curstat.size:
28
print "# MODIFIED", path
33
def getfailureitems(failures):
35
for rootpath, names in failures:
36
root = py.path.local(rootpath)
38
current = py.test.collect.Directory(root).Directory(root)
39
elif root.check(file=1):
40
current = py.test.collect.Module(root).Module(root)
41
# root is fspath of names[0] -> pop names[0]
42
# slicing works with empty lists
47
current = current.join(name)
49
print "WARNING: could not find %s on %r" %(name, current)
55
class RemoteTerminalSession(Session):
56
def __init__(self, config, file=None):
57
super(RemoteTerminalSession, self).__init__(config=config)
60
file = py.std.sys.stdout
62
self.out = getout(file)
64
def _setexecutable(self):
65
name = self.config.option.executable
67
executable = py.std.sys.executable
69
executable = py.path.local.sysfind(name)
70
assert executable is not None, executable
71
self.executable = executable
74
rootdir = self.config.topdir
78
if self.config.option.looponfailing and (failures or not wasfailing):
79
while not checkpyfilechange(rootdir):
80
py.std.time.sleep(4.4)
81
wasfailing = len(failures)
82
failures = self.run_remote_session(failures)
83
if not self.config.option.looponfailing:
86
print "# looponfailing: mode: %d failures args" % len(failures)
87
for root, names in failures:
88
name = "/".join(names) # XXX
89
print "Failure at: %r" % (name,)
90
print "# watching py files below %s" % rootdir
91
print "# ", "^" * len(str(rootdir))
94
def _initslavegateway(self):
95
print "* opening PopenGateway: ", self.executable
96
topdir = self.config.topdir
97
return py.execnet.PopenGateway(self.executable), topdir
99
def run_remote_session(self, failures):
100
gw, topdir = self._initslavegateway()
101
channel = gw.remote_exec("""
102
from py.__.test.terminal.remote import slaverun_TerminalSession
103
slaverun_TerminalSession(channel)
104
""", stdout=self.out, stderr=self.out)
106
print "MASTER: initiated slave terminal session ->"
107
repr = self.config._makerepr(conftestnames=[])
108
channel.send((str(topdir), repr, failures))
109
print "MASTER: send start info, topdir=%s" % (topdir,)
111
return channel.receive()
112
except channel.RemoteError, e:
114
print "ERROR while waiting for proper slave startup"
121
def slaverun_TerminalSession(channel):
122
""" we run this on the other side. """
123
print "SLAVE: initializing ..."
124
topdir, repr, failures = channel.receive()
125
print "SLAVE: received configuration, using topdir:", topdir
126
config = py.test.config
127
config._initdirect(topdir, repr, failures)
128
config.option.session = None
129
config.option.looponfailing = False
130
config.option.usepdb = False
131
config.option.executable = None
133
config.option.verbose = True
135
session = config.initsession()
136
session.shouldclose = channel.isclosed
137
print "SLAVE: starting session.main()"
139
failures = session.getitemoutcomepairs(Failed)
140
failures = [config.get_collector_trail(item) for item,_ in failures]
141
channel.send(failures)