Brodie Rao avatar Brodie Rao committed 8f15bea

runner: prevent Python's SIGPIPE handler from being inherited by subprocesses

This fixes issue #16 that reports getting broken pipe errors for this
test:

$ cat /dev/urandom | head -1 > /dev/null
cat: write error: Broken pipe

Comments (0)

Files changed (2)

 import optparse
 import os
 import re
+import signal
 import subprocess
 import sys
 import shutil
     """Like the string-escape codec, but doesn't escape quotes"""
     return escapesub(lambda m: escapemap[m.group(0)], s[:-1]) + ' (esc)\n'
 
+def resetsigpipe():
+    """Reset SIGPIPE to SIG_DFL (for use in subprocesses).
+
+    Doing subprocess.Popen(..., preexec_fn=resetsigpipe) will prevent
+    Python's SIGPIPE handler (SIG_IGN) from being inherited by the
+    child process.
+    """
+    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
 def test(path, indent=2, shell='/bin/sh'):
     """Run test at path and return input, output, and diff.
 
     p = subprocess.Popen([shell, '-'], bufsize=-1, stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                          universal_newlines=True, env=env,
+                         preexec_fn=resetsigpipe,
                          close_fds=os.name == 'posix')
     salt = 'CRAM%s' % time.time()
 
 def patch(cmd, diff):
     """Run echo [lines from diff] | cmd -p0"""
     p = subprocess.Popen([cmd, '-p0'], bufsize=-1, stdin=subprocess.PIPE,
-                         universal_newlines=True, close_fds=os.name == 'posix')
+                         universal_newlines=True, preexec_fn=resetsigpipe,
+                         close_fds=os.name == 'posix')
     for line in diff:
         p.stdin.write(line)
     p.stdin.close()
   \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc)
   $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n'
   \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc)
+
+Command that closes a pipe:
+
+  $ cat /dev/urandom | head -1 > /dev/null
+
+If Cram let Python's SIGPIPE handler get inherited by this script, we
+might see broken pipe messages.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.