comparison en/examples/run-example @ 79:53427f786a0f

Make run-example time out if shell seems to get stuck.
author Bryan O'Sullivan <bos@serpentine.com>
date Mon, 04 Sep 2006 14:31:17 -0700
parents a893de25bc24
children b476081a9c04
comparison
equal deleted inserted replaced
78:a893de25bc24 79:53427f786a0f
8 import errno 8 import errno
9 import getopt 9 import getopt
10 import os 10 import os
11 import pty 11 import pty
12 import re 12 import re
13 import select
13 import shutil 14 import shutil
14 import signal 15 import signal
15 import stat 16 import stat
16 import sys 17 import sys
17 import tempfile 18 import tempfile
39 class example: 40 class example:
40 shell = '/usr/bin/env bash' 41 shell = '/usr/bin/env bash'
41 prompt = '__run_example_prompt__ ' 42 prompt = '__run_example_prompt__ '
42 pi_re = re.compile(r'#\$\s*(name):\s*(.*)$') 43 pi_re = re.compile(r'#\$\s*(name):\s*(.*)$')
43 44
45 timeout = 5
46
44 def __init__(self, name, verbose): 47 def __init__(self, name, verbose):
45 self.name = name 48 self.name = name
46 self.verbose = verbose 49 self.verbose = verbose
50 self.poll = select.poll()
47 51
48 def parse(self): 52 def parse(self):
49 '''yield each hunk of input from the file.''' 53 '''yield each hunk of input from the file.'''
50 fp = open(self.name) 54 fp = open(self.name)
51 cfp = cStringIO.StringIO() 55 cfp = cStringIO.StringIO()
74 if len(rs) > limit: 78 if len(rs) > limit:
75 return ('%s%s ... [%d bytes]' % (rs[:limit], rs[0], len(s))) 79 return ('%s%s ... [%d bytes]' % (rs[:limit], rs[0], len(s)))
76 else: 80 else:
77 return rs 81 return rs
78 82
83 timeout = 5
84
85 def read(self):
86 events = self.poll.poll(self.timeout * 1000)
87 if not events:
88 print >> sys.stderr, '[timed out after %d seconds]' % self.timeout
89 os.kill(self.pid, signal.SIGHUP)
90 return ''
91 return os.read(self.cfd, 1024)
92
79 def receive(self): 93 def receive(self):
80 out = cStringIO.StringIO() 94 out = cStringIO.StringIO()
81 while True: 95 while True:
82 try: 96 try:
83 if self.verbose: 97 if self.verbose:
84 sys.stderr.write('< ') 98 sys.stderr.write('< ')
85 s = os.read(self.cfd, 1024) 99 s = self.read()
86 except OSError, err: 100 except OSError, err:
87 if err.errno == errno.EIO: 101 if err.errno == errno.EIO:
88 return '' 102 return ''
89 raise 103 raise
90 if self.verbose: 104 if self.verbose:
124 print >> rcfp, 'export HGRCPATH=$HGRC' 138 print >> rcfp, 'export HGRCPATH=$HGRC'
125 print >> rcfp, 'cd %s' % tmpdir 139 print >> rcfp, 'cd %s' % tmpdir
126 rcfp.close() 140 rcfp.close()
127 sys.stdout.flush() 141 sys.stdout.flush()
128 sys.stderr.flush() 142 sys.stderr.flush()
129 pid, self.cfd = pty.fork() 143 self.pid, self.cfd = pty.fork()
130 if pid == 0: 144 if self.pid == 0:
131 cmdline = ['/usr/bin/env', 'bash', '--noediting', '--noprofile', 145 cmdline = ['/usr/bin/env', 'bash', '--noediting', '--noprofile',
132 '--norc'] 146 '--norc']
133 try: 147 try:
134 os.execv(cmdline[0], cmdline) 148 os.execv(cmdline[0], cmdline)
135 except OSError, err: 149 except OSError, err:
136 print >> sys.stderr, '%s: %s' % (cmdline[0], err.strerror) 150 print >> sys.stderr, '%s: %s' % (cmdline[0], err.strerror)
137 sys.stderr.flush() 151 sys.stderr.flush()
138 os._exit(0) 152 os._exit(0)
153 self.poll.register(self.cfd, select.POLLIN | select.POLLERR |
154 select.POLLHUP)
139 try: 155 try:
140 try: 156 try:
141 # eat first prompt string from shell 157 # eat first prompt string from shell
142 os.read(self.cfd, 1024) 158 self.read()
143 # setup env and prompt 159 # setup env and prompt
144 self.sendreceive('source %s\n' % rcfile) 160 self.sendreceive('source %s\n' % rcfile)
145 for hunk in self.parse(): 161 for hunk in self.parse():
146 # is this line a processing instruction? 162 # is this line a processing instruction?
147 m = self.pi_re.match(hunk) 163 m = self.pi_re.match(hunk)
171 ofp.write(tex_escape(output)) 187 ofp.write(tex_escape(output))
172 self.status('\n') 188 self.status('\n')
173 open(self.name + '.run', 'w') 189 open(self.name + '.run', 'w')
174 except: 190 except:
175 print >> sys.stderr, '(killed)' 191 print >> sys.stderr, '(killed)'
176 os.kill(pid, signal.SIGKILL) 192 os.kill(self.pid, signal.SIGKILL)
177 pid, rc = os.wait() 193 pid, rc = os.wait()
178 raise 194 raise
179 else: 195 else:
180 try: 196 try:
181 output = self.sendreceive('exit\n') 197 output = self.sendreceive('exit\n')
182 if ofp: 198 if ofp:
183 ofp.write(output) 199 ofp.write(output)
184 os.close(self.cfd) 200 os.close(self.cfd)
185 except IOError: 201 except IOError:
186 pass 202 pass
187 os.kill(pid, signal.SIGTERM) 203 os.kill(self.pid, signal.SIGTERM)
188 pid, rc = os.wait() 204 pid, rc = os.wait()
189 if rc: 205 if rc:
190 if os.WIFEXITED(rc): 206 if os.WIFEXITED(rc):
191 print >> sys.stderr, '(exit %s)' % os.WEXITSTATUS(rc) 207 print >> sys.stderr, '(exit %s)' % os.WEXITSTATUS(rc)
192 elif os.WIFSIGNALED(rc): 208 elif os.WIFSIGNALED(rc):