aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-12-30 22:38:14 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-12-30 22:38:14 +0000
commited7ea8e04a963a7163edd7f8c9c00ca57d246743 (patch)
tree49ad27f734cd69b1173b375cc909ebf8b5cee090
parentb1f2ed57d102a708af03edeed3f0448c75e4cf96 (diff)
downloadpaludis-ed7ea8e04a963a7163edd7f8c9c00ca57d246743.tar.gz
paludis-ed7ea8e04a963a7163edd7f8c9c00ca57d246743.tar.xz
Kill PStream in favour of Command.with_captured_output_stream. Provide sneaky pipe callback support.
-rw-r--r--paludis/environments/paludis/bashable_conf.cc12
-rw-r--r--paludis/environments/paludis/paludis_config.cc30
-rw-r--r--paludis/hooker.cc17
-rw-r--r--paludis/repositories/e/ebuild.cc13
-rwxr-xr-xpaludis/repositories/e/ebuild/ebuild.bash2
-rw-r--r--paludis/repositories/e/vdb_repository.cc9
-rw-r--r--paludis/repositories/gems/installed_gems_repository.cc1
-rw-r--r--paludis/set_file.cc12
-rw-r--r--paludis/util/files.m41
-rw-r--r--paludis/util/output_wrapper_TEST.cc123
-rw-r--r--paludis/util/pstream.cc209
-rw-r--r--paludis/util/pstream.hh236
-rw-r--r--paludis/util/pstream_TEST.cc122
-rw-r--r--paludis/util/system.cc379
-rw-r--r--paludis/util/system.hh21
-rw-r--r--paludis/util/system_TEST.cc141
-rwxr-xr-xpaludis/util/system_TEST_setup.sh30
-rw-r--r--src/clients/gtkpaludis/libgtkpaludis/messages_page.cc2
-rw-r--r--src/clients/gtkpaludis/libgtkpaludis/task_window.cc2
19 files changed, 605 insertions, 757 deletions
diff --git a/paludis/environments/paludis/bashable_conf.cc b/paludis/environments/paludis/bashable_conf.cc
index 595053d..e96148a 100644
--- a/paludis/environments/paludis/bashable_conf.cc
+++ b/paludis/environments/paludis/bashable_conf.cc
@@ -20,10 +20,10 @@
#include "bashable_conf.hh"
#include <paludis/util/config_file.hh>
#include <paludis/util/fs_entry.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/is_file_with_extension.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/log.hh>
+#include <paludis/util/system.hh>
using namespace paludis;
using namespace paludis::paludis_environment;
@@ -37,17 +37,19 @@ paludis::paludis_environment::make_bashable_conf(const FSEntry & f)
if (is_file_with_extension(f, ".bash", IsFileWithOptions()))
{
+ std::stringstream s;
Command cmd(Command("bash '" + stringify(f) + "'")
.with_setenv("PALUDIS_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
.with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
- .with_stderr_prefix(f.basename() + "> "));
- PStream s(cmd);
+ .with_stderr_prefix(f.basename() + "> ")
+ .with_captured_stdout_stream(&s));
+ int exit_status(run_command(cmd));
result.reset(new LineConfigFile(s, LineConfigFileOptions()));
- if (s.exit_status() != 0)
+ if (exit_status != 0)
{
Log::get_instance()->message(ll_warning, lc_context, "Script '" + stringify(f)
- + "' returned non-zero exit status '" + stringify(s.exit_status()) + "'");
+ + "' returned non-zero exit status '" + stringify(exit_status) + "'");
result.reset();
}
}
diff --git a/paludis/environments/paludis/paludis_config.cc b/paludis/environments/paludis/paludis_config.cc
index 652c6e1..4310b3a 100644
--- a/paludis/environments/paludis/paludis_config.cc
+++ b/paludis/environments/paludis/paludis_config.cc
@@ -32,7 +32,6 @@
#include <paludis/util/fs_entry.hh>
#include <paludis/util/is_file_with_extension.hh>
#include <paludis/util/log.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/sr.hh>
#include <paludis/util/set.hh>
@@ -148,17 +147,19 @@ namespace paludis
kv.reset(new KeyValueConfigFile(FSEntry(config_dir) / "environment.conf", KeyValueConfigFileOptions()));
else if ((FSEntry(config_dir) / "environment.bash").exists())
{
+ std::stringstream s;
Command cmd(Command("bash '" + stringify(FSEntry(config_dir) / "environment.bash") + "'")
.with_setenv("PALUDIS_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
.with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
- .with_stderr_prefix("environment.bash> "));
- PStream s(cmd);
+ .with_stderr_prefix("environment.bash> ")
+ .with_captured_stdout_stream(&s));
+ int exit_status(run_command(cmd));
kv.reset(new KeyValueConfigFile(s, KeyValueConfigFileOptions()));
- if (s.exit_status() != 0)
+ if (exit_status != 0)
{
Log::get_instance()->message(ll_warning, lc_context, "Script '" + stringify(FSEntry(config_dir) / "environment.bash")
- + "' returned non-zero exit status '" + stringify(s.exit_status()) + "'");
+ + "' returned non-zero exit status '" + stringify(exit_status) + "'");
kv.reset();
}
}
@@ -300,13 +301,18 @@ PaludisConfig::PaludisConfig(PaludisEnvironment * const e, const std::string & s
}
else if ((local_config_dir / "repository_defaults.bash").exists())
{
+ std::stringstream s;
Command cmd(Command("bash '" + stringify(local_config_dir / "repository_defaults.bash") + "'")
.with_setenv("PALUDIS_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
.with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
- .with_stderr_prefix("repository_defaults.bash> "));
- PStream s(cmd);
+ .with_stderr_prefix("repository_defaults.bash> ")
+ .with_captured_stdout_stream(&s));
+ int exit_status(run_command(cmd));
KeyValueConfigFile defaults_file(s, KeyValueConfigFileOptions(), KeyValueConfigFile::Defaults(conf_vars));
std::copy(defaults_file.begin(), defaults_file.end(), conf_vars->inserter());
+ if (exit_status != 0)
+ Log::get_instance()->message(ll_warning, lc_context, "Script '" + stringify(local_config_dir / "repository_defaults.bash")
+ + "' returned non-zero exit status '" + stringify(exit_status) + "'");
}
std::list<FSEntry> dirs;
@@ -334,17 +340,19 @@ PaludisConfig::PaludisConfig(PaludisEnvironment * const e, const std::string & s
tr1::shared_ptr<KeyValueConfigFile> kv;
if (is_file_with_extension(*repo_file, ".bash", IsFileWithOptions()))
{
+ std::stringstream s;
Command cmd(Command("bash '" + stringify(*repo_file) + "'")
.with_setenv("PALUDIS_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
.with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
- .with_stderr_prefix(repo_file->basename() + "> "));
- PStream s(cmd);
+ .with_stderr_prefix(repo_file->basename() + "> ")
+ .with_captured_stdout_stream(&s));
+ int exit_status(run_command(cmd));
kv.reset(new KeyValueConfigFile(s, KeyValueConfigFileOptions(), KeyValueConfigFile::Defaults(conf_vars)));
- if (s.exit_status() != 0)
+ if (exit_status != 0)
{
Log::get_instance()->message(ll_warning, lc_context, "Script '" + stringify(*repo_file)
- + "' returned non-zero exit status '" + stringify(s.exit_status()) + "'");
+ + "' returned non-zero exit status '" + stringify(exit_status) + "'");
kv.reset();
}
}
diff --git a/paludis/hooker.cc b/paludis/hooker.cc
index 1a2e4d9..14355df 100644
--- a/paludis/hooker.cc
+++ b/paludis/hooker.cc
@@ -32,7 +32,6 @@
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/strip.hh>
#include <paludis/util/graph-impl.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/tokeniser.hh>
#include <paludis/util/mutex.hh>
#include <paludis/about.hh>
@@ -159,10 +158,11 @@ BashHookFile::run(const Hook & hook) const
std::string output("");
if (hook.output_dest == hod_grab)
{
- PStream s(cmd);
+ std::stringstream s;
+ cmd.with_captured_stdout_stream(&s);
+ exit_status = run_command(cmd);
output = strip_trailing(std::string((std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>()),
" \t\n");
- exit_status = s.exit_status();
}
else
exit_status = run_command(cmd);
@@ -210,10 +210,10 @@ FancyHookFile::run(const Hook & hook) const
std::string output("");
if (hook.output_dest == hod_grab)
{
- PStream s(cmd);
+ std::stringstream s;
+ exit_status = run_command(cmd.with_captured_stdout_stream(&s));
output = strip_trailing(std::string((std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>()),
" \t\n");
- exit_status = s.exit_status();
}
else
exit_status = run_command(cmd);
@@ -265,10 +265,13 @@ FancyHookFile::_add_dependency_class(const Hook & hook, DirectedGraph<std::strin
for (Hook::ConstIterator x(hook.begin()), x_end(hook.end()) ; x != x_end ; ++x)
cmd.with_setenv(x->first, x->second);
- PStream s(cmd);
+ std::stringstream s;
+ cmd
+ .with_captured_stdout_stream(&s);
+ int exit_status(run_command(cmd));
+
std::string deps((std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>());
- int exit_status(s.exit_status());
if (0 == exit_status)
{
Log::get_instance()->message(ll_debug, lc_no_context, "Hook dependencies for '" + stringify(file_name())
diff --git a/paludis/repositories/e/ebuild.cc b/paludis/repositories/e/ebuild.cc
index f84b036..35284cc 100644
--- a/paludis/repositories/e/ebuild.cc
+++ b/paludis/repositories/e/ebuild.cc
@@ -25,7 +25,6 @@
#include <paludis/util/system.hh>
#include <paludis/util/strip.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/log.hh>
#include <paludis/util/sequence.hh>
#include <paludis/util/options.hh>
@@ -269,7 +268,9 @@ EbuildMetadataCommand::do_run_command(const Command & cmd)
{
Context context("When running ebuild command to generate metadata for '" + stringify(*params.package_id) + "':");
- PStream prog(cmd);
+ std::stringstream prog;
+ Command real_cmd(cmd);
+ int exit_status(run_command(real_cmd.with_captured_stdout_stream(&prog)));
input.assign((std::istreambuf_iterator<char>(prog)), std::istreambuf_iterator<char>());
std::stringstream input_stream(input);
KeyValueConfigFile f(input_stream, KeyValueConfigFileOptions() + kvcfo_disallow_continuations + kvcfo_disallow_comments
@@ -277,7 +278,7 @@ EbuildMetadataCommand::do_run_command(const Command & cmd)
+ kvcfo_disallow_variables + kvcfo_preserve_whitespace);
std::copy(f.begin(), f.end(), keys->inserter());
- if (0 == prog.exit_status())
+ if (0 == exit_status)
ok = true;
}
catch (const Exception & e)
@@ -433,12 +434,14 @@ EbuildVariableCommand::extend_command(const Command & cmd)
bool
EbuildVariableCommand::do_run_command(const Command & cmd)
{
- PStream prog(cmd);
+ std::stringstream prog;
+ Command real_cmd(cmd);
+ int exit_status(run_command(real_cmd.with_captured_stdout_stream(&prog)));
_result = strip_trailing_string(
std::string((std::istreambuf_iterator<char>(prog)),
std::istreambuf_iterator<char>()), "\n");
- return (0 == prog.exit_status());
+ return (0 == exit_status);
}
std::string
diff --git a/paludis/repositories/e/ebuild/ebuild.bash b/paludis/repositories/e/ebuild/ebuild.bash
index 95bcf34..260b503 100755
--- a/paludis/repositories/e/ebuild/ebuild.bash
+++ b/paludis/repositories/e/ebuild/ebuild.bash
@@ -221,7 +221,7 @@ ebuild_scrub_environment()
echo "\${!${PALUDIS_CLIENT_UPPER}_CMDLINE_*} ${PALUDIS_CLIENT_UPPER}_OPTIONS" )
unset -v PALUDIS_CLIENT
- unset -v PALUDIS_HOME PALUDIS_PID ROOT
+ unset -v PALUDIS_HOME PALUDIS_PID PALUDIS_PIPE_COMMAND_WRITE_FD PALUDIS_PIPE_COMMAND_READ_FD ROOT
unset -v CATEGORY PN PV P PVR PF ${!LD_*}
unset -v ebuild EBUILD
diff --git a/paludis/repositories/e/vdb_repository.cc b/paludis/repositories/e/vdb_repository.cc
index eeda341..bc01291 100644
--- a/paludis/repositories/e/vdb_repository.cc
+++ b/paludis/repositories/e/vdb_repository.cc
@@ -57,7 +57,6 @@
#include <paludis/util/fs_entry.hh>
#include <paludis/util/is_file_with_extension.hh>
#include <paludis/util/log.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/set.hh>
#include <paludis/util/sequence.hh>
#include <paludis/util/map.hh>
@@ -778,12 +777,14 @@ VDBRepository::get_environment_variable(
}
else if ((vdb_dir / "environment.bz2").is_regular_file_or_symlink_to_regular_file())
{
- PStream p("bash -c '( bunzip2 < " + stringify(vdb_dir / "environment.bz2" ) +
- " ; echo echo \\$" + var + " ) | bash 2>/dev/null'");
+ std::stringstream p;
+ Command cmd(Command("bash -c '( bunzip2 < " + stringify(vdb_dir / "environment.bz2" ) +
+ " ; echo echo \\$" + var + " ) | bash 2>/dev/null'").with_captured_stdout_stream(&p));
+ int exit_status(run_command(cmd));
std::string result(strip_trailing_string(std::string(
(std::istreambuf_iterator<char>(p)),
std::istreambuf_iterator<char>()), "\n"));
- if (0 != p.exit_status())
+ if (0 != exit_status)
throw ActionError("Could not load environment.bz2");
return result;
}
diff --git a/paludis/repositories/gems/installed_gems_repository.cc b/paludis/repositories/gems/installed_gems_repository.cc
index c7dc591..0feed97 100644
--- a/paludis/repositories/gems/installed_gems_repository.cc
+++ b/paludis/repositories/gems/installed_gems_repository.cc
@@ -30,7 +30,6 @@
#include <paludis/util/sequence.hh>
#include <paludis/util/is_file_with_extension.hh>
#include <paludis/util/make_shared_ptr.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/visitor-impl.hh>
#include <paludis/util/system.hh>
#include <paludis/util/mutex.hh>
diff --git a/paludis/set_file.cc b/paludis/set_file.cc
index b9a7edb..ef45828 100644
--- a/paludis/set_file.cc
+++ b/paludis/set_file.cc
@@ -21,13 +21,13 @@
#include <paludis/util/fs_entry.hh>
#include <paludis/util/log.hh>
#include <paludis/util/tokeniser.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/sequence.hh>
#include <paludis/util/visitor-impl.hh>
#include <paludis/util/options.hh>
#include <paludis/util/mutex.hh>
#include <paludis/util/config_file.hh>
+#include <paludis/util/system.hh>
#include <paludis/environment.hh>
#include <paludis/query.hh>
#include <paludis/package_database.hh>
@@ -421,14 +421,16 @@ PaludisBashHandler::PaludisBashHandler(const SetFileParams & p) :
Context context("When loading paludis bash set file '" + stringify(_p.file_name) + "':");
_contents.reset(new ConstTreeSequence<SetSpecTree, AllDepSpec>(tr1::shared_ptr<AllDepSpec>(new AllDepSpec)));
+ std::stringstream s;
Command cmd(Command("bash '" + stringify(_p.file_name) + "'")
.with_setenv("ROOT", _p.environment ? stringify(_p.environment->root()) : "/")
.with_setenv("SET", stringify(_p.file_name))
.with_setenv("SET_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
.with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
.with_setenv("PALUDIS_COMMAND", _p.environment ? _p.environment->paludis_command() : "")
- .with_stderr_prefix(_p.file_name.basename() + "> "));
- PStream s(cmd);
+ .with_stderr_prefix(_p.file_name.basename() + "> ")
+ .with_captured_stdout_stream(&s));
+ int exit_status(run_command(cmd));
LineConfigFile ff(s, LineConfigFileOptions() + lcfo_disallow_continuations + lcfo_disallow_comments
+ lcfo_no_skip_blank_lines);
@@ -436,10 +438,10 @@ PaludisBashHandler::PaludisBashHandler(const SetFileParams & p) :
line != line_end ; ++line)
do_one_conf_line(*line, _contents, _p);
- if (s.exit_status() != 0)
+ if (exit_status != 0)
{
Log::get_instance()->message(ll_warning, lc_context, "Set file script '" + stringify(_p.file_name) +
- "' returned non-zero exit status '" + stringify(s.exit_status()) + "'");
+ "' returned non-zero exit status '" + stringify(exit_status) + "'");
_contents.reset(new ConstTreeSequence<SetSpecTree, AllDepSpec>(tr1::shared_ptr<AllDepSpec>(new AllDepSpec)));
}
}
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index 2b21b3e..8825e6f 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -40,7 +40,6 @@ add(`options', `hh', `fwd', `cc', `test')
add(`output_wrapper', `test', `testscript')
add(`pipe', `hh', `cc')
add(`private_implementation_pattern', `hh', `impl')
-add(`pstream', `hh', `cc', `test')
add(`random', `hh', `cc', `test')
add(`remove_shared_ptr', `hh')
add(`rmd160', `hh', `cc', `test')
diff --git a/paludis/util/output_wrapper_TEST.cc b/paludis/util/output_wrapper_TEST.cc
index 9828b29..e9da796 100644
--- a/paludis/util/output_wrapper_TEST.cc
+++ b/paludis/util/output_wrapper_TEST.cc
@@ -20,7 +20,6 @@
#include <test/test_framework.hh>
#include <test/test_runner.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/system.hh>
#include <paludis/util/join.hh>
@@ -39,11 +38,12 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' -- "
- "bash output_wrapper_TEST_dir/stdout_prefix.bash"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(run_command(Command("./outputwrapper --stdout-prefix 'o p ' -- "
+ "bash output_wrapper_TEST_dir/stdout_prefix.bash")
+ .with_captured_stdout_stream(&p)), 0);
std::string s((std::istreambuf_iterator<char>(p)), std::istreambuf_iterator<char>());
TEST_CHECK_EQUAL(s, "o p one\no p two\no p three\n");
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_stdout_prefix;
@@ -53,11 +53,12 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stderr-prefix 'e p ' -- "
- "bash output_wrapper_TEST_dir/stderr_prefix.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stderr-prefix 'e p ' -- "
+ "bash output_wrapper_TEST_dir/stderr_prefix.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::string s((std::istreambuf_iterator<char>(p)), std::istreambuf_iterator<char>());
TEST_CHECK_EQUAL(s, "e p one\ne p two\ne p three\n");
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_stderr_prefix;
@@ -67,8 +68,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
- "bash output_wrapper_TEST_dir/mixed_prefix.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
+ "bash output_wrapper_TEST_dir/mixed_prefix.bash 2>&1")
+ .with_captured_stdout_stream(&p)), 0);
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -79,7 +82,6 @@ namespace test_cases
TEST_CHECK(lines.count("e p one"));
TEST_CHECK(lines.count("e p three"));
TEST_CHECK(lines.count("o p two"));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_mixed_prefix;
@@ -89,7 +91,9 @@ namespace test_cases
void run()
{
- PStream p(Command("bash output_wrapper_TEST_dir/long_lines.bash"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(run_command(Command("bash output_wrapper_TEST_dir/long_lines.bash")
+ .with_captured_stdout_stream(&p)), 0);
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -99,7 +103,6 @@ namespace test_cases
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(2));
TEST_CHECK(lines.count("e p " + std::string(10000, 'e')));
TEST_CHECK(lines.count("o p " + std::string(10000, 'o')));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_long_lines;
@@ -109,7 +112,9 @@ namespace test_cases
void run()
{
- PStream p(Command("bash output_wrapper_TEST_dir/no_trailing_newlines.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("bash output_wrapper_TEST_dir/no_trailing_newlines.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -118,7 +123,6 @@ namespace test_cases
TestMessageSuffix s("lines=(" + join(lines.begin(), lines.end(), ",") + ")");
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(1));
TEST_CHECK(lines.count("o p monkeye p pants"));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_no_trailing_newline;
@@ -128,8 +132,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
- "bash output_wrapper_TEST_dir/exit_status.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(5, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
+ "bash output_wrapper_TEST_dir/exit_status.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -139,7 +145,6 @@ namespace test_cases
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(2));
TEST_CHECK(lines.count("o p lorem ipsum dolor"));
TEST_CHECK(lines.count("e p sit amet"));
- TEST_CHECK_EQUAL(5, p.exit_status());
}
} test_exit_status;
@@ -149,8 +154,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
- "bash output_wrapper_TEST_dir/no_wrap_blanks.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
+ "bash output_wrapper_TEST_dir/no_wrap_blanks.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -162,7 +169,6 @@ namespace test_cases
TEST_CHECK(lines.count("e p three"));
TEST_CHECK(lines.count("o p two"));
TEST_CHECK_EQUAL(lines.count(""), static_cast<std::size_t>(4));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_no_wrap_blanks;
@@ -172,8 +178,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/wrap_blanks.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/wrap_blanks.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -186,7 +194,6 @@ namespace test_cases
TEST_CHECK(lines.count("o p two"));
TEST_CHECK_EQUAL(lines.count("e p "), static_cast<std::size_t>(2));
TEST_CHECK_EQUAL(lines.count("o p "), static_cast<std::size_t>(2));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_wrap_blanks;
@@ -196,8 +203,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
- "bash output_wrapper_TEST_dir/discard_blank_output.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
+ "bash output_wrapper_TEST_dir/discard_blank_output.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -205,7 +214,6 @@ namespace test_cases
TestMessageSuffix s("lines=(" + join(lines.begin(), lines.end(), ",") + ")");
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(0));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_discard_blank_output;
@@ -215,8 +223,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
- "bash output_wrapper_TEST_dir/discard_blank_output_not_blank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
+ "bash output_wrapper_TEST_dir/discard_blank_output_not_blank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -226,7 +236,6 @@ namespace test_cases
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(4));
TEST_CHECK(lines.count("o p monkey"));
TEST_CHECK_EQUAL(lines.count(""), static_cast<std::size_t>(3));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_discard_blank_output_not_blank;
@@ -236,8 +245,11 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/discard_wrap_blank_output.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command(
+ "./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/discard_wrap_blank_output.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -245,7 +257,6 @@ namespace test_cases
TestMessageSuffix s("lines=(" + join(lines.begin(), lines.end(), ",") + ")");
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(0));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_discard_wrap_blank_output;
@@ -255,8 +266,11 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/discard_wrap_blank_output_not_blank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(
+ Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/discard_wrap_blank_output_not_blank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -266,7 +280,6 @@ namespace test_cases
TEST_CHECK_EQUAL(lines.size(), static_cast<std::size_t>(4));
TEST_CHECK(lines.count("o p monkey"));
TEST_CHECK_EQUAL(lines.count("o p "), static_cast<std::size_t>(3));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_discard_wrap_blank_output_not_blank;
@@ -276,8 +289,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
- "bash output_wrapper_TEST_dir/carriage_return.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' -- "
+ "bash output_wrapper_TEST_dir/carriage_return.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -299,7 +314,6 @@ namespace test_cases
TEST_CHECK(lines.count("e p foo\\r\\re p bar"));
TEST_CHECK(lines.count("\\re p foo"));
TEST_CHECK_EQUAL(lines.count("\\r"), static_cast<std::size_t>(2));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_carriage_return;
@@ -309,8 +323,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/carriage_return.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/carriage_return.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -333,7 +349,6 @@ namespace test_cases
TEST_CHECK(lines.count("e p foo\\re p \\re p bar"));
TEST_CHECK(lines.count("e p \\re p foo"));
TEST_CHECK(lines.count("e p \\re p "));
- TEST_CHECK_EQUAL(0, p.exit_status());
}
} test_carriage_return_wrap_blank;
@@ -343,8 +358,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
- "bash output_wrapper_TEST_dir/carriage_return_blank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
+ "bash output_wrapper_TEST_dir/carriage_return_blank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -366,8 +383,11 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/carriage_return_blank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(
+ Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/carriage_return_blank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -389,8 +409,10 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
- "bash output_wrapper_TEST_dir/carriage_return_nonblank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output -- "
+ "bash output_wrapper_TEST_dir/carriage_return_nonblank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
@@ -415,8 +437,11 @@ namespace test_cases
void run()
{
- PStream p(Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
- "bash output_wrapper_TEST_dir/carriage_return_nonblank.bash 2>&1"));
+ std::stringstream p;
+ TEST_CHECK_EQUAL(0, run_command(
+ Command("./outputwrapper --stdout-prefix 'o p ' --stderr-prefix 'e p ' --discard-blank-output --wrap-blanks -- "
+ "bash output_wrapper_TEST_dir/carriage_return_nonblank.bash 2>&1")
+ .with_captured_stdout_stream(&p)));
std::multiset<std::string> lines;
std::string line;
while (std::getline(p, line))
diff --git a/paludis/util/pstream.cc b/paludis/util/pstream.cc
deleted file mode 100644
index 946c715..0000000
--- a/paludis/util/pstream.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/* vim: set sw=4 sts=4 et foldmethod=syntax : */
-
-/*
- * Copyright (c) 2006, 2007 Ciaran McCreesh
- *
- * This file is part of the Paludis package manager. Paludis is free software;
- * you can redistribute it and/or modify it under the terms of the GNU General
- * Public License version 2, as published by the Free Software Foundation.
- *
- * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <paludis/util/log.hh>
-#include <paludis/util/pstream.hh>
-#include <paludis/util/stringify.hh>
-#include <paludis/util/wrapped_forward_iterator.hh>
-
-#include <cstring>
-#include <iostream>
-#include <errno.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <grp.h>
-
-using namespace paludis;
-
-PStreamError::PStreamError(const std::string & our_message) throw () :
- Exception(our_message)
-{
-}
-
-PStreamInBuf::int_type
-PStreamInBuf::underflow()
-{
- if (gptr() < egptr())
- return *gptr();
-
- int num_putback = gptr() - eback();
- if (num_putback > putback_size)
- num_putback = putback_size;
- std::memmove(buffer + putback_size - num_putback,
- gptr() - num_putback, num_putback);
-
- ssize_t n = read(fd, buffer + putback_size, buffer_size - putback_size);
- if (n == 0)
- return EOF;
- else if (n < 0)
- throw PStreamError("read returned error " + stringify(strerror(errno)) + ", fd is " + stringify(fd));
-
- setg(buffer + putback_size - num_putback, buffer + putback_size, buffer + putback_size + n);
-
- return *gptr();
-}
-
-PStreamInBuf::PStreamInBuf(const Command & cmd) :
- _command(cmd)
-{
- Context context("When running command '" + stringify(cmd.command()) + "' asynchronously:");
-
- std::string extras;
-
- if (! cmd.chdir().empty())
- extras.append(" [chdir " + cmd.chdir() + "]");
-
- for (Command::ConstIterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
- extras.append(" [setenv " + s->first + "=" + s->second + "]");
-
- if (cmd.gid() && *cmd.gid() != getgid())
- extras.append(" [setgid " + stringify(*cmd.gid()) + "]");
-
- if (cmd.uid() && *cmd.uid() != getuid())
- extras.append(" [setuid " + stringify(*cmd.uid()) + "]");
-
- extras.append(" [stdout_pipe " + stringify(stdout_pipe.read_fd()) + ", " + stringify(stdout_pipe.write_fd()) + "]");
-
- std::string c(cmd.command());
-
- if ((! cmd.stdout_prefix().empty()) || (! cmd.stderr_prefix().empty()))
- c = getenv_with_default("PALUDIS_OUTPUTWRAPPER_DIR", LIBEXECDIR "/paludis/utils") + "/outputwrapper --stdout-prefix '"
- + cmd.stdout_prefix() + "' --stderr-prefix '" + cmd.stderr_prefix() + "' "
- + (cmd.prefix_discard_blank_output() ? " --discard-blank-output " : "")
- + (cmd.prefix_blank_lines() ? " --wrap-blanks " : "")
- + " -- " + c;
-
- cmd.echo_to_stderr();
- Log::get_instance()->message(ll_debug, lc_context, "execl /bin/sh -c " + c + " " + extras);
-
- child = fork();
-
- if (0 == child)
- {
- try
- {
- if (! cmd.chdir().empty())
- if (-1 == chdir(cmd.chdir().c_str()))
- throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
-
- for (Command::ConstIterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
- setenv(s->first.c_str(), s->second.c_str(), 1);
-
- if (-1 == dup2(stdout_pipe.write_fd(), 1))
- throw PStreamError("dup2 failed");
- close(stdout_pipe.read_fd());
-
- if (-1 != PStream::stderr_fd)
- {
- if (-1 == dup2(PStream::stderr_fd, 2))
- throw PStreamError("dup2 failed");
-
- if (-1 != PStream::stderr_close_fd)
- close(PStream::stderr_close_fd);
- }
-
- if (cmd.gid() && *cmd.gid() != getgid())
- {
- gid_t g(*cmd.gid());
-
- if (0 != ::setgid(*cmd.gid()))
- std::cerr << "setgid(" << *cmd.gid() << ") failed for exec of '" << c << "': "
- << strerror(errno) << std::endl;
- else if (0 != ::setgroups(1, &g))
- std::cerr << "setgroups failed for exec of '" << c << "': " << strerror(errno) << std::endl;
- }
-
- if (cmd.uid() && *cmd.uid() != getuid())
- if (0 != ::setuid(*cmd.uid()))
- std::cerr << "setuid(" << *cmd.uid() << ") failed for exec of '" << c << "': "
- << strerror(errno) << std::endl;
-
- execl("/bin/sh", "sh", "-c", c.c_str(), static_cast<char *>(0));
- throw PStreamError("execl /bin/sh -c '" + c + "' failed:"
- + stringify(strerror(errno)));
- }
- catch (const Exception & e)
- {
- std::cerr << "exec of '" << c << "' failed due to exception '" << e.message()
- << "' (" << e.what() << ")" << std::endl;
- exit(123);
- }
- catch (...)
- {
- std::cerr << "exec of '" << c << "' failed due to unknown exception" << std::endl;
- exit(124);
- }
- }
- else if (-1 == child)
- throw PStreamError("fork failed: " + stringify(strerror(errno)));
- else
- {
- close(stdout_pipe.write_fd());
- stdout_pipe.clear_write_fd();
- fd = stdout_pipe.read_fd();
- }
-
- setg(buffer + putback_size, buffer + putback_size, buffer + putback_size);
-}
-
-PStreamInBuf::~PStreamInBuf()
-{
- Context context("When destroying PStream process with fd '" + stringify(fd) + "':");
-
- if (0 != fd)
- {
- int fdn(fd), x;
- if (-1 == waitpid(child, &x, 0))
- throw PStreamError("waitpid returned error " + stringify(strerror(errno)) + ", fd is " + stringify(fd));
- Log::get_instance()->message(ll_debug, lc_context) << "waitpid " << fdn << " for destructor -> " <<
- (WIFSIGNALED(x) ? "signal " + stringify(WTERMSIG(x) + 128) : "exit status " + stringify(WEXITSTATUS(x)));
- }
-}
-
-int
-PStreamInBuf::exit_status()
-{
- Context context("When requesting exit status for PStream process with fd '" + stringify(fd) + "':");
- if (0 != fd)
- {
- int fdn(fd);
- if (-1 == waitpid(child, &_exit_status, 0))
- throw PStreamError("waitpid returned error " + stringify(strerror(errno)) + ", fd is " + stringify(fd));
- fd = 0;
- Log::get_instance()->message(ll_debug, lc_context) << "waitpid " << fdn << " for exit_status() -> " <<
- (WIFSIGNALED(_exit_status) ? "signal " + stringify(WTERMSIG(_exit_status) + 128) : "exit status " + stringify(WEXITSTATUS(_exit_status)));
- }
- return WIFSIGNALED(_exit_status) ? WTERMSIG(_exit_status) + 128 : WEXITSTATUS(_exit_status);
-}
-
-void
-PStream::set_stderr_fd(const int fd, const int fd2)
-{
- _stderr_fd = fd;
- _stderr_close_fd = fd2;
-}
-
-int PStream::_stderr_fd(-1);
-const int & PStream::stderr_fd(_stderr_fd);
-
-int PStream::_stderr_close_fd(-1);
-const int & PStream::stderr_close_fd(_stderr_close_fd);
-
diff --git a/paludis/util/pstream.hh b/paludis/util/pstream.hh
deleted file mode 100644
index 6bdda2c..0000000
--- a/paludis/util/pstream.hh
+++ /dev/null
@@ -1,236 +0,0 @@
-/* vim: set sw=4 sts=4 et foldmethod=syntax : */
-
-/*
- * Copyright (c) 2006, 2007 Ciaran McCreesh
- *
- * This file is part of the Paludis package manager. Paludis is free software;
- * you can redistribute it and/or modify it under the terms of the GNU General
- * Public License version 2, as published by the Free Software Foundation.
- *
- * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef PALUDIS_GUARD_PALUDIS_PSTREAM_HH
-#define PALUDIS_GUARD_PALUDIS_PSTREAM_HH 1
-
-#include <cstdio>
-#include <istream>
-#include <limits>
-#include <paludis/util/exception.hh>
-#include <paludis/util/instantiation_policy.hh>
-#include <paludis/util/pipe.hh>
-#include <paludis/util/system.hh>
-#include <streambuf>
-#include <string>
-
-/** \file
- * Declarations for the PStream and PStreamInBuf classes, and related
- * utilities.
- *
- * \ingroup g_system
- *
- * \section Examples
- *
- * - None at this time.
- */
-
-namespace paludis
-{
- /**
- * Thrown if a PStream or PStreamInBuf encounters an error.
- *
- * \ingroup g_system
- * \ingroup g_exceptions
- * \nosubgrouping
- */
- class PALUDIS_VISIBLE PStreamError :
- public Exception
- {
- public:
- ///\name Basic operations
- ///\{
-
- PStreamError(const std::string & message) throw ();
-
- ///\}
- };
-
- /**
- * Input buffer class for a process, invoked using popen(3).
- *
- * Bidirectional I/O isn't supported since we haven't needed it yet, and
- * because popen on Linux is unidirectional.
- *
- * See \ref TCppSL Ch. 13.13 for what we're doing here. The buffer code is
- * based upon the "io/inbuf1.hpp" example in section 13.13.3.
- *
- * \ingroup g_system
- * \nosubgrouping
- */
- class PALUDIS_VISIBLE PStreamInBuf :
- public std::streambuf,
- private InstantiationPolicy<PStreamInBuf, instantiation_method::NonCopyableTag>
- {
- private:
- Pipe stdout_pipe;
-
- Command _command;
-
- int _exit_status;
-
- pid_t child;
-
- protected:
- /**
- * Our file descriptor.
- */
- int fd;
-
- /**
- * At most how many characters can we put back?
- */
- static const int putback_size = std::numeric_limits<unsigned>::digits >> 3;
-
- /**
- * How large is our internal buffer?
- */
- static const int buffer_size = 3 * putback_size;
-
- /**
- * Internal buffer.
- */
- char buffer[buffer_size];
-
- /**
- * Called when an underflow occurs.
- */
- virtual int_type underflow();
-
- public:
- ///\name Basic operations
- ///\{
-
- /**
- * Constructor.
- *
- * \param command The command to run. See PStream for discussion.
- */
- PStreamInBuf(const Command & command);
-
- ~PStreamInBuf();
-
- ///\}
-
- /**
- * What was our command?
- */
- const Command & command() const
- {
- return _command;
- }
-
- /**
- * What is our exit status?
- */
- int exit_status();
- };
-
- /**
- * For internal use by PStream classes.
- *
- * \ingroup g_system
- */
- namespace pstream_internals
- {
- /**
- * Avoid base from member issues for PStream.
- *
- * \ingroup g_system
- */
- struct PALUDIS_VISIBLE PStreamInBufBase :
- private paludis::InstantiationPolicy<PStreamInBufBase, instantiation_method::NonCopyableTag>
- {
- /**
- * Our buffer.
- */
- PStreamInBuf buf;
-
- /**
- * Constructor.
- */
- PStreamInBufBase(const Command & command) :
- buf(command)
- {
- }
- };
- }
-
- /**
- * A PStream class is a standard input stream class whose contents comes
- * from the output of an executed command.
- *
- * \ingroup g_system
- * \nosubgrouping
- */
- class PALUDIS_VISIBLE PStream :
- private InstantiationPolicy<PStream, instantiation_method::NonCopyableTag>,
- protected pstream_internals::PStreamInBufBase,
- public std::istream
- {
- private:
- static int _stderr_fd;
- static int _stderr_close_fd;
-
- public:
- ///\name Basic operations
- ///\{
-
- /**
- * Constructor.
- *
- * \param command The command to execute. PATH is used, so there is
- * usually no need to specify a full path. Arguments can be passed
- * as part of the command.
- */
- PStream(const Command & command) :
- PStreamInBufBase(command),
- std::istream(&buf)
- {
- }
-
- ///\}
-
- /**
- * What is our exit status?
- */
- int exit_status()
- {
- return buf.exit_status();
- }
-
- /**
- * Set a file descriptors to use for stderr and close on stderr
- * (for all PStream instances).
- */
- static void set_stderr_fd(const int, const int);
-
- /**
- * File descriptor to use for stderr.
- */
- static const int & stderr_fd;
-
- /**
- * File descriptor to close for stderr.
- */
- static const int & stderr_close_fd;
- };
-}
-
-#endif
diff --git a/paludis/util/pstream_TEST.cc b/paludis/util/pstream_TEST.cc
deleted file mode 100644
index a1b26b9..0000000
--- a/paludis/util/pstream_TEST.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-/* vim: set sw=4 sts=4 et foldmethod=syntax : */
-
-/*
- * Copyright (c) 2006, 2007 Ciaran McCreesh
- *
- * This file is part of the Paludis package manager. Paludis is free software;
- * you can redistribute it and/or modify it under the terms of the GNU General
- * Public License version 2, as published by the Free Software Foundation.
- *
- * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <paludis/util/pstream.hh>
-#include <test/test_framework.hh>
-#include <test/test_runner.hh>
-
-using namespace paludis;
-using namespace test;
-
-/** \file
- * Tests for PStream.
- *
- */
-
-namespace test_cases
-{
- /**
- * \test Test PStream on a normal command.
- *
- */
- struct PStreamTest : TestCase
- {
- PStreamTest() : TestCase("pstream") { }
-
- void run()
- {
- PStream * p;
- TEST_CHECK((p = new PStream("echo hi")));
- std::string line;
- TEST_CHECK(std::getline(*p, line));
- TEST_CHECK_EQUAL(line, "hi");
- TEST_CHECK(! std::getline(*p, line));
- TEST_CHECK_EQUAL(p->exit_status(), 0);
- delete p;
- }
- } test_pstream;
-
- /**
- * \test Test PStream on a command that doesn't exist.
- *
- */
- struct PStreamNoExistTest : TestCase
- {
- PStreamNoExistTest() : TestCase("pstream nonexistent command") { }
-
- void run()
- {
- PStream p("thiscommanddoesnotexist 2>/dev/null");
- TEST_CHECK(p.exit_status() != 0);
- }
- } test_pstream_no_exist;
-
- /**
- * \test Test PStream on a command that returns a failure with no output.
- *
- */
- struct PStreamSilentFailTest : TestCase
- {
- PStreamSilentFailTest() : TestCase("pstream silent fail") { }
-
- void run()
- {
- PStream p("test -e /doesnotexist");
- TEST_CHECK(p.exit_status() != 0);
- }
- } test_pstream_silent_fail;
-
- /**
- * \test Test PStream on a command that fails with output.
- *
- */
- struct PStreamFailTest : TestCase
- {
- PStreamFailTest() : TestCase("pstream fail") { }
-
- void run()
- {
- PStream * p;
- TEST_CHECK((p = new PStream("cat /doesnotexist 2>&1")));
- std::string line;
- TEST_CHECK(std::getline(*p, line));
- TEST_CHECK(! line.empty());
- TEST_CHECK(! std::getline(*p, line));
- TEST_CHECK(p->exit_status() != 0);
- delete p;
- }
- } test_pstream_fail;
-
- struct PStreamParallelTest : TestCase
- {
- PStreamParallelTest() : TestCase("pstream parallel") { }
-
- void run()
- {
- PStream one("echo one ; sleep 3 ; echo one"),
- two("echo two ; sleep 2 ; echo two "),
- three("echo three ; sleep 1 ; echo three");
-
- TEST_CHECK_EQUAL(std::string((std::istreambuf_iterator<char>(three)), std::istreambuf_iterator<char>()), "three\nthree\n");
- TEST_CHECK_EQUAL(std::string((std::istreambuf_iterator<char>(one)), std::istreambuf_iterator<char>()), "one\none\n");
- TEST_CHECK_EQUAL(std::string((std::istreambuf_iterator<char>(two)), std::istreambuf_iterator<char>()), "two\ntwo\n");
- }
- } test_pstream_parallel;
-}
-
diff --git a/paludis/util/system.cc b/paludis/util/system.cc
index 0c32f9d..1fef385 100644
--- a/paludis/util/system.cc
+++ b/paludis/util/system.cc
@@ -25,10 +25,15 @@
#include <paludis/util/destringify.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/wrapped_forward_iterator-impl.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/fd_output_stream.hh>
+#include <paludis/util/pipe.hh>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <grp.h>
@@ -66,7 +71,7 @@ namespace
}
- static pid_t paludis_pid(get_paludis_pid());
+ static pid_t paludis_pid PALUDIS_ATTRIBUTE((used)) = get_paludis_pid();
}
void
@@ -147,6 +152,8 @@ namespace paludis
std::string stderr_prefix;
bool prefix_discard_blank_output;
bool prefix_blank_lines;
+ tr1::function<std::string (const std::string &)> pipe_command_handler;
+ std::ostream * captured_stdout_stream;
Implementation(const std::string & c,
const std::map<std::string, std::string> & s = (std::map<std::string, std::string>()),
@@ -154,7 +161,9 @@ namespace paludis
tr1::shared_ptr<uid_t> u = tr1::shared_ptr<uid_t>(),
tr1::shared_ptr<gid_t> g = tr1::shared_ptr<gid_t>(),
const std::string & p = "", const std::string & q = "",
- const bool b = false, const bool bb = false) :
+ const bool b = false, const bool bb = false,
+ const tr1::function<std::string (const std::string &)> & h = tr1::function<std::string (const std::string &)>(),
+ std::ostream * cs = 0) :
command(c),
setenv_values(s),
chdir(d),
@@ -164,7 +173,9 @@ namespace paludis
stdout_prefix(p),
stderr_prefix(q),
prefix_discard_blank_output(b),
- prefix_blank_lines(bb)
+ prefix_blank_lines(bb),
+ pipe_command_handler(h),
+ captured_stdout_stream(cs)
{
}
};
@@ -185,7 +196,7 @@ Command::Command(const Command & other) :
other._imp->setenv_values, other._imp->chdir, other._imp->echo_to_stderr,
other._imp->uid, other._imp->gid, other._imp->stdout_prefix, other._imp->stderr_prefix,
other._imp->prefix_discard_blank_output,
- other._imp->prefix_blank_lines))
+ other._imp->prefix_blank_lines, other._imp->pipe_command_handler, other._imp->captured_stdout_stream))
{
}
@@ -201,7 +212,8 @@ Command::operator= (const Command & other)
other._imp->stdout_prefix,
other._imp->stderr_prefix,
other._imp->prefix_discard_blank_output,
- other._imp->prefix_blank_lines));
+ other._imp->prefix_blank_lines,
+ other._imp->pipe_command_handler, other._imp->captured_stdout_stream));
if (other.uid() && other.gid())
with_uid_gid(*other.uid(), *other.gid());
}
@@ -236,6 +248,13 @@ Command::with_uid_gid(const uid_t u, const gid_t g)
}
Command &
+Command::with_captured_stdout_stream(std::ostream * const c)
+{
+ _imp->captured_stdout_stream = c;
+ return *this;
+}
+
+Command &
Command::with_sandbox()
{
#if HAVE_SANDBOX
@@ -296,83 +315,304 @@ paludis::run_command(const Command & cmd)
Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + command
+ " " + extras);
+ tr1::shared_ptr<Pipe> internal_command_reader(new Pipe), pipe_command_reader, pipe_command_response, captured_stdout;
+ if (cmd.pipe_command_handler())
+ {
+ pipe_command_reader.reset(new Pipe);
+ pipe_command_response.reset(new Pipe);
+ }
+ if (cmd.captured_stdout_stream())
+ captured_stdout.reset(new Pipe);
+
pid_t child(fork());
if (0 == child)
{
- try
+ pid_t child_child(fork());
+ if (0 == child_child)
{
- if (! cmd.chdir().empty())
- if (-1 == chdir(stringify(cmd.chdir()).c_str()))
- throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
-
- for (Command::ConstIterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
- setenv(s->first.c_str(), s->second.c_str(), 1);
- setenv("PATH_NOT_CLOBBERED_BY_SANDBOX", getenv_with_default("PATH", "").c_str(), 1);
-
- if (-1 != stdout_write_fd)
+ /* The pid that does the exec */
+ try
{
- if (-1 == dup2(stdout_write_fd, 1))
- throw RunCommandError("dup2 failed: " + stringify(strerror(errno)));
-
- if (-1 != stdout_close_fd)
- close(stdout_close_fd);
+ if (cmd.pipe_command_handler())
+ {
+ close(pipe_command_reader->read_fd());
+ pipe_command_reader->clear_read_fd();
+
+ close(pipe_command_response->write_fd());
+ pipe_command_response->clear_write_fd();
+ }
+
+ if (cmd.captured_stdout_stream())
+ {
+ close(captured_stdout->read_fd());
+ captured_stdout->clear_read_fd();
+ }
+
+ close(internal_command_reader->read_fd());
+ internal_command_reader->clear_read_fd();
+ close(internal_command_reader->write_fd());
+ internal_command_reader->write_fd();
+
+ if (! cmd.chdir().empty())
+ if (-1 == chdir(stringify(cmd.chdir()).c_str()))
+ throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
+
+ for (Command::ConstIterator s(cmd.begin_setenvs()), s_end(cmd.end_setenvs()) ; s != s_end ; ++s)
+ setenv(s->first.c_str(), s->second.c_str(), 1);
+
+ setenv("PATH_NOT_CLOBBERED_BY_SANDBOX", getenv_with_default("PATH", "").c_str(), 1);
+
+ if (cmd.pipe_command_handler())
+ {
+ setenv("PALUDIS_PIPE_COMMAND_WRITE_FD", stringify(pipe_command_reader->write_fd()).c_str(), 1);
+ setenv("PALUDIS_PIPE_COMMAND_READ_FD", stringify(pipe_command_response->read_fd()).c_str(), 1);
+ }
+
+ if (cmd.captured_stdout_stream())
+ {
+ if (-1 == dup2(captured_stdout->write_fd(), 1))
+ throw RunCommandError("dup2 failed: " + stringify(strerror(errno)));
+ }
+ else if (-1 != stdout_write_fd)
+ {
+ if (-1 == dup2(stdout_write_fd, 1))
+ throw RunCommandError("dup2 failed: " + stringify(strerror(errno)));
+
+ if (-1 != stdout_close_fd)
+ close(stdout_close_fd);
+ }
+
+ if (-1 != stderr_write_fd)
+ {
+ if (-1 == dup2(stderr_write_fd, 2))
+ throw RunCommandError("dup2 failed: " + stringify(strerror(errno)));
+
+ if (-1 != stderr_close_fd)
+ close(stderr_close_fd);
+ }
+
+ if (cmd.gid() && *cmd.gid() != getgid())
+ {
+ gid_t g(*cmd.gid());
+
+ if (0 != ::setgid(*cmd.gid()))
+ std::cerr << "setgid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
+ << strerror(errno) << std::endl;
+ else if (0 != ::setgroups(1, &g))
+ std::cerr << "setgroups failed for exec of '" << command << "': " << strerror(errno) << std::endl;
+ }
+
+ if (cmd.uid() && *cmd.uid() != getuid())
+ if (0 != ::setuid(*cmd.uid()))
+ std::cerr << "setuid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
+ << strerror(errno) << std::endl;
+
+ execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char *>(0));
+ throw RunCommandError("execl /bin/sh -c '" + command + "' failed:"
+ + stringify(strerror(errno)));
}
-
- if (-1 != stderr_write_fd)
+ catch (const Exception & e)
{
- if (-1 == dup2(stderr_write_fd, 2))
- throw RunCommandError("dup2 failed: " + stringify(strerror(errno)));
-
- if (-1 != stderr_close_fd)
- close(stderr_close_fd);
+ std::cerr << "exec of '" << command << "' failed due to exception '" << e.message()
+ << "' (" << e.what() << ")" << std::endl;
+ exit(123);
}
-
- if (cmd.gid() && *cmd.gid() != getgid())
+ catch (...)
{
- gid_t g(*cmd.gid());
-
- if (0 != ::setgid(*cmd.gid()))
- std::cerr << "setgid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
- << strerror(errno) << std::endl;
- else if (0 != ::setgroups(1, &g))
- std::cerr << "setgroups failed for exec of '" << command << "': " << strerror(errno) << std::endl;
+ std::cerr << "exec of '" << command << "' failed due to unknown exception" << std::endl;
+ exit(124);
}
-
- if (cmd.uid() && *cmd.uid() != getuid())
- if (0 != ::setuid(*cmd.uid()))
- std::cerr << "setuid(" << *cmd.uid() << ") failed for exec of '" << command << "': "
- << strerror(errno) << std::endl;
-
- execl("/bin/sh", "sh", "-c", command.c_str(), static_cast<char *>(0));
- throw RunCommandError("execl /bin/sh -c '" + command + "' failed:"
- + stringify(strerror(errno)));
}
- catch (const Exception & e)
+ else if (-1 == child_child)
{
- std::cerr << "exec of '" << command << "' failed due to exception '" << e.message()
- << "' (" << e.what() << ")" << std::endl;
- exit(123);
+ std::cerr << "fork failed: " + stringify(strerror(errno)) + "'" << std::endl;
+ exit(125);
}
- catch (...)
+ else
{
- std::cerr << "exec of '" << command << "' failed due to unknown exception" << std::endl;
- exit(124);
+ /* The pid that waits for the exec pid and then writes to the done pipe */
+ if (cmd.pipe_command_handler())
+ {
+ close(pipe_command_reader->read_fd());
+ pipe_command_reader->clear_read_fd();
+
+ close(pipe_command_response->read_fd());
+ pipe_command_response->clear_read_fd();
+ close(pipe_command_response->write_fd());
+ pipe_command_response->clear_write_fd();
+ }
+
+ if (cmd.captured_stdout_stream())
+ {
+ close(captured_stdout->read_fd());
+ captured_stdout->clear_read_fd();
+ close(captured_stdout->write_fd());
+ captured_stdout->clear_write_fd();
+ }
+
+ close(internal_command_reader->read_fd());
+ internal_command_reader->clear_read_fd();
+
+ int status(-1);
+
+ stdout_write_fd = -1;
+ stdout_close_fd = -1;
+ stderr_write_fd = -1;
+ stderr_close_fd = -1;
+
+ int ret(-1);
+ if (-1 == waitpid(child_child, &status, 0))
+ std::cerr << "wait failed: " + stringify(strerror(errno)) + "'" << std::endl;
+ else
+ ret = (WIFSIGNALED(status) ? WTERMSIG(status) + 128 : WEXITSTATUS(status));
+
+ {
+ FDOutputStream stream(internal_command_reader->write_fd());
+ stream << "EXIT " << ret << std::endl;
+ }
}
+
+ _exit(0);
}
else if (-1 == child)
throw RunCommandError("fork failed: " + stringify(strerror(errno)));
else
{
- int status(-1);
+ /* Our original pid */
+ if (cmd.pipe_command_handler())
+ {
+ close(pipe_command_reader->write_fd());
+ pipe_command_reader->clear_write_fd();
+ close(pipe_command_response->read_fd());
+ pipe_command_response->clear_read_fd();
+ }
- stdout_write_fd = -1;
- stdout_close_fd = -1;
- stderr_write_fd = -1;
- stderr_close_fd = -1;
+ if (cmd.captured_stdout_stream())
+ {
+ close(captured_stdout->write_fd());
+ captured_stdout->clear_write_fd();
+ }
+
+ close(internal_command_reader->write_fd());
+ internal_command_reader->clear_write_fd();
+
+ std::string pipe_command_buffer, internal_command_buffer;
+ while (true)
+ {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ int max_fd(0);
+
+ if (cmd.pipe_command_handler())
+ {
+ FD_SET(pipe_command_reader->read_fd(), &read_fds);
+ max_fd = std::max(max_fd, pipe_command_reader->read_fd());
+ }
+
+ if (cmd.captured_stdout_stream())
+ {
+ FD_SET(captured_stdout->read_fd(), &read_fds);
+ max_fd = std::max(max_fd, captured_stdout->read_fd());
+ }
+
+ FD_SET(internal_command_reader->read_fd(), &read_fds);
+ max_fd = std::max(max_fd, internal_command_reader->read_fd());
+
+ timespec tv;
+ tv.tv_sec = 5;
+ tv.tv_nsec = 0;
+
+ int retval(pselect(max_fd + 1, &read_fds, 0, 0, &tv, 0));
+ if (-1 == retval)
+ throw RunCommandError("select failed: " + stringify(strerror(errno)));
+ else if (0 == retval)
+ {
+ Log::get_instance()->message(ll_debug, lc_context) << "Waiting for child " << child << " to finish";
+ continue;
+ }
+ else
+ {
+ char buf[1024];
+ if (cmd.pipe_command_handler() && FD_ISSET(pipe_command_reader->read_fd(), &read_fds))
+ {
+ int r;
+ if (((r = read(pipe_command_reader->read_fd(), buf, 1024))) > 0)
+ pipe_command_buffer.append(std::string(buf, r));
+ }
+
+ if (FD_ISSET(internal_command_reader->read_fd(), &read_fds))
+ {
+ int r;
+ if (((r = read(internal_command_reader->read_fd(), buf, 1024))) > 0)
+ internal_command_buffer.append(std::string(buf, r));
+ }
+
+ if (cmd.captured_stdout_stream() && FD_ISSET(captured_stdout->read_fd(), &read_fds))
+ {
+ int r;
+ if (((r = read(captured_stdout->read_fd(), buf, 1024))) > 0)
+ *cmd.captured_stdout_stream() << std::string(buf, r);
+ }
+ }
+
+ if (! pipe_command_buffer.empty())
+ Log::get_instance()->message(ll_debug, lc_context) << "pipe_command_buffer is '" << pipe_command_buffer << "'";
+ if (! internal_command_buffer.empty())
+ Log::get_instance()->message(ll_debug, lc_context) << "internal_command_buffer is '" << internal_command_buffer << "'";
- if (-1 == waitpid(child, &status, 0))
- throw RunCommandError("wait failed: " + stringify(strerror(errno)));
- return WIFSIGNALED(status) ? WTERMSIG(status) + 128 : WEXITSTATUS(status);
+ while (! pipe_command_buffer.empty())
+ {
+ std::string::size_type n_p(pipe_command_buffer.find('\n'));
+ if (std::string::npos == n_p)
+ break;
+
+ std::string op(pipe_command_buffer.substr(0, n_p));
+ pipe_command_buffer.erase(0, n_p + 1);
+
+ std::string response;
+ if (cmd.pipe_command_handler())
+ {
+ response = cmd.pipe_command_handler()(op);
+ Log::get_instance()->message(ll_debug, lc_context) << "Pipe command op '" << op << "' response '"
+ << response << "'";
+ }
+ else
+ Log::get_instance()->message(ll_warning, lc_context) << "Pipe command op '" << op <<
+ "' was requested but no handler defined. This is probably a bug...";
+
+ response = strip_trailing(response, "\n") + "\n";
+ ssize_t n(0);
+ while (! response.empty())
+ {
+ n = write(pipe_command_response->write_fd(), response.c_str(), response.length());
+ if (-1 == n)
+ throw InternalError(PALUDIS_HERE, "write failed: " + stringify(strerror(errno)));
+ else
+ response.erase(0, n);
+ }
+ }
+
+ while (! internal_command_buffer.empty())
+ {
+ std::string::size_type n_p(internal_command_buffer.find('\n'));
+ if (std::string::npos == n_p)
+ break;
+
+ std::string op(internal_command_buffer.substr(0, n_p));
+ internal_command_buffer.erase(0, n_p + 1);
+ if (0 == op.compare(0, 4, "EXIT"))
+ {
+ op.erase(0, 4);
+ int status(-1);
+ Log::get_instance()->message(ll_debug, lc_context) << "Got exit op '" << op << "'";
+ if (-1 == waitpid(child, &status, 0))
+ std::cerr << "wait failed: " + stringify(strerror(errno)) + "'" << std::endl;
+ return destringify<int>(strip_leading(strip_trailing(op, " \r\n\t"), " \r\n\t"));
+ }
+ else
+ throw InternalError(PALUDIS_HERE, "unknown op '" + op + "' on internal_command_buffer");
+ }
+ }
}
throw InternalError(PALUDIS_HERE, "should never be reached");
@@ -446,6 +686,13 @@ Command::with_stderr_prefix(const std::string & s)
return *this;
}
+Command &
+Command::with_pipe_command_handler(const tr1::function<std::string (const std::string &)> & f)
+{
+ _imp->pipe_command_handler = f;
+ return *this;
+}
+
std::string
Command::stdout_prefix() const
{
@@ -470,6 +717,18 @@ Command::prefix_blank_lines() const
return _imp->prefix_blank_lines;
}
+const tr1::function<std::string (const std::string &)> &
+Command::pipe_command_handler() const
+{
+ return _imp->pipe_command_handler;
+}
+
+std::ostream *
+Command::captured_stdout_stream() const
+{
+ return _imp->captured_stdout_stream;
+}
+
std::string
paludis::get_user_name(const uid_t u)
{
diff --git a/paludis/util/system.hh b/paludis/util/system.hh
index 946a798..31998bd 100644
--- a/paludis/util/system.hh
+++ b/paludis/util/system.hh
@@ -23,6 +23,7 @@
#include <paludis/util/exception.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/tr1_memory.hh>
+#include <paludis/util/tr1_functional.hh>
#include <paludis/util/wrapped_forward_iterator-fwd.hh>
#include <string>
#include <sys/types.h>
@@ -170,6 +171,16 @@ namespace paludis
*/
Command & with_prefix_blank_lines();
+ /**
+ * Specify a pipe command handler.
+ */
+ Command & with_pipe_command_handler(const tr1::function<std::string (const std::string &)> &);
+
+ /**
+ * Specify a stream to which stdout is captured and written.
+ */
+ Command & with_captured_stdout_stream(std::ostream * const);
+
///\}
///\name Fetch command execution options
@@ -221,6 +232,16 @@ namespace paludis
*/
bool prefix_blank_lines() const;
+ /**
+ * The pipe command handler.
+ */
+ const tr1::function<std::string (const std::string &)> & pipe_command_handler() const;
+
+ /**
+ * The captured stdout stream, or null.
+ */
+ std::ostream * captured_stdout_stream() const;
+
///\}
///\name Iterate over our setenvs.
diff --git a/paludis/util/system_TEST.cc b/paludis/util/system_TEST.cc
index 473e047..15c289e 100644
--- a/paludis/util/system_TEST.cc
+++ b/paludis/util/system_TEST.cc
@@ -18,7 +18,6 @@
*/
#include <paludis/util/system.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/fs_entry.hh>
#include <paludis/util/log.hh>
#include <paludis/util/thread_pool.hh>
@@ -30,11 +29,6 @@
# include <sched.h>
#endif
-/** \file
- * Test cases for system.hh .
- *
- */
-
using namespace test;
using namespace paludis;
@@ -70,15 +64,24 @@ namespace
if (0 != run_command("/bin/true"))
throw InternalError(PALUDIS_HERE, "true isn't");
}
+
+ std::string response_handler(const std::string & s)
+ {
+ if (s == "ONE")
+ return "1";
+ else if (s == "TWO")
+ return "2";
+ else if (s == "THREE")
+ return "3";
+ else if (s == "FOUR")
+ return "4";
+ else
+ return "9";
+ }
}
namespace test_cases
{
-
- /**
- * \test Test getenv_with_default.
- *
- */
struct GetenvWithDefaultTest : TestCase
{
GetenvWithDefaultTest() : TestCase("getenv_with_default") { }
@@ -91,10 +94,6 @@ namespace test_cases
}
} test_getenv_with_default;
- /**
- * \test Test getenv_or_error.
- *
- */
struct GetenvOrErrorTest : TestCase
{
GetenvOrErrorTest() : TestCase("getenv_or_error") { }
@@ -106,10 +105,6 @@ namespace test_cases
}
} test_getenv_or_error;
- /**
- * \test Test kernel_version.
- *
- */
struct KernelVersionTest : TestCase
{
KernelVersionTest() : TestCase("kernel version") { }
@@ -121,18 +116,14 @@ namespace test_cases
TEST_CHECK('2' == kernel_version().at(0));
TEST_CHECK('.' == kernel_version().at(1));
#elif defined(__FreeBSD__)
- TEST_CHECK('6' == kernel_version().at(0));
- TEST_CHECK('.' == kernel_version().at(1));
+ TEST_CHECK('6' == kernel_version().at(0));
+ TEST_CHECK('.' == kernel_version().at(1));
#else
# error You need to write a sanity test for kernel_version() for your platform.
#endif
}
} test_kernel_version;
- /**
- * \test Test run_command.
- *
- */
struct RunCommandTest : TestCase
{
RunCommandTest() : TestCase("run_command") { }
@@ -159,10 +150,6 @@ namespace test_cases
}
} test_run_command_mutex;
- /**
- * \test Test run_command_in_directory.
- *
- */
struct RunCommandInDirectoryTest : TestCase
{
RunCommandInDirectoryTest() : TestCase("run_command_in_directory") { }
@@ -179,10 +166,6 @@ namespace test_cases
}
} test_run_command_in_directory;
- /**
- * \test Test make_env_command.
- *
- */
struct MakeEnvCommandTest : TestCase
{
MakeEnvCommandTest() : TestCase("make_env_command") { }
@@ -210,10 +193,6 @@ namespace test_cases
}
} test_make_env_command;
- /**
- * \test Test make_env_command with quotes.
- *
- */
struct MakeEnvCommandQuoteTest : TestCase
{
MakeEnvCommandQuoteTest() : TestCase("make_env_command quotes") { }
@@ -228,5 +207,93 @@ namespace test_cases
.with_setenv("PALUDUS_TEST_ENV_VAR", "..'..")));
}
} test_make_env_command_quotes;
+
+ struct PipeCommandTest : TestCase
+ {
+ PipeCommandTest() : TestCase("pipe command") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(run_command(Command("bash system_TEST_dir/pipe_test.bash ONE TWO")
+ .with_pipe_command_handler(&response_handler)), 12);
+ TEST_CHECK_EQUAL(run_command(Command("bash system_TEST_dir/pipe_test.bash THREE FOUR")
+ .with_pipe_command_handler(&response_handler)), 34);
+ }
+ } test_pipe_command;
+
+ struct CapturedTest : TestCase
+ {
+ CapturedTest() : TestCase("captured stdout") { }
+
+ void run()
+ {
+ std::stringstream s;
+ TEST_CHECK_EQUAL(run_command(Command("echo hi").with_captured_stdout_stream(&s)), 0);
+ std::string line;
+ TEST_CHECK(std::getline(s, line));
+ TEST_CHECK_EQUAL(line, "hi");
+ TEST_CHECK(! std::getline(s, line));
+ }
+ } test_captured;
+
+ struct CapturedNoExistTest : TestCase
+ {
+ CapturedNoExistTest() : TestCase("captured nonexistent command") { }
+
+ void run()
+ {
+ std::stringstream s;
+ TEST_CHECK(run_command(Command("thiscommanddoesnotexist 2>/dev/null").with_captured_stdout_stream(&s)) != 0);
+ std::string line;
+ TEST_CHECK(! std::getline(s, line));
+ }
+ } test_captured_no_exist;
+
+ struct CapturedSilentFailTest : TestCase
+ {
+ CapturedSilentFailTest() : TestCase("captured silent fail") { }
+
+ void run()
+ {
+ std::stringstream s;
+ TEST_CHECK(run_command(Command("test -e /doesnotexist").with_captured_stdout_stream(&s)) != 0);
+ std::string line;
+ TEST_CHECK(! std::getline(s, line));
+ }
+ } test_captured_silent_fail;
+
+ struct CapturedFailTest : TestCase
+ {
+ CapturedFailTest() : TestCase("captured fail") { }
+
+ void run()
+ {
+ std::stringstream s;
+ TEST_CHECK(run_command(Command("cat /doesnotexist 2>&1").with_captured_stdout_stream(&s)) != 0);
+ std::string line;
+ TEST_CHECK(std::getline(s, line));
+ TEST_CHECK(! line.empty());
+ TEST_CHECK(! std::getline(s, line));
+ }
+ } test_captured_fail;
+
+
+ struct CapturedPipeCommandTest : TestCase
+ {
+ CapturedPipeCommandTest() : TestCase("captured pipe command") { }
+
+ void run()
+ {
+ std::stringstream s;
+ TEST_CHECK_EQUAL(run_command(Command("bash system_TEST_dir/captured_pipe_test.bash ONE TWO THREE")
+ .with_pipe_command_handler(&response_handler)
+ .with_captured_stdout_stream(&s)),
+ 13);
+ std::string line;
+ TEST_CHECK(std::getline(s, line));
+ TEST_CHECK_EQUAL(line, "2");
+ TEST_CHECK(! std::getline(s, line));
+ }
+ } test_captured_pipe_command;
}
diff --git a/paludis/util/system_TEST_setup.sh b/paludis/util/system_TEST_setup.sh
index d1c9e76..c75cdda 100755
--- a/paludis/util/system_TEST_setup.sh
+++ b/paludis/util/system_TEST_setup.sh
@@ -3,3 +3,33 @@
mkdir system_TEST_dir || exit 2
cd system_TEST_dir || exit 3
+
+cat <<'END' > pipe_test.bash
+#!/bin/bash
+
+echo $1 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+read -u$PALUDIS_PIPE_COMMAND_READ_FD response1
+
+echo $2 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+read -u$PALUDIS_PIPE_COMMAND_READ_FD response2
+
+exit $response1$response2
+END
+
+cat <<'END' > captured_pipe_test.bash
+#!/bin/bash
+
+echo $1 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+read -u$PALUDIS_PIPE_COMMAND_READ_FD response1
+
+echo $2 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+read -u$PALUDIS_PIPE_COMMAND_READ_FD response2
+
+echo $3 1>&$PALUDIS_PIPE_COMMAND_WRITE_FD
+read -u$PALUDIS_PIPE_COMMAND_READ_FD response3
+
+echo $response2
+
+exit $response1$response3
+END
+
diff --git a/src/clients/gtkpaludis/libgtkpaludis/messages_page.cc b/src/clients/gtkpaludis/libgtkpaludis/messages_page.cc
index b31238b..bbbc4b4 100644
--- a/src/clients/gtkpaludis/libgtkpaludis/messages_page.cc
+++ b/src/clients/gtkpaludis/libgtkpaludis/messages_page.cc
@@ -6,7 +6,6 @@
#include <paludis/query.hh>
#include <paludis/util/fd_output_stream.hh>
#include <paludis/util/system.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/log.hh>
#include <vtemm/terminal_widget.hh>
@@ -90,7 +89,6 @@ MessagesPage::set_capture_output_options()
{
set_run_command_stdout_fds(_imp->slave_fd, _imp->master_fd);
set_run_command_stderr_fds(_imp->slave_fd, _imp->master_fd);
- PStream::set_stderr_fd(_imp->slave_fd, _imp->master_fd);
Log::get_instance()->set_log_stream(_imp->messages_stream.get());
}
diff --git a/src/clients/gtkpaludis/libgtkpaludis/task_window.cc b/src/clients/gtkpaludis/libgtkpaludis/task_window.cc
index 143c871..4e3c3d1 100644
--- a/src/clients/gtkpaludis/libgtkpaludis/task_window.cc
+++ b/src/clients/gtkpaludis/libgtkpaludis/task_window.cc
@@ -7,7 +7,6 @@
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/tr1_memory.hh>
#include <paludis/util/fd_output_stream.hh>
-#include <paludis/util/pstream.hh>
#include <paludis/util/system.hh>
#include <paludis/util/log.hh>
#include <gtkmm/table.h>
@@ -85,7 +84,6 @@ TaskWindow::TaskWindow(MainWindow * const m, GuiTask * const t) :
_imp->terminal.set_pty(dup(_imp->master_fd));
set_run_command_stdout_fds(_imp->slave_fd, _imp->master_fd);
set_run_command_stderr_fds(_imp->slave_fd, _imp->master_fd);
- PStream::set_stderr_fd(_imp->slave_fd, _imp->master_fd);
Log::get_instance()->set_log_stream(_imp->messages_stream.get());
_imp->terminal.set_scroll_on_output(true);