Mercurial > hgbook
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): |