Created
February 24, 2017 11:56
-
-
Save iainlane/8b96022e3b98901b25cc5bcab6b43e02 to your computer and use it in GitHub Desktop.
intercept_stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
from splice import tee, splice | |
import asyncio.subprocess, errno, io, os, sys | |
# Run argv, return its stderr while also keeping it output to sys.stderr | |
def intercept_stderr(argv): | |
@asyncio.coroutine | |
def call_it(loop): | |
(r, w) = os.pipe() | |
# Start looking at the read end of our pipe | |
f = loop.run_in_executor(None, peek_pipe, r, sys.stderr) | |
# Fire off the process, setting stderr to the write end | |
create = asyncio.create_subprocess_exec(argv, stderr=w) | |
proc = yield from create | |
yield from proc.wait() | |
# It's finished - this will make tee() inside peek_pipe() return EINVAL | |
# so that it returns | |
os.close(r) | |
os.close(w) | |
res = yield from f | |
return res | |
# Read from 'r', putting results in 'dest' and returning the data read | |
def peek_pipe(r, dest): | |
ret = io.StringIO() | |
while True: | |
(r2, w2) = os.pipe() | |
try: | |
# Copy from r to w2, without consuming from r | |
l = tee (r, w2, sys.maxsize, 0) | |
# Now consume r by putting it into dest (the place where it | |
# came from, i.e. stderr) | |
splice(r, None, dest, None, l, 0) | |
# And also consume r2 | |
with open(r2, 'r') as f: | |
ret.write(f.read(l)) | |
os.close(w2) | |
except OSError as e: | |
# This happens when call_it() closes our input pipe | |
if e.errno == errno.EINVAL: | |
return ret.getvalue() | |
raise | |
loop = asyncio.get_event_loop() | |
r = loop.run_until_complete(call_it(loop)) | |
loop.close() | |
return r |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment