]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Support PIPE for stdout and stderr, too.
authorTommi Virtanen <tommi.virtanen@dreamhost.com>
Mon, 6 Jun 2011 23:47:55 +0000 (16:47 -0700)
committerTommi Virtanen <tommi.virtanen@dreamhost.com>
Tue, 7 Jun 2011 21:41:50 +0000 (14:41 -0700)
orchestra/run.py
orchestra/test/test_run.py

index cc38793915fce5fb118a65f45ff0b73b6d21347d..e60d8b9815e5e2d710fa90660fab63ce37da0373 100644 (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
-
-    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()
 
index d0da399b9cb2c28cf23df2bb6329e3711373fd1a..0452758b946abaae74aa09e1d4e401c4913506bd 100644 (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 '")