Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

engine: Fix command execution #226

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/reference/actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ Parameter Required Type Description
================== ========== ============== ==================================
``command`` yes string command to execute in shell
``mode`` no string one of ``sync``, ``async``, ``detach``
``output`` no string one of ``never``, ``normal``, ``always``
``log_output`` no string one of ``never``, ``on_error``, ``always``
``ignore_failure`` no bool whether to ignore execution failure
================== ========== ============== ==================================

Expand All @@ -212,7 +212,7 @@ Parameter Required Type Description
``path`` yes string command to execute directly
``args`` no array arguments to pass to path
``mode`` no string one of ``sync``, ``async``, ``detach``
``output`` no string one of ``never``, ``normal``, ``always``
``log_output`` no string one of ``never``, ``on_error``, ``always``
``ignore_failure`` no bool whether to ignore execution failure
================== ========== ============== ==================================

Expand Down
41 changes: 21 additions & 20 deletions engine/src/utility/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ namespace engine {
CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const {
namespace bp = boost::process;

// Verbosity is Never(0), OnFailure(1), Always(2)
auto verbose = static_cast<int>(cmd.verbosity());

CommandResult r;
r.name = cmd.executable().filename().native();
r.command = cmd.command();
Expand All @@ -40,7 +43,9 @@ CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const {
return r;
}

logger()->info("Run: {}", r.command);
if (verbose > 1) {
logger()->info("Run: {}", r.command);
}
try {
if (!cmd.is_sync()) {
r.child = bp::child(cmd.executable(), cmd.args());
Expand All @@ -56,20 +61,19 @@ CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const {
// was only found by rummaging through the source code. Ridiculous.
r.child = bp::child(cmd.executable(), cmd.args(), (bp::std_out & bp::std_err) > is);

if (cmd.verbosity() != cloe::Command::Verbosity::Never) {
std::string line;
bool log_output = logger_ && cmd.verbosity() == cloe::Command::Verbosity::Always;
while (r.child->running() && std::getline(is, line)) {
if (log_output) {
logger()->debug("{}:{} | {}", r.name, r.child->id(), line);
}
r.output.push_back(line);
std::string line;
// After finished running output the rest of the lines.
while (std::getline(is, line)) {
if (verbose > 1) {
logger()->debug("{}:{} | {}", r.name, r.child->id(), line);
}
r.output.push_back(line);
}

r.child->wait();
r.exit_code = r.child->exit_code();

if (*r.exit_code != 0) {
if (*r.exit_code != 0 && (verbose > 0 || !cmd.ignore_failure())) {
logger()->error("Error running: {}", r.command);
if (!r.output.empty()) {
std::stringstream s;
Expand All @@ -84,20 +88,17 @@ CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const {
}
}
}
} catch (std::system_error& e) {
logger()->error("Error running: {}", r.command);
logger()->error("> Message: {}", e.what());
} catch (std::runtime_error& e) {
if (verbose > 0 || !cmd.ignore_failure()) {
logger()->error("Error running: {}", r.command);
logger()->error("> Message: {}", e.what());

if (!cmd.ignore_failure()) {
throw cloe::ConcludedError{e};
if (!cmd.ignore_failure()) {
throw cloe::ConcludedError{e};
}
}

r.error = e;
} catch (std::runtime_error& e) {
// TODO(ben): When does this happen?
if (!cmd.ignore_failure()) {
throw cloe::ConcludedError{e};
}
}

return r;
Expand Down
2 changes: 1 addition & 1 deletion engine/src/utility/command.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct CommandResult {
std::string command;
boost::optional<boost::process::child> child;
boost::optional<int> exit_code;
boost::optional<std::system_error> error;
boost::optional<std::runtime_error> error;
std::vector<std::string> output;
};

Expand Down
72 changes: 36 additions & 36 deletions engine/tests/test_engine_json_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,15 @@
"description": "whether to ignore execution failure",
"type": "boolean"
},
"log_output": {
"description": "how to log command output",
"enum": [
"never",
"on_error",
"always"
],
"type": "string"
},
"mode": {
"description": "synchronization mode to use",
"enum": [
Expand All @@ -481,15 +490,6 @@
],
"type": "string"
},
"output": {
"description": "how to log command output",
"enum": [
"never",
"normal",
"always"
],
"type": "string"
},
"path": {
"comment": "path should be executable",
"description": "path to executable",
Expand All @@ -514,6 +514,15 @@
"description": "whether to ignore execution failure",
"type": "boolean"
},
"log_output": {
"description": "how to log command output",
"enum": [
"never",
"on_error",
"always"
],
"type": "string"
},
"mode": {
"description": "synchronization mode to use",
"enum": [
Expand All @@ -522,15 +531,6 @@
"detach"
],
"type": "string"
},
"output": {
"description": "how to log command output",
"enum": [
"never",
"normal",
"always"
],
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -565,6 +565,15 @@
"description": "whether to ignore execution failure",
"type": "boolean"
},
"log_output": {
"description": "how to log command output",
"enum": [
"never",
"on_error",
"always"
],
"type": "string"
},
"mode": {
"description": "synchronization mode to use",
"enum": [
Expand All @@ -574,15 +583,6 @@
],
"type": "string"
},
"output": {
"description": "how to log command output",
"enum": [
"never",
"normal",
"always"
],
"type": "string"
},
"path": {
"comment": "path should be executable",
"description": "path to executable",
Expand All @@ -607,6 +607,15 @@
"description": "whether to ignore execution failure",
"type": "boolean"
},
"log_output": {
"description": "how to log command output",
"enum": [
"never",
"on_error",
"always"
],
"type": "string"
},
"mode": {
"description": "synchronization mode to use",
"enum": [
Expand All @@ -615,15 +624,6 @@
"detach"
],
"type": "string"
},
"output": {
"description": "how to log command output",
"enum": [
"never",
"normal",
"always"
],
"type": "string"
}
},
"required": [
Expand Down
18 changes: 9 additions & 9 deletions runtime/include/cloe/utility/command.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class Command : public Confable {
* Logging verbosity.
*/
enum class Verbosity {
Never, /// never log anything
Normal, /// log combined error when an error occurs
Always, /// log combined output
Never, /// never log anything
OnError, /// log combined error when an error occurs
Always, /// log combined output
};

Command() = default;
Expand Down Expand Up @@ -103,12 +103,12 @@ class Command : public Confable {
*/
std::string command() const;

Verbosity verbosity() const { return output_; }
Verbosity verbosity() const { return log_output_; }
Command verbosity(Verbosity v) && {
set_verbosity(v);
return std::move(*this);
}
void set_verbosity(Verbosity v) { output_ = v; }
void set_verbosity(Verbosity v) { log_output_ = v; }

Mode mode() const { return mode_; }
Command mode(Mode m) && {
Expand Down Expand Up @@ -142,13 +142,13 @@ class Command : public Confable {
{"path", make_schema(&executable_, "path to executable").require().not_empty().executable()},
{"args", make_schema(&args_, "arguments to executable")},
{"mode", make_schema(&mode_, "synchronization mode to use")},
{"output", make_schema(&output_, "how to log command output")},
{"log_output", make_schema(&log_output_, "how to log command output")},
{"ignore_failure", make_schema(&ignore_failure_, "whether to ignore execution failure")},
},
Struct{
{"command", make_schema(&command_, "command to execute within shell").require().not_empty()},
{"mode", make_schema(&mode_, "synchronization mode to use")},
{"output", make_schema(&output_, "how to log command output")},
{"log_output", make_schema(&log_output_, "how to log command output")},
{"ignore_failure", make_schema(&ignore_failure_, "whether to ignore execution failure")},
},
String{&command_, "command to execute within shell"}.not_empty(),
Expand All @@ -163,7 +163,7 @@ class Command : public Confable {
std::vector<std::string> args_;
std::string command_;
Mode mode_ = Mode::Sync;
Verbosity output_ = Verbosity::Always;
Verbosity log_output_ = Verbosity::Always;
bool ignore_failure_ = false;
};

Expand All @@ -176,7 +176,7 @@ ENUM_SERIALIZATION(Command::Mode, ({

ENUM_SERIALIZATION(Command::Verbosity, ({
{Command::Verbosity::Never, "never"},
{Command::Verbosity::Normal, "normal"},
{Command::Verbosity::OnError, "on_error"},
{Command::Verbosity::Always, "always"},
}))
// clang-format on
Expand Down
Loading