fix(script): Terminate running commands
Make sure the previous command has ended before executing a new command. This also fixes the execution block that was caused by the tailing the command output of action commands. Fixes jaagr/lemonbuddy#131
This commit is contained in:
parent
6923e0e288
commit
fa7e3d4430
@ -81,10 +81,9 @@ class controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_traymanager) {
|
if (m_command) {
|
||||||
m_log.trace("controller: Deactivate tray manager");
|
m_log.info("Terminating running shell command");
|
||||||
m_traymanager->deactivate();
|
m_command->terminate();
|
||||||
m_traymanager.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("controller: Deconstruct bar instance");
|
m_log.trace("controller: Deconstruct bar instance");
|
||||||
@ -515,17 +514,21 @@ class controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("controller: Unrecognized input '%s'", input);
|
m_clickmtx.unlock();
|
||||||
m_log.trace("controller: Forwarding input to shell");
|
|
||||||
|
|
||||||
auto command = command_util::make_command("/usr/bin/env\nsh\n-c\n" + input);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
command->exec(false);
|
if (m_command) {
|
||||||
command->tail([this](std::string output) { m_log.trace("> %s", output); });
|
m_log.warn("Terminating previous shell command");
|
||||||
command->wait();
|
m_command->terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.info("Executing shell command: %s", input);
|
||||||
|
|
||||||
|
m_command = command_util::make_command(input);
|
||||||
|
m_command->exec();
|
||||||
|
m_command.reset();
|
||||||
} catch (const application_error& err) {
|
} catch (const application_error& err) {
|
||||||
m_log.err(err.what());
|
m_log.err("controller: Error while forwarding input to shell -> %s", err.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +553,7 @@ class controller {
|
|||||||
|
|
||||||
vector<thread> m_threads;
|
vector<thread> m_threads;
|
||||||
map<alignment, vector<module_t>> m_modules;
|
map<alignment, vector<module_t>> m_modules;
|
||||||
|
command_util::command_t m_command;
|
||||||
|
|
||||||
unique_ptr<throttle_util::event_throttler> m_throttler;
|
unique_ptr<throttle_util::event_throttler> m_throttler;
|
||||||
throttle_util::strategy::try_once_or_leave_yolo m_throttle_strategy;
|
throttle_util::strategy::try_once_or_leave_yolo m_throttle_strategy;
|
||||||
|
@ -294,7 +294,6 @@ namespace modules {
|
|||||||
|
|
||||||
void wakeup() {
|
void wakeup() {
|
||||||
m_log.trace("%s: Release sleep lock", name());
|
m_log.trace("%s: Release sleep lock", name());
|
||||||
// std::unique_lock<std::mutex> lck(m_sleeplock);
|
|
||||||
m_sleephandler.notify_all();
|
m_sleephandler.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
LEMONBUDDY_NS
|
LEMONBUDDY_NS
|
||||||
|
|
||||||
#define SHELL_CMD "/usr/bin/env\nsh\n-c\n%cmd%"
|
|
||||||
#define OUTPUT_ACTION(BUTTON) \
|
#define OUTPUT_ACTION(BUTTON) \
|
||||||
if (!m_actions[BUTTON].empty()) \
|
if (!m_actions[BUTTON].empty()) \
|
||||||
m_builder->cmd(BUTTON, string_util::replace_all(m_actions[BUTTON], "%counter%", counter_str))
|
m_builder->cmd(BUTTON, string_util::replace_all(m_actions[BUTTON], "%counter%", counter_str))
|
||||||
@ -35,11 +34,12 @@ namespace modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
|
if (m_command && m_command->is_running()) {
|
||||||
|
m_log.warn("%s: Stopping shell command", name());
|
||||||
|
m_command->terminate();
|
||||||
|
}
|
||||||
wakeup();
|
wakeup();
|
||||||
enable(false);
|
event_module::stop();
|
||||||
m_command.reset();
|
|
||||||
std::lock_guard<threading_util::spin_lock> lck(m_updatelock);
|
|
||||||
wakeup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void idle() {
|
void idle() {
|
||||||
@ -64,7 +64,7 @@ namespace modules {
|
|||||||
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
||||||
m_log.trace("%s: Executing '%s'", name(), exec);
|
m_log.trace("%s: Executing '%s'", name(), exec);
|
||||||
|
|
||||||
m_command = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec));
|
m_command = command_util::make_command(exec);
|
||||||
m_command->exec(false);
|
m_command->exec(false);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
@ -89,13 +89,17 @@ namespace modules {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
if (m_command && m_command->is_running()) {
|
||||||
auto cmd = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec));
|
m_log.warn("%s: Previous shell command is still running...", name());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
||||||
m_log.trace("%s: Executing '%s'", name(), exec);
|
m_log.trace("%s: Executing '%s'", name(), exec);
|
||||||
|
|
||||||
cmd->exec(true);
|
m_command = command_util::make_command(exec);
|
||||||
cmd->tail([&](string output) { m_output = output; });
|
m_command->exec();
|
||||||
|
m_command->tail([&](string output) { m_output = output; });
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
m_log.err("%s: %s", name(), err.what());
|
m_log.err("%s: %s", name(), err.what());
|
||||||
throw module_error("Failed to execute command, stopping module...");
|
throw module_error("Failed to execute command, stopping module...");
|
||||||
|
@ -32,7 +32,7 @@ namespace command_util {
|
|||||||
*
|
*
|
||||||
* @code cpp
|
* @code cpp
|
||||||
* auto cmd = command_util::make_command(
|
* auto cmd = command_util::make_command(
|
||||||
* "/bin/sh\n-c\n while read -r line; do echo data from parent process: $line; done");
|
* "while read -r line; do echo data from parent process: $line; done");
|
||||||
* cmd->exec(false);
|
* cmd->exec(false);
|
||||||
* cmd->writeline("Test");
|
* cmd->writeline("Test");
|
||||||
* cout << cmd->readline();
|
* cout << cmd->readline();
|
||||||
@ -40,8 +40,7 @@ namespace command_util {
|
|||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* @code cpp
|
* @code cpp
|
||||||
* vector<string> exec{{"/bin/sh"}, {"-c"}, {"for i in 1 2 3; do echo $i; done"}};
|
* auto cmd = command_util::make_command("for i in 1 2 3; do echo $i; done");
|
||||||
* auto cmd = command_util::make_command(exec);
|
|
||||||
* cmd->exec();
|
* cmd->exec();
|
||||||
* cout << cmd->readline(); // 1
|
* cout << cmd->readline(); // 1
|
||||||
* cout << cmd->readline() << cmd->readline(); // 23
|
* cout << cmd->readline() << cmd->readline(); // 23
|
||||||
@ -49,10 +48,8 @@ namespace command_util {
|
|||||||
*/
|
*/
|
||||||
class command {
|
class command {
|
||||||
public:
|
public:
|
||||||
explicit command(const logger& logger, vector<string> cmd)
|
explicit command(const logger& logger, string cmd)
|
||||||
: command(logger, string_util::join(cmd, "\n")) {}
|
: m_log(logger), m_cmd("/usr/bin/env\nsh\n-c\n" + cmd) {
|
||||||
|
|
||||||
explicit command(const logger& logger, string cmd) : m_log(logger), m_cmd(cmd) {
|
|
||||||
if (pipe(m_stdin) != 0)
|
if (pipe(m_stdin) != 0)
|
||||||
throw command_strerror("Failed to allocate input stream");
|
throw command_strerror("Failed to allocate input stream");
|
||||||
if (pipe(m_stdout) != 0)
|
if (pipe(m_stdout) != 0)
|
||||||
@ -140,10 +137,10 @@ namespace command_util {
|
|||||||
* Wait for the child processs to finish
|
* Wait for the child processs to finish
|
||||||
*/
|
*/
|
||||||
int wait() {
|
int wait() {
|
||||||
auto waitflags = WCONTINUED | WUNTRACED;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
process_util::wait_for_completion(m_forkpid, &m_forkstatus, waitflags);
|
m_log.trace("command: Waiting for pid %d to finish...", m_forkpid);
|
||||||
|
|
||||||
|
process_util::wait_for_completion(m_forkpid, &m_forkstatus, WCONTINUED | WUNTRACED);
|
||||||
|
|
||||||
if (WIFEXITED(m_forkstatus) && m_forkstatus > 0)
|
if (WIFEXITED(m_forkstatus) && m_forkstatus > 0)
|
||||||
m_log.warn("command: Exited with failed status %d", WEXITSTATUS(m_forkstatus));
|
m_log.warn("command: Exited with failed status %d", WEXITSTATUS(m_forkstatus));
|
||||||
@ -155,6 +152,8 @@ namespace command_util {
|
|||||||
m_log.trace("command: Stopped by signal %d", WSTOPSIG(m_forkstatus));
|
m_log.trace("command: Stopped by signal %d", WSTOPSIG(m_forkstatus));
|
||||||
else if (WIFCONTINUED(m_forkstatus) == true)
|
else if (WIFCONTINUED(m_forkstatus) == true)
|
||||||
m_log.trace("command: Continued");
|
m_log.trace("command: Continued");
|
||||||
|
else
|
||||||
|
break;
|
||||||
} while (!WIFEXITED(m_forkstatus) && !WIFSIGNALED(m_forkstatus));
|
} while (!WIFEXITED(m_forkstatus) && !WIFSIGNALED(m_forkstatus));
|
||||||
|
|
||||||
return m_forkstatus;
|
return m_forkstatus;
|
||||||
@ -162,6 +161,9 @@ namespace command_util {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tail command output
|
* Tail command output
|
||||||
|
*
|
||||||
|
* @note: This is a blocking call and will not
|
||||||
|
* end until the stream is closed
|
||||||
*/
|
*/
|
||||||
void tail(function<void(string)> callback) {
|
void tail(function<void(string)> callback) {
|
||||||
io_util::tail(m_stdout[PIPE_READ], callback);
|
io_util::tail(m_stdout[PIPE_READ], callback);
|
||||||
@ -238,8 +240,7 @@ namespace command_util {
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
command_t make_command(Args&&... args) {
|
command_t make_command(Args&&... args) {
|
||||||
return make_unique<command>(
|
return make_unique<command>(configure_logger().create<const logger&>(), forward<Args>(args)...);
|
||||||
configure_logger().create<const logger&>(), forward<Args>(args)...);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user