: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.
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
-
- if stdout is None:
- stdout = logger.getChild('out')
- g_out = gevent.spawn(copy_file_to, r.stdout, stdout)
- r.stdout = stdout
+ 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."
+
+ 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()
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 '")