annotate en/examples/run-example @ 4:33a2e7b9978d

Make it possible to include example input and output from real programs. Instead of having to cut and paste example text, the task is automated.
author Bryan O'Sullivan <bos@serpentine.com>
date Sun, 25 Jun 2006 22:04:50 -0700
parents 906d9021f9e5
children 69d90ab9fd80
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
1 #!/usr/bin/python
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
2 #
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
3 # This program takes something that resembles a shell script and runs
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
4 # it, spitting input (commands from the script) and output into text
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
5 # files, for use in examples.
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
6
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
7 import cStringIO
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
8 import os
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
9 import pty
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
10 import re
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
11 import shutil
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
12 import sys
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
13 import tempfile
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
14 import time
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
15
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
16 def tex_escape(s):
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
17 if '\\' in s:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
18 s = s.replace('\\', '\\\\')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
19 if '{' in s:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
20 s = s.replace('{', '\\{')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
21 if '}' in s:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
22 s = s.replace('}', '\\}')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
23 return s
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
24
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
25 class example:
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
26 shell = '/bin/bash'
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
27 pi_re = re.compile('#\$\s*(name):\s*(.*)$')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
28
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
29 def __init__(self, name):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
30 self.name = name
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
31
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
32 def parse(self):
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
33 '''yield each hunk of input from the file.'''
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
34 fp = open(self.name)
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
35 cfp = cStringIO.StringIO()
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
36 for line in fp:
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
37 cfp.write(line)
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
38 if not line.rstrip().endswith('\\'):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
39 yield cfp.getvalue()
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
40 cfp.seek(0)
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
41 cfp.truncate()
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
42
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
43 def status(self, s):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
44 sys.stdout.write(s)
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
45 if not s.endswith('\n'):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
46 sys.stdout.flush()
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
47
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
48 def drain(self, ifp, ofp):
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
49 while True:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
50 s = ifp.read(4096)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
51 if not s: break
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
52 if ofp: ofp.write(tex_escape(s))
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
53
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
54 def run(self):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
55 ofp = None
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
56 basename = os.path.basename(self.name)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
57 self.status('running %s ' % basename)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
58 tmpdir = tempfile.mkdtemp(prefix=basename)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
59 try:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
60 for hunk in self.parse():
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
61 # is this line a processing instruction?
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
62 m = self.pi_re.match(hunk)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
63 if m:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
64 pi, rest = m.groups()
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
65 if pi == 'name':
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
66 self.status('.')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
67 out = rest
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
68 assert os.sep not in out
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
69 if out:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
70 ofp = open('%s.%s.out' % (self.name, out), 'w')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
71 else:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
72 ofp = None
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
73 else:
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
74 # it's something we should execute
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
75 cin, cout = os.popen4('cd %s; %s' % (tmpdir, hunk))
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
76 cin.close()
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
77 if ofp:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
78 # first, print the command we ran
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
79 if not hunk.startswith('#'):
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
80 nl = hunk.endswith('\n')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
81 hunk = ('$ \\textbf{%s}' %
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
82 tex_escape(hunk.rstrip('\n')))
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
83 if nl: hunk += '\n'
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
84 ofp.write(hunk)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
85 # then its output
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
86 self.drain(cout, ofp)
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
87 self.status('\n')
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
88 finally:
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
89 os.wait()
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
90 shutil.rmtree(tmpdir)
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
91
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
92 def main(path='.'):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
93 args = sys.argv[1:]
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
94 if args:
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
95 for a in args:
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
96 example(a).run()
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
97 return
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
98 for name in os.listdir(path):
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
99 if name == 'run-example' or name.startswith('.'): continue
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
100 if name.endswith('.out') or name.endswith('~'): continue
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
101 example(os.path.join(path, name)).run()
4
33a2e7b9978d Make it possible to include example input and output from real programs.
Bryan O'Sullivan <bos@serpentine.com>
parents: 3
diff changeset
102 print >> open(os.path.join(path, '.run'), 'w'), time.asctime()
3
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
103
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
104 if __name__ == '__main__':
906d9021f9e5 Making progress on autogenerated example output.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff changeset
105 main()