diff --git a/generate/templates/manual/include/cmd.h b/generate/templates/manual/include/cmd.h new file mode 100644 index 000000000..01189583e --- /dev/null +++ b/generate/templates/manual/include/cmd.h @@ -0,0 +1,56 @@ +#ifndef NODEGIT_CMD_H +#define NODEGIT_CMD_H + +#include +#include + +namespace nodegit { +/** + * \class Cmd + * Abstract class holding a command to execute. + * + * Instances of Cmd will store all the information needed to run the command, + * including environment variables to set, like CWD. + */ +class Cmd { +public: + /* Enumeration describing the environment variables that Cmd will handle + * - kCWD: Current Working Directory. + */ + enum class Env {kCWD}; + + Cmd() = default; + virtual ~Cmd() = default; + Cmd(const Cmd &other) = delete; + Cmd(Cmd &&other) = delete; + Cmd& operator=(const Cmd &other) = delete; + Cmd& operator=(Cmd &&other) = delete; + + virtual std::string Command() const = 0; // return the command to execute + virtual std::string Args() const = 0; // return the arguments of the command if any + + void SetEnv(Env env, const std::string &value) { + m_env[env] = value; + } + std::string GetEnv(Env env) const { + auto value = m_env.find(env); + if (value != m_env.end()) { return value->second; } + else { return std::string(""); } + } + void SetRedirectStdErr(bool redirectStdErr) { + m_redirectStdErr = redirectStdErr; + } + bool GetRedirectStdErr() const { + return m_redirectStdErr; + } + + // TODO: turn private, and restrict set/get access with pre-validation if necessary + std::string out {}; // cmd output. TODO: stream here? + std::string errorMsg {}; // error message if the command execution failed + +private: + std::map m_env {}; // environment variables for this command + bool m_redirectStdErr {true}; // whether or not to redirect stderr to stdout +}; +} // namespace nodegit +#endif // NODEGIT_CMD_H \ No newline at end of file diff --git a/generate/templates/manual/include/run_command.h b/generate/templates/manual/include/run_command.h new file mode 100644 index 000000000..911fb4a50 --- /dev/null +++ b/generate/templates/manual/include/run_command.h @@ -0,0 +1,62 @@ +#ifndef NODEGIT_RUN_CMD_H +#define NODEGIT_RUN_CMD_H + +#include +#include +#include +#include +#include +#include +#include "cmd.h" + +namespace nodegit { + // TODO: + // This is just a first testing version to run commands in MacOS, Linux and Win32 + namespace runcommand { + /** + * \brief Executes a command. + * + * \param cmd object storing all the information needed to execute a command. Result + * of the execution will also be stored here. + * \return true if command execution succeeded; false otherwise. + */ + bool exec(Cmd *cmd) { + // TODO: sanitize path + assert (cmd != nullptr); + std::string cwd = cmd->GetEnv(Cmd::Env::kCWD); + std::string cmdCwd = cwd.empty() ? std::string("") : std::string("cd ").append(cwd).append(" && "); + std::string cmdArgs = cmd->Args(); + std::string finalCmdArgs = cmdArgs.empty() ? std::string("") : std::string(" ").append(cmdArgs); + std::string cmdRedirectErr = cmd->GetRedirectStdErr() ? " 2>&1" : std::string(""); + std::string finalCmd = cmdCwd + cmd->Command() + finalCmdArgs + cmdRedirectErr; + +#ifdef WIN32 + auto pipe = _popen(finalCmd.c_str(), "r"); +#else + auto pipe = popen(finalCmd.c_str(), "r"); +#endif + if (!pipe) { + cmd->errorMsg = "popen() failed!"; + return false; + } + + std::array buffer {}; + while (!feof(pipe)) { + if (fgets(buffer.data(), 128, pipe) != nullptr) + cmd->out += buffer.data(); + } +#ifdef WIN32 + auto rc = _pclose(pipe); +#else + auto rc = pclose(pipe); +#endif + + if (rc != EXIT_SUCCESS) { + cmd->errorMsg = "pclose() failed!"; + return false; + } + return true; + } + } // namespace runcommand +} // namespace nodegit +#endif // NODEGIT_RUN_CMD_H \ No newline at end of file