aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-20 20:44:58 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-21 14:58:17 +0100
commite0829dd6ab62d8bd25308fc806072d1b378a1523 (patch)
treec3b66fde4f00680f159ff206eea92e90e55ff4ed
parentfcd415e70607343e806be7e05e99629969483edd (diff)
downloadpaludis-e0829dd6ab62d8bd25308fc806072d1b378a1523.tar.gz
paludis-e0829dd6ab62d8bd25308fc806072d1b378a1523.tar.xz
Process::prefix_std{out,err}
-rw-r--r--paludis/util/process.cc119
-rw-r--r--paludis/util/process.hh3
-rw-r--r--paludis/util/process_TEST.cc32
3 files changed, 152 insertions, 2 deletions
diff --git a/paludis/util/process.cc b/paludis/util/process.cc
index 5645208..82aa7b7 100644
--- a/paludis/util/process.cc
+++ b/paludis/util/process.cc
@@ -24,6 +24,7 @@
#include <paludis/util/pty.hh>
#include <paludis/util/fs_entry.hh>
#include <paludis/util/stringify.hh>
+#include <paludis/util/safe_ofstream.hh>
#include <iostream>
#include <functional>
@@ -116,11 +117,18 @@ namespace paludis
{
Pipe ctl_pipe;
+ std::unique_ptr<SafeOFStream> own_capture_stdout;
+ std::unique_ptr<SafeOFStream> own_capture_stderr;
+
+ std::string prefix_stdout;
std::ostream * capture_stdout;
std::unique_ptr<Channel> capture_stdout_pipe;
+ std::string prefix_stdout_buffer;
+ std::string prefix_stderr;
std::ostream * capture_stderr;
std::unique_ptr<Channel> capture_stderr_pipe;
+ std::string prefix_stderr_buffer;
std::ostream * capture_output_to_fd;
std::unique_ptr<Pipe> capture_output_to_fd_pipe;
@@ -150,6 +158,7 @@ namespace paludis
void
RunningProcessThread::thread_func()
{
+ bool prefix_stdout_buffer_has_newline(false), prefix_stderr_buffer_has_newline(false);
bool done(false);
while (! done)
{
@@ -198,7 +207,17 @@ RunningProcessThread::thread_func()
if (-1 == n)
throw ProcessError("read() capture_stdout_pipe read_fd failed");
else if (0 != n)
- capture_stdout->write(buf, n);
+ {
+ if (prefix_stdout.empty())
+ capture_stdout->write(buf, n);
+ else
+ {
+ std::string s(buf, n);
+ prefix_stdout_buffer.append(s);
+ if (std::string::npos != s.find('\n'))
+ prefix_stdout_buffer_has_newline = true;
+ }
+ }
done_anything = true;
}
@@ -208,7 +227,17 @@ RunningProcessThread::thread_func()
if (-1 == n)
throw ProcessError("read() capture_stderr_pipe read_fd failed");
else if (0 != n)
- capture_stderr->write(buf, n);
+ {
+ if (prefix_stderr.empty())
+ capture_stderr->write(buf, n);
+ else
+ {
+ std::string s(buf, n);
+ prefix_stderr_buffer.append(s);
+ if (std::string::npos != s.find('\n'))
+ prefix_stderr_buffer_has_newline = true;
+ }
+ }
done_anything = true;
}
@@ -259,12 +288,59 @@ RunningProcessThread::thread_func()
throw ProcessError("write() pipe_command_handler_response_pipe write_fd failed");
}
+ if (prefix_stdout_buffer_has_newline)
+ {
+ while (true)
+ {
+ std::string::size_type p(prefix_stdout_buffer.find('\n'));
+ if (std::string::npos == p)
+ break;
+
+ capture_stdout->write(prefix_stdout.data(), prefix_stdout.length());
+ capture_stdout->write(prefix_stdout_buffer.data(), p + 1);
+ prefix_stdout_buffer.erase(0, p + 1);
+ }
+
+ prefix_stdout_buffer_has_newline = false;
+ }
+
+ if (prefix_stderr_buffer_has_newline)
+ {
+ while (true)
+ {
+ std::string::size_type p(prefix_stderr_buffer.find('\n'));
+ if (std::string::npos == p)
+ break;
+
+ capture_stderr->write(prefix_stderr.data(), prefix_stderr.length());
+ capture_stderr->write(prefix_stderr_buffer.data(), p + 1);
+ prefix_stderr_buffer.erase(0, p + 1);
+ }
+
+ prefix_stderr_buffer_has_newline = false;
+ }
+
if (done_anything)
continue;
/* don't do this until nothing else has anything to do */
if (FD_ISSET(ctl_pipe.read_fd(), &read_fds))
{
+ /* haxx: flush our buffers first */
+ if (! prefix_stdout_buffer.empty())
+ {
+ prefix_stdout_buffer.append("\n");
+ prefix_stdout_buffer_has_newline = true;
+ continue;
+ }
+
+ if (! prefix_stderr_buffer.empty())
+ {
+ prefix_stderr_buffer.append("\n");
+ prefix_stderr_buffer_has_newline = true;
+ continue;
+ }
+
char c('?');
if (1 != ::read(ctl_pipe.read_fd(), &c, 1))
throw ProcessError("read() on our ctl pipe failed");
@@ -305,6 +381,9 @@ namespace paludis
gid_t setgid;
std::ostream * echo_command_to;
+ std::string prefix_stdout;
+ std::string prefix_stderr;
+
Imp(ProcessCommand && c) :
command(std::move(c)),
need_thread(false),
@@ -342,6 +421,26 @@ Process::run()
{
thread.reset(new RunningProcessThread{});
+ if (! _imp->prefix_stdout.empty())
+ {
+ thread->prefix_stdout = _imp->prefix_stdout;
+ if (! _imp->capture_stdout)
+ {
+ thread->own_capture_stdout.reset(new SafeOFStream(STDOUT_FILENO));
+ _imp->capture_stdout = thread->own_capture_stdout.get();
+ }
+ }
+
+ if (! _imp->prefix_stderr.empty())
+ {
+ thread->prefix_stderr = _imp->prefix_stderr;
+ if (! _imp->capture_stderr)
+ {
+ thread->own_capture_stderr.reset(new SafeOFStream(STDERR_FILENO));
+ _imp->capture_stderr = thread->own_capture_stderr.get();
+ }
+ }
+
if (_imp->capture_stdout)
{
thread->capture_stdout = _imp->capture_stdout;
@@ -554,6 +653,22 @@ Process::echo_command_to(std::ostream & s)
return *this;
}
+Process &
+Process::prefix_stdout(const std::string & s)
+{
+ _imp->need_thread = true;
+ _imp->prefix_stdout = s;
+ return *this;
+}
+
+Process &
+Process::prefix_stderr(const std::string & s)
+{
+ _imp->need_thread = true;
+ _imp->prefix_stderr = s;
+ return *this;
+}
+
namespace paludis
{
template <>
diff --git a/paludis/util/process.hh b/paludis/util/process.hh
index 79d9577..ddc17a1 100644
--- a/paludis/util/process.hh
+++ b/paludis/util/process.hh
@@ -89,6 +89,9 @@ namespace paludis
Process & use_ptys();
Process & setuid_setgid(uid_t, gid_t);
Process & echo_command_to(std::ostream &);
+
+ Process & prefix_stdout(const std::string &);
+ Process & prefix_stderr(const std::string &);
};
class PALUDIS_VISIBLE RunningProcessHandle :
diff --git a/paludis/util/process_TEST.cc b/paludis/util/process_TEST.cc
index 71f2170..69fc5fd 100644
--- a/paludis/util/process_TEST.cc
+++ b/paludis/util/process_TEST.cc
@@ -349,5 +349,37 @@ namespace test_cases
TEST_CHECK(! std::getline(stdout_stream, line));
}
} test_captured_pipe_command;
+
+ struct PrefixStdoutTest : TestCase
+ {
+ PrefixStdoutTest() : TestCase("prefix stdout") { }
+
+ void run()
+ {
+ std::stringstream stdout_stream;
+ Process echo_process(ProcessCommand({ "sh", "-c", "echo monkey ; echo in ; echo space"}));
+ echo_process.capture_stdout(stdout_stream);
+ echo_process.prefix_stdout("prefix> ");
+
+ TEST_CHECK_EQUAL(echo_process.run().wait(), 0);
+ TEST_CHECK_EQUAL(stdout_stream.str(), "prefix> monkey\nprefix> in\nprefix> space\n");
+ }
+ } test_prefix_stdout;
+
+ struct PrefixStderrTest : TestCase
+ {
+ PrefixStderrTest() : TestCase("prefix stderr") { }
+
+ void run()
+ {
+ std::stringstream stderr_stream;
+ Process echo_process(ProcessCommand({ "sh", "-c", "echo monkey 1>&2 ; echo in 1>&2 ; echo space 1>&2"}));
+ echo_process.capture_stderr(stderr_stream);
+ echo_process.prefix_stderr("prefix> ");
+
+ TEST_CHECK_EQUAL(echo_process.run().wait(), 0);
+ TEST_CHECK_EQUAL(stderr_stream.str(), "prefix> monkey\nprefix> in\nprefix> space\n");
+ }
+ } test_prefix_stderr;
}