sources for remote.py [rev. 38799]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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)