hgbook

diff en/examples/run-example @ 6:69d90ab9fd80

Really run example command sequences under a single shell.
Grotesque hackery involved. Bring strong stomachs.
author Bryan O'Sullivan <bos@serpentine.com>
date Mon Jun 26 10:15:49 2006 -0700 (2006-06-26)
parents 33a2e7b9978d
children 187702df428b 5ad16196cef4
line diff
     1.1 --- a/en/examples/run-example	Sun Jun 25 22:04:50 2006 -0700
     1.2 +++ b/en/examples/run-example	Mon Jun 26 10:15:49 2006 -0700
     1.3 @@ -9,6 +9,7 @@
     1.4  import pty
     1.5  import re
     1.6  import shutil
     1.7 +import signal
     1.8  import sys
     1.9  import tempfile
    1.10  import time
    1.11 @@ -24,6 +25,7 @@
    1.12          
    1.13  class example:
    1.14      shell = '/bin/bash'
    1.15 +    prompt = '__run_example_prompt__\n'
    1.16      pi_re = re.compile('#\$\s*(name):\s*(.*)$')
    1.17      
    1.18      def __init__(self, name):
    1.19 @@ -45,18 +47,50 @@
    1.20          if not s.endswith('\n'):
    1.21              sys.stdout.flush()
    1.22  
    1.23 -    def drain(self, ifp, ofp):
    1.24 +    def send(self, s):
    1.25 +        self.cfp.write(s)
    1.26 +        self.cfp.flush()
    1.27 +
    1.28 +    def receive(self):
    1.29 +        out = cStringIO.StringIO()
    1.30          while True:
    1.31 -            s = ifp.read(4096)
    1.32 -            if not s: break
    1.33 -            if ofp: ofp.write(tex_escape(s))
    1.34 +            s = self.cfp.readline().replace('\r\n', '\n')
    1.35 +            if not s or s == self.prompt:
    1.36 +                break
    1.37 +            out.write(s)
    1.38 +        return out.getvalue()
    1.39          
    1.40 +    def sendreceive(self, s):
    1.41 +        self.send(s)
    1.42 +        r = self.receive()
    1.43 +        if r.startswith(s):
    1.44 +            r = r[len(s):]
    1.45 +        return r
    1.46 +    
    1.47      def run(self):
    1.48          ofp = None
    1.49          basename = os.path.basename(self.name)
    1.50          self.status('running %s ' % basename)
    1.51          tmpdir = tempfile.mkdtemp(prefix=basename)
    1.52 +        rcfile = os.path.join(tmpdir, '.bashrc')
    1.53 +        rcfp = open(rcfile, 'w')
    1.54 +        print >> rcfp, 'PS1="%s"' % self.prompt
    1.55 +        print >> rcfp, 'unset HISTFILE'
    1.56 +        print >> rcfp, 'export LANG=C'
    1.57 +        print >> rcfp, 'export LC_ALL=C'
    1.58 +        print >> rcfp, 'export TZ=GMT'
    1.59 +        print >> rcfp, 'export HGRC="%s/.hgrc"' % tmpdir
    1.60 +        print >> rcfp, 'export HGRCPATH=$HGRC'
    1.61 +        print >> rcfp, 'cd %s' % tmpdir
    1.62 +        rcfp.close()
    1.63 +        pid, fd = pty.fork()
    1.64 +        if pid == 0:
    1.65 +            #os.execl(self.shell, self.shell)
    1.66 +            os.system('/bin/bash --noediting --noprofile --rcfile %s' % rcfile)
    1.67 +            sys.exit(0)
    1.68 +        self.cfp = os.fdopen(fd, 'w+')
    1.69          try:
    1.70 +            self.receive()
    1.71              for hunk in self.parse():
    1.72                  # is this line a processing instruction?
    1.73                  m = self.pi_re.match(hunk)
    1.74 @@ -70,22 +104,30 @@
    1.75                              ofp = open('%s.%s.out' % (self.name, out), 'w')
    1.76                          else:
    1.77                              ofp = None
    1.78 -                else:
    1.79 +                elif hunk.strip():
    1.80                      # it's something we should execute
    1.81 -                    cin, cout = os.popen4('cd %s; %s' % (tmpdir, hunk))
    1.82 -                    cin.close()
    1.83 -                    if ofp:
    1.84 -                        # first, print the command we ran
    1.85 -                        if not hunk.startswith('#'):
    1.86 -                            nl = hunk.endswith('\n')
    1.87 -                            hunk = ('$ \\textbf{%s}' %
    1.88 -                                    tex_escape(hunk.rstrip('\n')))
    1.89 -                            if nl: hunk += '\n'
    1.90 -                        ofp.write(hunk)
    1.91 +                    output = self.sendreceive(hunk)
    1.92 +                    if not ofp:
    1.93 +                        continue
    1.94 +                    # first, print the command we ran
    1.95 +                    if not hunk.startswith('#'):
    1.96 +                        nl = hunk.endswith('\n')
    1.97 +                        hunk = ('$ \\textbf{%s}' %
    1.98 +                                tex_escape(hunk.rstrip('\n')))
    1.99 +                        if nl: hunk += '\n'
   1.100 +                    ofp.write(hunk)
   1.101                      # then its output
   1.102 -                    self.drain(cout, ofp)
   1.103 +                    ofp.write(output)
   1.104              self.status('\n')
   1.105          finally:
   1.106 +            try:
   1.107 +                output = self.sendreceive('exit\n')
   1.108 +                if ofp:
   1.109 +                    ofp.write(output)
   1.110 +                self.cfp.close()
   1.111 +            except IOError:
   1.112 +                pass
   1.113 +            os.kill(pid, signal.SIGTERM)
   1.114              os.wait()
   1.115              shutil.rmtree(tmpdir)
   1.116