summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorKevin Van Brunt <kmvanbrunt@gmail.com>2019-03-20 10:56:27 -0400
committerKevin Van Brunt <kmvanbrunt@gmail.com>2019-03-20 10:56:27 -0400
commite42065ea805c813790ae91dd00e3677ed811c8cd (patch)
tree9c59206830eee4d4422c246dfb5f08945cb01fdd /cmd2
parent88f514c956b304407a2426f3da0918673602e3ee (diff)
downloadcmd2-git-e42065ea805c813790ae91dd00e3677ed811c8cd.tar.gz
Updated ProcReader to determine which of the process streams are pipes
Diffstat (limited to 'cmd2')
-rw-r--r--cmd2/cmd2.py13
-rw-r--r--cmd2/utils.py20
2 files changed, 23 insertions, 10 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 6f0835e0..c33e2927 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -2941,13 +2941,18 @@ class Cmd(cmd.Cmd):
expanded_command = ' '.join(tokens)
- # If stdout is a StdSim, then we will use pipes so we can save stdout and stderr output
- if isinstance(self.stdout, utils.StdSim):
- proc = subprocess.Popen(expanded_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ # For any output that is a StdSim, we will use a pipe so we can save the output
+ is_out_sim = isinstance(self.stdout, utils.StdSim)
+ is_err_sim = isinstance(sys.stderr, utils.StdSim)
+
+ proc_stdout = subprocess.PIPE if is_out_sim else self.stdout
+ proc_stderr = subprocess.PIPE if is_err_sim else sys.stderr
+
+ proc = subprocess.Popen(expanded_command, stdout=proc_stdout, stderr=proc_stderr, shell=True)
+ if is_out_sim or is_err_sim:
proc_reader = utils.ProcReader(proc, self.stdout, sys.stderr)
proc_reader.wait()
else:
- proc = subprocess.Popen(expanded_command, stdout=self.stdout, shell=True)
proc.communicate()
@staticmethod
diff --git a/cmd2/utils.py b/cmd2/utils.py
index a0026eba..45c7ca6a 100644
--- a/cmd2/utils.py
+++ b/cmd2/utils.py
@@ -371,7 +371,7 @@ class ByteBuf(object):
class ProcReader(object):
- """Used to read stdout and stderr from a Popen process whose stdout and stderr are set to binary pipes"""
+ """Used to read stdout and stderr from a Popen process if any of those were set to subprocess.PIPE"""
def __init__(self, proc: subprocess.Popen, stdout: Union[StdSim, BinaryIO, TextIO],
stderr: Union[StdSim, BinaryIO, TextIO]) -> None:
"""
@@ -390,9 +390,11 @@ class ProcReader(object):
self._err_thread = threading.Thread(name='out_thread', target=self._reader_thread_func,
kwargs={'read_stdout': False})
- # Start reading from the process
- self._out_thread.start()
- self._err_thread.start()
+ # Start the reader threads for pipes only
+ if self._proc.stdout is not None:
+ self._out_thread.start()
+ if self._proc.stderr is not None:
+ self._err_thread.start()
def terminate(self) -> None:
"""Terminates the process being run"""
@@ -400,10 +402,13 @@ class ProcReader(object):
def wait(self) -> None:
"""Wait for the process to finish"""
- self._out_thread.join()
- self._err_thread.join()
+ if self._out_thread.is_alive():
+ self._out_thread.join()
+ if self._err_thread.is_alive():
+ self._err_thread.join()
# Handle case where the process ended before the last read could be done
+ # This will return None for the streams that weren't pipes so it is safe.
out, err = self._proc.communicate()
if out:
self._write_bytes(self._stdout, out)
@@ -422,6 +427,9 @@ class ProcReader(object):
read_stream = self._proc.stderr
write_stream = self._stderr
+ # The thread should have been started only if this stream was a pipe
+ assert read_stream is not None
+
# Run until process completes
while self._proc.poll() is None:
# noinspection PyUnresolvedReferences