changeset 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, 26 Jun 2006 10:15:49 -0700
parents faa29ca23fc8
children 339e75288632
files en/examples/mq.qinit-help en/examples/run-example
diffstat 2 files changed, 61 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/en/examples/mq.qinit-help	Sun Jun 25 22:44:24 2006 -0700
+++ b/en/examples/mq.qinit-help	Mon Jun 26 10:15:49 2006 -0700
@@ -1,2 +1,5 @@
+echo '[extensions]' >> $HGRC
+echo 'hgext.mq =' >> $HGRC
+
 #$ name: help
 hg help qinit
--- a/en/examples/run-example	Sun Jun 25 22:44:24 2006 -0700
+++ b/en/examples/run-example	Mon Jun 26 10:15:49 2006 -0700
@@ -9,6 +9,7 @@
 import pty
 import re
 import shutil
+import signal
 import sys
 import tempfile
 import time
@@ -24,6 +25,7 @@
         
 class example:
     shell = '/bin/bash'
+    prompt = '__run_example_prompt__\n'
     pi_re = re.compile('#\$\s*(name):\s*(.*)$')
     
     def __init__(self, name):
@@ -45,18 +47,50 @@
         if not s.endswith('\n'):
             sys.stdout.flush()
 
-    def drain(self, ifp, ofp):
+    def send(self, s):
+        self.cfp.write(s)
+        self.cfp.flush()
+
+    def receive(self):
+        out = cStringIO.StringIO()
         while True:
-            s = ifp.read(4096)
-            if not s: break
-            if ofp: ofp.write(tex_escape(s))
+            s = self.cfp.readline().replace('\r\n', '\n')
+            if not s or s == self.prompt:
+                break
+            out.write(s)
+        return out.getvalue()
         
+    def sendreceive(self, s):
+        self.send(s)
+        r = self.receive()
+        if r.startswith(s):
+            r = r[len(s):]
+        return r
+    
     def run(self):
         ofp = None
         basename = os.path.basename(self.name)
         self.status('running %s ' % basename)
         tmpdir = tempfile.mkdtemp(prefix=basename)
+        rcfile = os.path.join(tmpdir, '.bashrc')
+        rcfp = open(rcfile, 'w')
+        print >> rcfp, 'PS1="%s"' % self.prompt
+        print >> rcfp, 'unset HISTFILE'
+        print >> rcfp, 'export LANG=C'
+        print >> rcfp, 'export LC_ALL=C'
+        print >> rcfp, 'export TZ=GMT'
+        print >> rcfp, 'export HGRC="%s/.hgrc"' % tmpdir
+        print >> rcfp, 'export HGRCPATH=$HGRC'
+        print >> rcfp, 'cd %s' % tmpdir
+        rcfp.close()
+        pid, fd = pty.fork()
+        if pid == 0:
+            #os.execl(self.shell, self.shell)
+            os.system('/bin/bash --noediting --noprofile --rcfile %s' % rcfile)
+            sys.exit(0)
+        self.cfp = os.fdopen(fd, 'w+')
         try:
+            self.receive()
             for hunk in self.parse():
                 # is this line a processing instruction?
                 m = self.pi_re.match(hunk)
@@ -70,22 +104,30 @@
                             ofp = open('%s.%s.out' % (self.name, out), 'w')
                         else:
                             ofp = None
-                else:
+                elif hunk.strip():
                     # 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)
+                    output = self.sendreceive(hunk)
+                    if not ofp:
+                        continue
+                    # 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)
+                    ofp.write(output)
             self.status('\n')
         finally:
+            try:
+                output = self.sendreceive('exit\n')
+                if ofp:
+                    ofp.write(output)
+                self.cfp.close()
+            except IOError:
+                pass
+            os.kill(pid, signal.SIGTERM)
             os.wait()
             shutil.rmtree(tmpdir)