Mercurial > hgbook
changeset 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 | faa29ca23fc8 |
files | .hgignore en/99defs.tex en/Makefile en/examples/mq.qinit-help en/examples/run-example en/mq.tex |
diffstat | 6 files changed, 96 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sat Jun 24 17:42:40 2006 -0700 +++ b/.hgignore Sun Jun 25 22:04:50 2006 -0700 @@ -3,6 +3,7 @@ syntax: glob +.run .*.swp *~ *.aux
--- a/en/99defs.tex Sat Jun 24 17:42:40 2006 -0700 +++ b/en/99defs.tex Sun Jun 25 22:04:50 2006 -0700 @@ -1,10 +1,11 @@ -\newcommand{\tildefile}[1]{\texttt{\~/#1}} +\newcommand{\tildefile}[1]{\texttt{\~{}/#1}} \newcommand{\filename}[1]{\texttt{#1}} \newcommand{\hgext}[1]{\texttt{#1}} \newcommand{\hgcmd}[1]{``\texttt{hg #1}''} \newcommand{\hgcmdargs}[2]{``\texttt{hg #1 #2}''} -\DefineVerbatimEnvironment{codesample}{Verbatim}{frame=single,gobble=2,numbers=left} +\DefineVerbatimEnvironment{codesample4}{Verbatim}{frame=single,gobble=4,numbers=left,commandchars=\\\{\}} +\newcommand{\interaction}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{examples/#1.out}} %%% Local Variables: %%% mode: latex
--- a/en/Makefile Sat Jun 24 17:42:40 2006 -0700 +++ b/en/Makefile Sun Jun 25 22:04:50 2006 -0700 @@ -4,6 +4,10 @@ 99defs.tex \ mq.tex +example-sources := \ + examples/run-example \ + examples/mq.qinit-help + latex-options = \ -interaction batchmode \ -output-directory $(dir $(1)) \ @@ -13,7 +17,7 @@ pdf: pdf/hgbook.pdf -pdf/hgbook.pdf: $(sources) +pdf/hgbook.pdf: $(sources) examples mkdir -p $(dir $@) pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) cp 99book.bib $(dir $@) @@ -32,11 +36,18 @@ cd $(dir $(1)) && t4ht -f/$(basename $(notdir $(1))) endef -html/onepage/hgbook.html: $(sources) +html/onepage/hgbook.html: $(sources) examples $(call htlatex,$@,$<) -html/split/hgbook.html: $(sources) +html/split/hgbook.html: $(sources) examples $(call htlatex,$@,$<,2) +.PHONY: examples + +examples: examples/.run + +examples/.run: $(example-sources) + cd examples && ./run-example + clean: rm -rf html pdf *.aux *.dvi *.log *.out
--- a/en/examples/mq.qinit-help Sat Jun 24 17:42:40 2006 -0700 +++ b/en/examples/mq.qinit-help Sun Jun 25 22:04:50 2006 -0700 @@ -1,2 +1,2 @@ -# name: help +#$ name: help hg help qinit
--- a/en/examples/run-example Sat Jun 24 17:42:40 2006 -0700 +++ b/en/examples/run-example Sun Jun 25 22:04:50 2006 -0700 @@ -1,16 +1,36 @@ #!/usr/bin/python +# +# This program takes something that resembles a shell script and runs +# it, spitting input (commands from the script) and output into text +# files, for use in examples. import cStringIO import os import pty import re +import shutil import sys +import tempfile +import time +def tex_escape(s): + if '\\' in s: + s = s.replace('\\', '\\\\') + if '{' in s: + s = s.replace('{', '\\{') + if '}' in s: + s = s.replace('}', '\\}') + return s + class example: + shell = '/bin/bash' + pi_re = re.compile('#\$\s*(name):\s*(.*)$') + def __init__(self, name): self.name = name def parse(self): + '''yield each hunk of input from the file.''' fp = open(self.name) cfp = cStringIO.StringIO() for line in fp: @@ -20,28 +40,54 @@ cfp.seek(0) cfp.truncate() - name_re = re.compile('#\s*name:\s*(.*)$') - def status(self, s): sys.stdout.write(s) if not s.endswith('\n'): sys.stdout.flush() + def drain(self, ifp, ofp): + while True: + s = ifp.read(4096) + if not s: break + if ofp: ofp.write(tex_escape(s)) + def run(self): ofp = None - self.status('running %s ' % os.path.basename(self.name)) - for hunk in self.parse(): - m = self.name_re.match(hunk) - if m: - self.status('.') - out = m.group(1) - assert os.sep not in out - if out: - ofp = open('%s.%s.out' % (self.name, out), 'w') + basename = os.path.basename(self.name) + self.status('running %s ' % basename) + tmpdir = tempfile.mkdtemp(prefix=basename) + try: + for hunk in self.parse(): + # is this line a processing instruction? + m = self.pi_re.match(hunk) + if m: + pi, rest = m.groups() + if pi == 'name': + self.status('.') + out = rest + assert os.sep not in out + if out: + ofp = open('%s.%s.out' % (self.name, out), 'w') + else: + ofp = None else: - ofp = None - elif ofp: ofp.write(hunk) - self.status('\n') + # it's something we should execute + cin, cout = os.popen4('cd %s; %s' % (tmpdir, hunk)) + cin.close() + if ofp: + # first, print the command we ran + if not hunk.startswith('#'): + nl = hunk.endswith('\n') + hunk = ('$ \\textbf{%s}' % + tex_escape(hunk.rstrip('\n'))) + if nl: hunk += '\n' + ofp.write(hunk) + # then its output + self.drain(cout, ofp) + self.status('\n') + finally: + os.wait() + shutil.rmtree(tmpdir) def main(path='.'): args = sys.argv[1:] @@ -53,6 +99,7 @@ if name == 'run-example' or name.startswith('.'): continue if name.endswith('.out') or name.endswith('~'): continue example(os.path.join(path, name)).run() + print >> open(os.path.join(path, '.run'), 'w'), time.asctime() if __name__ == '__main__': main()
--- a/en/mq.tex Sat Jun 24 17:42:40 2006 -0700 +++ b/en/mq.tex Sun Jun 25 22:04:50 2006 -0700 @@ -131,16 +131,26 @@ Because MQ is implemented as an extension, you must explicitly enable before you can use it. (You don't need to download anything; MQ ships with the standard Mercurial distribution.) To enable MQ, edit your -\tildefile{.hgrc} file, and add the following lines: +\tildefile{.hgrc} file, and add the lines in figure~\ref{ex:mq:config}. -\begin{codesample} - [extensions] - hgext.mq = -\end{codesample} +\begin{figure} + \begin{codesample4} + [extensions] + hgext.mq = + \end{codesample4} + \label{ex:mq:config} + \caption{Contents to add to \tildefile{.hgrc} to enable the MQ extension} +\end{figure} Once the extension is enabled, it will make a number of new commands -available. +available. To verify that the extension is working, follow the +example in figure~\ref{ex:mq:enabled}. +\begin{figure} + \interaction{mq.qinit-help.help} + \caption{How to verify that MQ is enabled} + \label{ex:mq:enabled} +\end{figure} %%% Local Variables: %%% mode: latex