Created
June 29, 2016 03:50
-
-
Save sp3c73r2038/fa7e30d47b7a9451eeb183a520549561 to your computer and use it in GitHub Desktop.
run command in child process without
This file contains hidden or 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
# -*- coding: utf-8 -*- | |
import errno | |
import os | |
import fcntl | |
# !! License GPLv2 !! | |
# only work on Linux, MacOSX, may work on Windows, no tested. | |
# some syscall/flags not available on other OS(like Solaris), so not supported | |
def run_in_child(cmd): | |
"""run shell command in child process, | |
non-blocking yields output. | |
Args: | |
cmd (string): command to run | |
Returns: | |
string, int: output line and exit value, output would be ``None'', | |
exit value should use the last one. | |
""" | |
r, w = os.pipe() | |
pid = os.fork() | |
exitvalue = None | |
if pid == 0: | |
# child | |
os.dup2(r, 0) | |
os.dup2(w, 1) | |
os.dup2(w, 2) | |
os.close(r) | |
os.close(w) | |
os.execl('/bin/bash', 'bash', '-c', cmd) | |
else: | |
f = fcntl.fcntl(r, fcntl.F_GETFL) | |
fcntl.fcntl(r, fcntl.F_SETFL, f | os.O_NONBLOCK) | |
line = b'' | |
while True: | |
try: | |
_ = os.read(r, 1) | |
line += _ | |
if _ == b'\r': | |
_ = os.read(r, 1) | |
line += _ | |
yield line.decode('UTF-8').strip(), exitvalue | |
line = b'' | |
if _ == b'\n': | |
yield line.decode('UTF-8').strip(), exitvalue | |
line = b'' | |
except OSError as e: | |
try: | |
if type(e) == BlockingIOError: | |
pass | |
else: | |
raise | |
except NameError: | |
if e.errno == errno.EAGAIN: | |
pass | |
else: | |
raise | |
try: | |
_pid, exitvalue = os.waitpid(-1, os.WNOHANG) | |
except Exception as e: | |
try: | |
if type(e) == ChildProcessError: | |
break | |
else: | |
raise | |
except NameError: | |
if e.errno == errno.ECHILD: | |
break | |
else: | |
raise | |
if line: | |
yield line.decode('UTF-8').strip(), exitvalue | |
yield None, exitvalue | |
def local(cmd, quiet=False, _raise=True): | |
"""run local command, prints output non-blocking | |
Args: | |
cmd (string): command to run | |
quiet (bool): whether to surpress output | |
_raise (bool): whether to raise RuntimeError when exit value is not 0 | |
""" | |
line = '' | |
exitvalue = 0 | |
for line, exitvalue in run_in_child(cmd): | |
if not quiet and line: | |
print(line) | |
if exitvalue != 0: | |
raise RuntimeError('run local command failed: %s' % cmd) | |
local('python -u sleep.py') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment