hgbook

view en/examples/run-example @ 19:187702df428b

Piles of new content for MQ chapter - cookbook stuff.
author Bryan O'Sullivan <bos@serpentine.com>
date Fri Jul 07 19:56:53 2006 -0700 (2006-07-07)
parents 69d90ab9fd80
children a752b0fd3c10
line source
1 #!/usr/bin/python
2 #
3 # This program takes something that resembles a shell script and runs
4 # it, spitting input (commands from the script) and output into text
5 # files, for use in examples.
7 import cStringIO
8 import os
9 import pty
10 import re
11 import shutil
12 import signal
13 import sys
14 import tempfile
15 import time
17 def tex_escape(s):
18 if '\\' in s:
19 s = s.replace('\\', '\\\\')
20 if '{' in s:
21 s = s.replace('{', '\\{')
22 if '}' in s:
23 s = s.replace('}', '\\}')
24 return s
26 class example:
27 shell = '/bin/bash'
28 prompt = '__run_example_prompt__\n'
29 pi_re = re.compile('#\$\s*(name):\s*(.*)$')
31 def __init__(self, name):
32 self.name = name
34 def parse(self):
35 '''yield each hunk of input from the file.'''
36 fp = open(self.name)
37 cfp = cStringIO.StringIO()
38 for line in fp:
39 cfp.write(line)
40 if not line.rstrip().endswith('\\'):
41 yield cfp.getvalue()
42 cfp.seek(0)
43 cfp.truncate()
45 def status(self, s):
46 sys.stdout.write(s)
47 if not s.endswith('\n'):
48 sys.stdout.flush()
50 def send(self, s):
51 self.cfp.write(s)
52 self.cfp.flush()
54 def receive(self):
55 out = cStringIO.StringIO()
56 while True:
57 s = self.cfp.readline().replace('\r\n', '\n')
58 if not s or s == self.prompt:
59 break
60 out.write(s)
61 return out.getvalue()
63 def sendreceive(self, s):
64 self.send(s)
65 r = self.receive()
66 if r.startswith(s):
67 r = r[len(s):]
68 return r
70 def run(self):
71 ofp = None
72 basename = os.path.basename(self.name)
73 self.status('running %s ' % basename)
74 tmpdir = tempfile.mkdtemp(prefix=basename)
75 rcfile = os.path.join(tmpdir, '.bashrc')
76 rcfp = open(rcfile, 'w')
77 print >> rcfp, 'PS1="%s"' % self.prompt
78 print >> rcfp, 'unset HISTFILE'
79 print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd()
80 print >> rcfp, 'export LANG=C'
81 print >> rcfp, 'export LC_ALL=C'
82 print >> rcfp, 'export TZ=GMT'
83 print >> rcfp, 'export HGRC="%s/.hgrc"' % tmpdir
84 print >> rcfp, 'export HGRCPATH=$HGRC'
85 print >> rcfp, 'cd %s' % tmpdir
86 rcfp.close()
87 pid, fd = pty.fork()
88 if pid == 0:
89 #os.execl(self.shell, self.shell)
90 os.system('/bin/bash --noediting --noprofile --rcfile %s' % rcfile)
91 sys.exit(0)
92 self.cfp = os.fdopen(fd, 'w+')
93 try:
94 self.receive()
95 for hunk in self.parse():
96 # is this line a processing instruction?
97 m = self.pi_re.match(hunk)
98 if m:
99 pi, rest = m.groups()
100 if pi == 'name':
101 self.status('.')
102 out = rest
103 assert os.sep not in out
104 if out:
105 ofp = open('%s.%s.out' % (self.name, out), 'w')
106 else:
107 ofp = None
108 elif hunk.strip():
109 # it's something we should execute
110 output = self.sendreceive(hunk)
111 if not ofp:
112 continue
113 # first, print the command we ran
114 if not hunk.startswith('#'):
115 nl = hunk.endswith('\n')
116 hunk = ('$ \\textbf{%s}' %
117 tex_escape(hunk.rstrip('\n')))
118 if nl: hunk += '\n'
119 ofp.write(hunk)
120 # then its output
121 ofp.write(tex_escape(output))
122 self.status('\n')
123 finally:
124 try:
125 output = self.sendreceive('exit\n')
126 if ofp:
127 ofp.write(output)
128 self.cfp.close()
129 except IOError:
130 pass
131 os.kill(pid, signal.SIGTERM)
132 os.wait()
133 shutil.rmtree(tmpdir)
135 def main(path='.'):
136 args = sys.argv[1:]
137 if args:
138 for a in args:
139 example(a).run()
140 return
141 for name in os.listdir(path):
142 if name == 'run-example' or name.startswith('.'): continue
143 if name.endswith('.out') or name.endswith('~'): continue
144 pathname = os.path.join(path, name)
145 if os.path.isfile(pathname):
146 example(pathname).run()
147 print >> open(os.path.join(path, '.run'), 'w'), time.asctime()
149 if __name__ == '__main__':
150 main()