Support PIPE for stdout and stderr, too.

This commit is contained in:
Tommi Virtanen 2011-06-06 16:47:55 -07:00
parent a988083c4b
commit 37cbd7abc7
2 changed files with 91 additions and 11 deletions

View File

@ -190,7 +190,7 @@ def run(
:param args: command to run
:type args: list of string
:param stdin: Standard input to send; either a string, a file-like object, None, or `PIPE`. `PIPE` means caller is responsible for closing stdin, or command may never exit.
:param stdout: What to do with standard output. Either a file-like object, a `logging.Logger`, or `None` for copying to default log.
:param stdout: What to do with standard output. Either a file-like object, a `logging.Logger`, `PIPE`, or `None` for copying to default log. `PIPE` means caller is responsible for reading, or command may never exit.
:param stderr: What to do with standard error. See `stdout`.
:param logger: If logging, write stdout/stderr to "out" and "err" children of this logger. Defaults to logger named after this module.
:param check_status: Whether to raise CalledProcessError on non-zero exit status, and . Defaults to True. All signals and connection loss are made to look like SIGHUP.
@ -210,19 +210,29 @@ def run(
if logger is None:
logger = log
if stderr is None:
stderr = logger.getChild('err')
g_err = gevent.spawn(copy_file_to, r.stderr, stderr)
r.stderr = stderr
g_err = None
if stderr is not PIPE:
if stderr is None:
stderr = logger.getChild('err')
g_err = gevent.spawn(copy_file_to, r.stderr, stderr)
r.stderr = stderr
else:
assert not wait, "Using PIPE for stderr without wait=False would deadlock."
if stdout is None:
stdout = logger.getChild('out')
g_out = gevent.spawn(copy_file_to, r.stdout, stdout)
r.stdout = stdout
g_out = None
if stdout is not PIPE:
if stdout is None:
stdout = logger.getChild('out')
g_out = gevent.spawn(copy_file_to, r.stdout, stdout)
r.stdout = stdout
else:
assert not wait, "Using PIPE for stdout without wait=False would deadlock."
def _check_status(status):
g_err.get()
g_out.get()
if g_err is not None:
g_err.get()
if g_out is not None:
g_out.get()
if g_in is not None:
g_in.get()

View File

@ -309,6 +309,76 @@ def test_run_stdin_pipe():
eq(got, 0)
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_stdout_pipe():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('read').with_args().returns('one')
out.expects('read').with_args().returns('two')
out.expects('read').with_args().returns('')
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(0)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
stdout=run.PIPE,
wait=False,
)
eq(r.command, 'foo')
assert isinstance(r.exitstatus, gevent.event.AsyncResult)
eq(r.exitstatus.ready(), False)
eq(r.stdout.read(), 'one')
eq(r.stdout.read(), 'two')
eq(r.stdout.read(), '')
got = r.exitstatus.get()
eq(got, 0)
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_stderr_pipe():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('read').with_args().returns('one')
err.expects('read').with_args().returns('two')
err.expects('read').with_args().returns('')
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(0)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
stderr=run.PIPE,
wait=False,
)
eq(r.command, 'foo')
assert isinstance(r.exitstatus, gevent.event.AsyncResult)
eq(r.exitstatus.ready(), False)
eq(r.stderr.read(), 'one')
eq(r.stderr.read(), 'two')
eq(r.stderr.read(), '')
got = r.exitstatus.get()
eq(got, 0)
def test_quote_simple():
got = run.quote(['a b', ' c', 'd e '])
eq(got, "'a b' ' c' 'd e '")