#pragma once #include "common.hpp" #include "components/logger.hpp" #include "components/types.hpp" #include "errors.hpp" #include "utils/file.hpp" POLYBAR_NS DEFINE_ERROR(command_error); /** * Wrapper used to execute command in a subprocess. * In-/output streams are opened to enable ipc. * If the command is created using command_util::make_command<output_policy::REDIRECTED>, the child streams are * redirected and you can read the program output or write into the program input. * * If the command is created using command_util::make_command<output_policy::IGNORED>, the output is not redirected and * you can't communicate with the child program. * * Example usage: * * \code cpp * auto cmd = command_util::make_command<output_policy::REDIRECTED>("cat /etc/rc.local"); * cmd->exec(); * cmd->tail([](string s) { std::cout << s << std::endl; }); * \endcode * * \code cpp * auto cmd = command_util::make_command<output_policy::REDIRECTED>("for i in 1 2 3; do echo $i; done"); * cmd->exec(); * cout << cmd->readline(); // 1 * cout << cmd->readline() << cmd->readline(); // 23 * \endcode * * \code cpp * auto cmd = command_util::make_command<output_policy::IGNORED>("ping kernel.org"); * int status = cmd->exec(); * \endcode */ template <output_policy> class command; template <> class command<output_policy::IGNORED> { public: explicit command(const logger& logger, string cmd); command(const command&) = delete; ~command(); command& operator=(const command&) = delete; int exec(bool wait_for_completion = true); void terminate(); bool is_running(); int wait(); pid_t get_pid(); int get_exit_status(); protected: const logger& m_log; string m_cmd; pid_t m_forkpid{-1}; int m_forkstatus{-1}; }; template <> class command<output_policy::REDIRECTED> : private command<output_policy::IGNORED> { public: explicit command(const logger& logger, string cmd); command(const command&) = delete; ~command(); command& operator=(const command&) = delete; int exec(bool wait_for_completion = true, const vector<pair<string, string>>& env = {}); using command<output_policy::IGNORED>::terminate; using command<output_policy::IGNORED>::is_running; using command<output_policy::IGNORED>::wait; using command<output_policy::IGNORED>::get_pid; using command<output_policy::IGNORED>::get_exit_status; void tail(std::function<void(string)> cb); string readline(); int get_stdout(int c); int get_stdin(int c); protected: int m_stdout[2]{0, 0}; int m_stdin[2]{0, 0}; unique_ptr<fd_stream<std::istream>> m_stdout_reader{nullptr}; }; namespace command_util { template <output_policy OutputType, typename... Args> unique_ptr<command<OutputType>> make_command(Args&&... args) { return std::make_unique<command<OutputType>>(logger::make(), forward<Args>(args)...); } } // namespace command_util POLYBAR_NS_END