aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-01-05 15:42:55 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-01-05 18:42:59 +0000
commit1d7fa3dd097834ee102a741b245b669cb3387661 (patch)
tree621f05a44d6d02ff5bf1bdf92b046422cd09dbec
parent9657d3023e92d82de18ad8d92af0cc12637c72ef (diff)
downloadpaludis-1d7fa3dd097834ee102a741b245b669cb3387661.tar.gz
paludis-1d7fa3dd097834ee102a741b245b669cb3387661.tar.xz
Output via IPC
-rw-r--r--paludis/Makefile.am.m42
-rw-r--r--paludis/files.m41
-rw-r--r--paludis/ipc_output_manager-fwd.hh32
-rw-r--r--paludis/ipc_output_manager.cc405
-rw-r--r--paludis/ipc_output_manager.hh103
-rw-r--r--src/clients/cave/cmd_execute_resolution.cc28
-rw-r--r--src/clients/cave/cmd_perform.cc79
7 files changed, 622 insertions, 28 deletions
diff --git a/paludis/Makefile.am.m4 b/paludis/Makefile.am.m4
index e352c7a..6f0cc45 100644
--- a/paludis/Makefile.am.m4
+++ b/paludis/Makefile.am.m4
@@ -64,7 +64,7 @@ ifelse(`$2', `testscript', `addtestscript(`$1')', `')')dnl
define(`add', `addthis(`$1',`$2')addthis(`$1',`$3')addthis(`$1',`$4')dnl
addthis(`$1',`$5')addthis(`$1',`$6')addthis(`$1',`$7')addthis(`$1',`$8')')dnl
-AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@ @PALUDIS_CXXFLAGS_NO_WOLD_STYLE_CAST@
include(`paludis/files.m4')
diff --git a/paludis/files.m4 b/paludis/files.m4
index 4c346e9..62f2d1c 100644
--- a/paludis/files.m4
+++ b/paludis/files.m4
@@ -48,6 +48,7 @@ add(`handled_information', `hh', `fwd', `cc')
add(`hook', `hh', `cc', `fwd', `se')
add(`hooker', `hh', `cc', `test', `testscript')
add(`install_task', `hh', `cc', `se')
+add(`ipc_output_manager', `hh', `cc', `fwd')
add(`literal_metadata_key', `hh', `cc')
add(`mask', `hh', `cc', `fwd', `se')
add(`match_package', `hh', `cc', `se', `fwd')
diff --git a/paludis/ipc_output_manager-fwd.hh b/paludis/ipc_output_manager-fwd.hh
new file mode 100644
index 0000000..328e449
--- /dev/null
+++ b/paludis/ipc_output_manager-fwd.hh
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 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_IPC_OUTPUT_MANAGER_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_IPC_OUTPUT_MANAGER_FWD_HH 1
+
+namespace paludis
+{
+ struct IPCOutputManager;
+
+ struct IPCInputManager;
+
+ struct OutputManagerFromIPC;
+}
+
+#endif
diff --git a/paludis/ipc_output_manager.cc b/paludis/ipc_output_manager.cc
new file mode 100644
index 0000000..3eaa22c
--- /dev/null
+++ b/paludis/ipc_output_manager.cc
@@ -0,0 +1,405 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 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/ipc_output_manager.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/safe_ofstream.hh>
+#include <paludis/util/safe_ifstream.hh>
+#include <paludis/util/set.hh>
+#include <paludis/util/map.hh>
+#include <paludis/util/wrapped_forward_iterator.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/iterator_funcs.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/thread.hh>
+#include <paludis/util/pipe.hh>
+#include <paludis/standard_output_manager.hh>
+#include <paludis/create_output_manager_info.hh>
+#include <paludis/serialise.hh>
+#include <paludis/environment.hh>
+#include <tr1/functional>
+#include <vector>
+#include <cstdlib>
+#include <cstring>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<IPCOutputManager>
+ {
+ std::tr1::shared_ptr<SafeOFStream> stdout_stream;
+ std::tr1::shared_ptr<SafeOFStream> stderr_stream;
+
+ std::tr1::shared_ptr<SafeIFStream> pipe_command_read_stream;
+ std::tr1::shared_ptr<SafeOFStream> pipe_command_write_stream;
+
+ Implementation(int r, int w) :
+ pipe_command_write_stream(new SafeOFStream(w))
+ {
+ *pipe_command_write_stream << "PING 1 GOAT" << '\0' << std::flush;
+
+ pipe_command_read_stream.reset(new SafeIFStream(r));
+ std::string response;
+ if (! std::getline(*pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+ if (response != "OPONG GOAT")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+ }
+ };
+}
+
+IPCOutputManager::IPCOutputManager(const int r, const int w, const CreateOutputManagerInfo & i) :
+ PrivateImplementationPattern<IPCOutputManager>(new Implementation<IPCOutputManager>(r, w))
+{
+ std::stringstream ser_stream;
+ Serialiser ser(ser_stream);
+ i.serialise(ser);
+ *_imp->pipe_command_write_stream << "CREATE 1 " << ser_stream.str() << '\0' << std::flush;
+
+ std::string response;
+ if (! std::getline(*_imp->pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+
+ std::vector<std::string> tokens;
+ tokenise_whitespace(response, std::back_inserter(tokens));
+
+ if (tokens.size() != 4 || tokens[0] != "O" || tokens[1] != "1")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+
+ _imp->stdout_stream.reset(new SafeOFStream(destringify<int>(tokens[2])));
+ _imp->stderr_stream.reset(new SafeOFStream(destringify<int>(tokens[3])));
+}
+
+IPCOutputManager::~IPCOutputManager()
+{
+ *_imp->pipe_command_write_stream << "FINISHED 1" << '\0' << std::flush;
+
+ std::string response;
+ if (! std::getline(*_imp->pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+ if (response != "O")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+}
+
+std::ostream &
+IPCOutputManager::stdout_stream()
+{
+ return *_imp->stdout_stream;
+}
+
+std::ostream &
+IPCOutputManager::stderr_stream()
+{
+ return *_imp->stderr_stream;
+}
+
+void
+IPCOutputManager::message(const MessageType t, const std::string & s)
+{
+ *_imp->pipe_command_write_stream << "MESSAGE 1 " << t << " " << s << '\0' << std::flush;
+
+ std::string response;
+ if (! std::getline(*_imp->pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+ if (response != "O")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+}
+
+void
+IPCOutputManager::succeeded()
+{
+ *_imp->pipe_command_write_stream << "SUCCEEDED 1" << '\0' << std::flush;
+
+ std::string response;
+ if (! std::getline(*_imp->pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+ if (response != "O")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+}
+
+void
+IPCOutputManager::flush()
+{
+}
+
+bool
+IPCOutputManager::want_to_flush() const
+{
+ return false;
+}
+
+void
+IPCOutputManager::nothing_more_to_come()
+{
+ *_imp->pipe_command_write_stream << "NOTHING_MORE_TO_COME 1" << '\0' << std::flush;
+
+ std::string response;
+ if (! std::getline(*_imp->pipe_command_read_stream, response, '\0'))
+ throw InternalError(PALUDIS_HERE, "couldn't get a pipe command response");
+ if (response != "O")
+ throw InternalError(PALUDIS_HERE, "got response '" + response + "'");
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<IPCInputManager>
+ {
+ const Environment * const env;
+ const OutputExclusivity exclusivity;
+
+ std::tr1::shared_ptr<OutputManager> output_manager;
+ std::tr1::shared_ptr<Thread> copy_thread;
+
+ Pipe stdout_pipe, stderr_pipe, finished_pipe;
+
+ Implementation(const Environment * const e, const OutputExclusivity x) :
+ env(e),
+ exclusivity(x)
+ {
+ }
+ };
+}
+
+IPCInputManager::IPCInputManager(const Environment * const e, const OutputExclusivity x) :
+ PrivateImplementationPattern<IPCInputManager>(new Implementation<IPCInputManager>(e, x))
+{
+}
+
+IPCInputManager::~IPCInputManager()
+{
+ char c('x');
+ if (1 != write(_imp->finished_pipe.write_fd(), &c, 1))
+ throw InternalError(PALUDIS_HERE, "write failed");
+}
+
+const std::tr1::function<std::string (const std::string &)>
+IPCInputManager::pipe_command_handler()
+{
+ return std::tr1::bind(&IPCInputManager::_pipe_command_handler, this, std::tr1::placeholders::_1);
+}
+
+std::string
+IPCInputManager::_pipe_command_handler(const std::string & s)
+{
+ std::vector<std::string> tokens;
+ tokenise_whitespace(s, std::back_inserter(tokens));
+
+ if (tokens.empty())
+ throw InternalError(PALUDIS_HERE, "tokens is empty");
+
+ if (tokens[0] == "PING")
+ {
+ if (tokens.size() != 3 || tokens[1] != "1")
+ return "Ebad PING subcommand";
+ return "OPONG " + tokens[2];
+ }
+ else if (tokens[0] == "CREATE")
+ {
+ if (tokens.size() != 3 || tokens[1] != "1")
+ return "Ebad CREATE subcommand";
+
+ if (_imp->output_manager)
+ return "Ealready constructed";
+
+ Deserialiser deserialiser(_imp->env, tokens[2]);
+ Deserialisation deserialisation("CreateOutputManagerInfo", deserialiser);
+ const std::tr1::shared_ptr<CreateOutputManagerInfo> i(CreateOutputManagerInfo::deserialise(deserialisation));
+
+ _imp->output_manager = _imp->env->create_output_manager(*i);
+ _imp->copy_thread.reset(new Thread(std::tr1::bind(&IPCInputManager::_copy_thread, this)));
+
+ return "O 1 " + stringify(_imp->stdout_pipe.write_fd()) + " " + stringify(_imp->stderr_pipe.write_fd());
+ }
+ else if (tokens[0] == "MESSAGE")
+ {
+ if (tokens.size() < 3 || tokens[1] != "1")
+ return "Ebad MESSAGE subcommand";
+
+ MessageType t(destringify<MessageType>(tokens[2]));
+ std::string m(join(next(tokens.begin(), 3), tokens.end(), " "));
+ _imp->output_manager->message(t, m);
+
+ return "O";
+ }
+ else if (tokens[0] == "SUCCEEDED")
+ {
+ if (tokens.size() != 2 || tokens[1] != "1")
+ return "Ebad SUCCEEDED subcommand";
+ _imp->output_manager->succeeded();
+
+ return "O";
+ }
+ else if (tokens[0] == "NOTHING_MORE_TO_COME")
+ {
+ if (tokens.size() != 2 || tokens[1] != "1")
+ return "Ebad NOTHING_MORE_TO_COME subcommand";
+ _imp->output_manager->nothing_more_to_come();
+
+ return "O";
+ }
+ else if (tokens[0] == "FINISHED")
+ {
+ if (tokens.size() != 2 || tokens[1] != "1")
+ return "Ebad FINISHED subcommand";
+
+ char c('x');
+ if (1 != write(_imp->finished_pipe.write_fd(), &c, 1))
+ throw InternalError(PALUDIS_HERE, "write failed");
+
+ return "O";
+ }
+ else
+ return "Eunknown pipe command";
+}
+
+void
+IPCInputManager::_copy_thread()
+{
+ bool done(false);
+ while (! done)
+ {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ int max_fd(0);
+
+ FD_SET(_imp->stdout_pipe.read_fd(), &read_fds);
+ max_fd = std::max(max_fd, _imp->stdout_pipe.read_fd());
+
+ FD_SET(_imp->stderr_pipe.read_fd(), &read_fds);
+ max_fd = std::max(max_fd, _imp->stderr_pipe.read_fd());
+
+ FD_SET(_imp->finished_pipe.read_fd(), &read_fds);
+ max_fd = std::max(max_fd, _imp->finished_pipe.read_fd());
+
+ int retval(pselect(max_fd + 1, &read_fds, 0, 0, 0, 0));
+ if (-1 == retval)
+ throw InternalError(PALUDIS_HERE, "pselect failed: " + stringify(strerror(errno)));
+
+ bool got_output(false);
+ char buf[1024];
+
+ if (FD_ISSET(_imp->stdout_pipe.read_fd(), &read_fds))
+ {
+ got_output = true;
+ int r;
+ if (((r = read(_imp->stdout_pipe.read_fd(), buf, 1024))) > 0)
+ _imp->output_manager->stdout_stream() << std::string(buf, r);
+ }
+
+ if (FD_ISSET(_imp->stderr_pipe.read_fd(), &read_fds))
+ {
+ got_output = true;
+ int r;
+ if (((r = read(_imp->stderr_pipe.read_fd(), buf, 1024))) > 0)
+ _imp->output_manager->stderr_stream() << std::string(buf, r);
+ }
+
+ if (got_output)
+ continue;
+
+ if (FD_ISSET(_imp->finished_pipe.read_fd(), &read_fds))
+ {
+ int r;
+ if (((r = read(_imp->finished_pipe.read_fd(), buf, 1024))) > 0)
+ done = true;
+ }
+ }
+}
+
+namespace paludis
+{
+ template <>
+ struct Implementation<OutputManagerFromIPC>
+ {
+ const Environment * const env;
+ const std::tr1::shared_ptr<const PackageID> id;
+ const OutputExclusivity exclusivity;
+
+ int read_fd, write_fd;
+
+ std::tr1::shared_ptr<OutputManager> result;
+
+ Implementation(const Environment * const e, const std::tr1::shared_ptr<const PackageID> & i,
+ const OutputExclusivity x) :
+ env(e),
+ id(i),
+ exclusivity(x),
+ read_fd(destringify<int>(getenv_with_default("PALUDIS_IPC_READ_FD", "-1"))),
+ write_fd(destringify<int>(getenv_with_default("PALUDIS_IPC_WRITE_FD", "-1")))
+ {
+ if (-1 == read_fd || -1 == write_fd)
+ throw InternalError(PALUDIS_HERE, "no pipe command handler available");
+ unsetenv("PALUDIS_IPC_READ_FD");
+ unsetenv("PALUDIS_IPC_WRITE_FD");
+ }
+ };
+}
+
+OutputManagerFromIPC::OutputManagerFromIPC(const Environment * const e,
+ const std::tr1::shared_ptr<const PackageID> & i,
+ const OutputExclusivity x) :
+ PrivateImplementationPattern<OutputManagerFromIPC>(new Implementation<OutputManagerFromIPC>(e, i, x))
+{
+}
+
+OutputManagerFromIPC::~OutputManagerFromIPC()
+{
+}
+
+const std::tr1::shared_ptr<OutputManager>
+OutputManagerFromIPC::operator() (const Action & a)
+{
+ if (! _imp->result)
+ _imp->result.reset(new IPCOutputManager(_imp->read_fd, _imp->write_fd,
+ CreateOutputManagerForPackageIDActionInfo(_imp->id, a, _imp->exclusivity)));
+ return _imp->result;
+}
+
+const std::tr1::shared_ptr<OutputManager>
+OutputManagerFromIPC::output_manager_if_constructed()
+{
+ return _imp->result;
+}
+
+void
+OutputManagerFromIPC::construct_standard_if_unconstructed()
+{
+ if (! _imp->result)
+ {
+ Log::get_instance()->message("output_manager_from_ipc.constructed_standard", ll_warning, lc_context)
+ << "No output manager available, creating a standard output manager. This is probably a bug.";
+ _imp->result.reset(new StandardOutputManager);
+ }
+}
+
+template class PrivateImplementationPattern<IPCOutputManager>;
+template class PrivateImplementationPattern<IPCInputManager>;
+template class PrivateImplementationPattern<OutputManagerFromIPC>;
+
diff --git a/paludis/ipc_output_manager.hh b/paludis/ipc_output_manager.hh
new file mode 100644
index 0000000..24fde29
--- /dev/null
+++ b/paludis/ipc_output_manager.hh
@@ -0,0 +1,103 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 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_IPC_OUTPUT_MANAGER_HH
+#define PALUDIS_GUARD_PALUDIS_IPC_OUTPUT_MANAGER_HH 1
+
+#include <paludis/ipc_output_manager-fwd.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/output_manager.hh>
+#include <paludis/environment-fwd.hh>
+#include <paludis/create_output_manager_info-fwd.hh>
+#include <paludis/package_id-fwd.hh>
+#include <paludis/action-fwd.hh>
+#include <tr1/memory>
+#include <tr1/functional>
+#include <string>
+
+namespace paludis
+{
+ class PALUDIS_VISIBLE IPCOutputManager :
+ private PrivateImplementationPattern<IPCOutputManager>,
+ public OutputManager
+ {
+ public:
+ IPCOutputManager(
+ const int pipe_read_fd,
+ const int pipe_write_fd,
+ const CreateOutputManagerInfo &);
+ ~IPCOutputManager();
+
+ virtual std::ostream & stdout_stream() PALUDIS_ATTRIBUTE((warn_unused_result));
+ virtual std::ostream & stderr_stream() PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual void succeeded();
+ virtual void flush();
+ virtual bool want_to_flush() const;
+ virtual void nothing_more_to_come();
+ virtual void message(const MessageType, const std::string &);
+ };
+
+ class PALUDIS_VISIBLE IPCInputManager :
+ private PrivateImplementationPattern<IPCInputManager>
+ {
+ private:
+ std::string _pipe_command_handler(const std::string &);
+ void _copy_thread();
+
+ public:
+ IPCInputManager(
+ const Environment * const,
+ const OutputExclusivity);
+
+ ~IPCInputManager();
+
+ const std::tr1::function<std::string (const std::string &)> pipe_command_handler()
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+
+ class PALUDIS_VISIBLE OutputManagerFromIPC :
+ private PrivateImplementationPattern<OutputManagerFromIPC>
+ {
+ public:
+ OutputManagerFromIPC(
+ const Environment * const,
+ const std::tr1::shared_ptr<const PackageID> &,
+ const OutputExclusivity
+ );
+
+ ~OutputManagerFromIPC();
+
+ const std::tr1::shared_ptr<OutputManager> operator() (const Action &);
+
+ const std::tr1::shared_ptr<OutputManager> output_manager_if_constructed();
+
+ void construct_standard_if_unconstructed();
+ };
+
+#ifdef PALUDIS_HAVE_EXTERN_TEMPLATE
+ extern template class PrivateImplementationPattern<IPCOutputManager>;
+ extern template class PrivateImplementationPattern<IPCInputManager>;
+ extern template class PrivateImplementationPattern<OutputManagerFromIPC>;
+#endif
+
+}
+
+#endif
diff --git a/src/clients/cave/cmd_execute_resolution.cc b/src/clients/cave/cmd_execute_resolution.cc
index 85c9032..06b19b5 100644
--- a/src/clients/cave/cmd_execute_resolution.cc
+++ b/src/clients/cave/cmd_execute_resolution.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2009 Ciaran McCreesh
+ * Copyright (c) 2009, 2010 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
@@ -58,6 +58,7 @@
#include <paludis/action.hh>
#include <paludis/package_dep_spec_properties.hh>
#include <paludis/serialise.hh>
+#include <paludis/ipc_output_manager.hh>
#include <set>
#include <iterator>
@@ -115,7 +116,7 @@ namespace
};
int do_pretend(
- const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<Environment> & env,
const ExecuteResolutionCommandLine & cmdline,
const ChangesToMakeDecision & decision,
const int x, const int y)
@@ -130,7 +131,7 @@ namespace
if (command.empty())
command = "$CAVE perform";
- command.append(" pretend --hooks --if-supported ");
+ command.append(" pretend --hooks --if-supported --managed-output ");
command.append(stringify(decision.origin_id()->uniquely_identifying_spec()));
command.append(" --x-of-y '" + stringify(x) + " of " + stringify(y) + "'");
@@ -142,7 +143,12 @@ namespace
command.append(" --" + cmdline.import_options.a_unpackaged_repository_params.long_name() + " '" + *p + "'");
}
+ IPCInputManager input_manager(env.get(), oe_exclusive);
paludis::Command cmd(command);
+ cmd
+ .with_pipe_command_handler("PALUDIS_IPC", input_manager.pipe_command_handler())
+ ;
+
return run_command(cmd);
}
@@ -173,7 +179,7 @@ namespace
}
int do_fetch(
- const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<Environment> & env,
const ExecuteResolutionCommandLine & cmdline,
const ChangesToMakeDecision & decision,
const int x, const int y, bool normal_only)
@@ -187,7 +193,7 @@ namespace
if (command.empty())
command = "$CAVE perform";
- command.append(" fetch --hooks --if-supported ");
+ command.append(" fetch --hooks --if-supported --managed-output ");
command.append(stringify(id->uniquely_identifying_spec()));
command.append(" --x-of-y '" + stringify(x) + " of " + stringify(y) + "'");
@@ -202,7 +208,11 @@ namespace
command.append(" --" + cmdline.import_options.a_unpackaged_repository_params.long_name() + " '" + *p + "'");
}
+ IPCInputManager input_manager(env.get(), oe_exclusive);
paludis::Command cmd(command);
+ cmd
+ .with_pipe_command_handler("PALUDIS_IPC", input_manager.pipe_command_handler())
+ ;
int retcode(run_command(cmd));
done_action("fetch (" + std::string(normal_only ? "regular parts" : "extra parts") + ")", decision, 0 == retcode);
@@ -210,7 +220,7 @@ namespace
}
int do_install(
- const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<Environment> & env,
const ExecuteResolutionCommandLine & cmdline,
const std::tr1::shared_ptr<const Resolution> & resolution,
const ChangesToMakeDecision & decision,
@@ -245,7 +255,7 @@ namespace
if (command.empty())
command = "$CAVE perform";
- command.append(" install --hooks ");
+ command.append(" install --hooks --managed-output ");
command.append(stringify(id->uniquely_identifying_spec()));
command.append(" --destination " + stringify(decision.destination()->repository()));
for (PackageIDSequence::ConstIterator i(decision.destination()->replacing()->begin()),
@@ -290,7 +300,11 @@ namespace
command.append(" --" + cmdline.import_options.a_unpackaged_repository_params.long_name() + " '" + *p + "'");
}
+ IPCInputManager input_manager(env.get(), oe_exclusive);
paludis::Command cmd(command);
+ cmd
+ .with_pipe_command_handler("PALUDIS_IPC", input_manager.pipe_command_handler())
+ ;
int retcode(run_command(cmd));
done_action(action_string, decision, 0 == retcode);
diff --git a/src/clients/cave/cmd_perform.cc b/src/clients/cave/cmd_perform.cc
index e71d2cb..1ece0bb 100644
--- a/src/clients/cave/cmd_perform.cc
+++ b/src/clients/cave/cmd_perform.cc
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2009 Ciaran McCreesh
+ * Copyright (c) 2009, 2010 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
@@ -36,6 +36,7 @@
#include <paludis/hook.hh>
#include <paludis/output_manager_from_environment.hh>
#include <paludis/output_manager.hh>
+#include <paludis/ipc_output_manager.hh>
#include <paludis/util/set.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
#include <paludis/util/make_shared_ptr.hh>
@@ -78,7 +79,7 @@ namespace
args::SwitchArg a_if_supported;
args::SwitchArg a_hooks;
args::StringArg a_x_of_y;
- args::SwitchArg a_background;
+ args::SwitchArg a_managed_output;
args::ArgsGroup g_fetch_action_options;
args::SwitchArg a_exclude_unmirrorable;
@@ -107,8 +108,9 @@ namespace
"Also execute the appropriate hooks for the action.", true),
a_x_of_y(&g_general_options, "x-of-y", '\0',
"Specify the value of the X_OF_Y variable that is passed to hooks."),
- a_background(&g_general_options, "background", '\0',
- "Indicate that we are being run in the background", true),
+ a_managed_output(&g_general_options, "managed-output", '\0',
+ "Specify that our output is being managed by another process. Used by "
+ "'cave execute-resolution'; not for end user use.", false),
g_fetch_action_options(main_options_section(), "Fetch Action Options",
"Options for if the action is 'fetch' or 'pretend-fetch'"),
@@ -156,6 +158,47 @@ namespace
}
};
+ struct OutputManagerFromIPCOrEnvironment
+ {
+ std::tr1::shared_ptr<OutputManagerFromIPC> manager_if_ipc;
+ std::tr1::shared_ptr<OutputManagerFromEnvironment> manager_if_env;
+
+ OutputManagerFromIPCOrEnvironment(
+ const Environment * const e,
+ const PerformCommandLine & cmdline,
+ const std::tr1::shared_ptr<const PackageID> & id)
+ {
+ if (cmdline.a_managed_output.specified())
+ manager_if_ipc.reset(new OutputManagerFromIPC(e, id, oe_exclusive));
+ else
+ manager_if_env.reset(new OutputManagerFromEnvironment(e, id, oe_exclusive));
+ }
+
+ const std::tr1::shared_ptr<OutputManager> operator() (const Action & a)
+ {
+ if (manager_if_env)
+ return (*manager_if_env)(a);
+ else
+ return (*manager_if_ipc)(a);
+ }
+
+ const std::tr1::shared_ptr<OutputManager> output_manager_if_constructed()
+ {
+ if (manager_if_env)
+ return manager_if_env->output_manager_if_constructed();
+ else
+ return manager_if_ipc->output_manager_if_constructed();
+ }
+
+ void construct_standard_if_unconstructed()
+ {
+ if (manager_if_env)
+ manager_if_env->construct_standard_if_unconstructed();
+ else
+ manager_if_ipc->construct_standard_if_unconstructed();
+ }
+ };
+
void execute(
const std::tr1::shared_ptr<Environment> & env,
const PerformCommandLine & cmdline,
@@ -163,7 +206,7 @@ namespace
const std::string & action_name,
Action & action)
{
- if (cmdline.a_x_of_y.specified() && ! cmdline.a_background.specified())
+ if (cmdline.a_x_of_y.specified())
std::cout << "\x1b]2;" << cmdline.a_x_of_y.argument() << " " << action_name << " "
<< stringify(*id) << "\x07" << std::flush;
@@ -183,7 +226,7 @@ namespace
).max_exit_status())
throw ActionAbortedError("Aborted by hook");
- if (cmdline.a_x_of_y.specified() && ! cmdline.a_background.specified())
+ if (cmdline.a_x_of_y.specified())
std::cout << "\x1b]2;Completed " << cmdline.a_x_of_y.argument() << " " << action_name << " "
<< stringify(*id) << "\x07" << std::flush;
}
@@ -203,7 +246,7 @@ namespace
UninstallAction uninstall_action(options);
execute(env, cmdline, id, "clean", uninstall_action);
- if (cmdline.a_x_of_y.specified() && ! cmdline.a_background.specified())
+ if (cmdline.a_x_of_y.specified())
std::cout << "\x1b]2;" << cmdline.a_x_of_y.argument() << " " << action_name << " "
<< stringify(*id) << "\x07" << std::flush;
}
@@ -211,10 +254,10 @@ namespace
struct WantInstallPhase
{
const PerformCommandLine & cmdline;
- OutputManagerFromEnvironment & output_manager_holder;
+ OutputManagerFromIPCOrEnvironment & output_manager_holder;
bool done_any;
- WantInstallPhase(const PerformCommandLine & c, OutputManagerFromEnvironment & o) :
+ WantInstallPhase(const PerformCommandLine & c, OutputManagerFromIPCOrEnvironment & o) :
cmdline(c),
output_manager_holder(o),
done_any(false)
@@ -322,10 +365,6 @@ PerformCommand::run(
throw BeMoreSpecific(spec, ids);
const std::tr1::shared_ptr<const PackageID> id(*ids->begin());
- OutputExclusivity exclusivity(oe_exclusive);
- if (cmdline.a_background.specified())
- exclusivity = oe_background;
-
FetchParts parts;
parts += fp_regulars;
if (! cmdline.a_regulars_only.specified())
@@ -338,7 +377,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<ConfigAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
ConfigActionOptions options(make_named_values<ConfigActionOptions>(
value_for<n::make_output_manager>(std::tr1::ref(output_manager_holder))
));
@@ -350,7 +389,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<FetchAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
FetchActionOptions options(make_named_values<FetchActionOptions>(
value_for<n::errors>(make_shared_ptr(new Sequence<FetchActionFailure>)),
value_for<n::exclude_unmirrorable>(cmdline.a_exclude_unmirrorable.specified()),
@@ -367,7 +406,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<PretendFetchAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
FetchActionOptions options(make_named_values<FetchActionOptions>(
value_for<n::errors>(make_shared_ptr(new Sequence<FetchActionFailure>)),
value_for<n::exclude_unmirrorable>(cmdline.a_exclude_unmirrorable.specified()),
@@ -394,7 +433,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<InfoAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
InfoActionOptions options(make_named_values<InfoActionOptions>(
value_for<n::make_output_manager>(std::tr1::ref(output_manager_holder))
));
@@ -428,7 +467,7 @@ PerformCommand::run(
replacing->push_back(*rids->begin());
}
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
WantInstallPhase want_phase(cmdline, output_manager_holder);
InstallActionOptions options(make_named_values<InstallActionOptions>(
value_for<n::destination>(destination),
@@ -448,7 +487,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<PretendAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
PretendActionOptions options(make_named_values<PretendActionOptions>(
value_for<n::make_output_manager>(std::tr1::ref(output_manager_holder))
));
@@ -462,7 +501,7 @@ PerformCommand::run(
if (cmdline.a_if_supported.specified() && ! id->supports_action(SupportsActionTest<UninstallAction>()))
return EXIT_SUCCESS;
- OutputManagerFromEnvironment output_manager_holder(env.get(), id, exclusivity);
+ OutputManagerFromIPCOrEnvironment output_manager_holder(env.get(), cmdline, id);
UninstallActionOptions options(make_named_values<UninstallActionOptions>(
value_for<n::config_protect>(cmdline.a_config_protect.argument()),
value_for<n::if_for_install_id>(make_null_shared_ptr()),