mirror of
https://github.com/polybar/polybar.git
synced 2024-11-18 13:55:11 -05:00
fix(script): Rerun tail script when done
- Improve handling of command life time proc - Restart tail command on successful completion - Should fix jaagr/lemonbuddy#105
This commit is contained in:
parent
20ca754629
commit
7e960a3966
3 changed files with 88 additions and 88 deletions
|
@ -76,8 +76,8 @@ class controller {
|
|||
m_log.trace("controller: Stop modules");
|
||||
for (auto&& block : m_modules) {
|
||||
for (auto&& module : block.second) {
|
||||
module->on_update.disconnect(this, &controller::on_module_update);
|
||||
module->on_stop.disconnect(this, &controller::on_module_stop);
|
||||
module->on_update.clear();
|
||||
module->on_stop.clear();
|
||||
module->stop();
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class controller {
|
|||
}
|
||||
|
||||
m_log.trace("controller: Deconstruct bar instance");
|
||||
g_signals::bar::action_click.disconnect(this, &controller::on_module_click);
|
||||
g_signals::bar::action_click.clear();
|
||||
m_bar.reset();
|
||||
|
||||
m_log.trace("controller: Interrupt X event loop");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
LEMONBUDDY_NS
|
||||
|
||||
#define SHELL_CMD "/usr/bin/env\nsh\n-c\n"
|
||||
#define SHELL_CMD "/usr/bin/env\nsh\n-c\n%cmd%"
|
||||
#define OUTPUT_ACTION(BUTTON) \
|
||||
if (!m_actions[BUTTON].empty()) \
|
||||
m_builder->cmd(BUTTON, string_util::replace_all(m_actions[BUTTON], "%counter%", counter_str))
|
||||
|
@ -18,7 +18,8 @@ namespace modules {
|
|||
void setup() {
|
||||
m_formatter->add(DEFAULT_FORMAT, TAG_OUTPUT, {TAG_OUTPUT});
|
||||
|
||||
// Load configuration values {{{
|
||||
// Load configuration values
|
||||
|
||||
REQ_CONFIG_VALUE(name(), m_exec, "exec");
|
||||
GET_CONFIG_VALUE(name(), m_tail, "tail");
|
||||
GET_CONFIG_VALUE(name(), m_maxlen, "maxlen");
|
||||
|
@ -30,113 +31,99 @@ namespace modules {
|
|||
m_actions[mousebtn::SCROLL_UP] = m_conf.get<string>(name(), "scroll-up", "");
|
||||
m_actions[mousebtn::SCROLL_DOWN] = m_conf.get<string>(name(), "scroll-down", "");
|
||||
|
||||
if (!m_tail) {
|
||||
m_interval = interval_t{m_conf.get<float>(name(), "interval", m_interval.count())};
|
||||
}
|
||||
// }}}
|
||||
// Execute the tail command {{{
|
||||
if (m_tail) {
|
||||
try {
|
||||
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
||||
m_log.trace("%s: Executing '%s'", name(), exec);
|
||||
|
||||
m_command = command_util::make_command(SHELL_CMD + exec);
|
||||
m_command->exec(false);
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("%s: Failed to execute tail command, stopping module..", name());
|
||||
m_log.err("%s: %s", name(), err.what());
|
||||
stop();
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
m_interval = interval_t{m_conf.get<float>(name(), "interval", 0.0f)};
|
||||
}
|
||||
|
||||
void stop() {
|
||||
// Put the module in stopped state {{{
|
||||
event_module::stop();
|
||||
// }}}
|
||||
// Terminate running command {{{
|
||||
try {
|
||||
if (m_tail && m_command)
|
||||
m_command.reset();
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("%s: %s", name(), err.what());
|
||||
}
|
||||
// }}}
|
||||
wakeup();
|
||||
enable(false);
|
||||
m_command.reset();
|
||||
std::lock_guard<threading_util::spin_lock> lck(this->update_lock);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
void idle() {
|
||||
if (!enabled())
|
||||
sleep(100ms);
|
||||
if (!m_tail)
|
||||
sleep(m_interval);
|
||||
else if (!m_command || !m_command->is_running())
|
||||
sleep(m_interval);
|
||||
}
|
||||
|
||||
bool has_event() {
|
||||
// Handle non-tailing command {{{
|
||||
if (!m_tail) {
|
||||
sleep(m_interval);
|
||||
return enabled();
|
||||
}
|
||||
// }}}
|
||||
// Handle tailing command {{{
|
||||
if (!m_command || !m_command->is_running()) {
|
||||
m_log.warn("%s: Tail command finished, stopping module...", name());
|
||||
stop();
|
||||
return false;
|
||||
} else if ((m_output = m_command->readline()) != m_prev) {
|
||||
m_prev = m_output;
|
||||
// Non tail commands should always run
|
||||
if (!m_tail)
|
||||
return true;
|
||||
} else {
|
||||
|
||||
if (!enabled())
|
||||
return false;
|
||||
|
||||
try {
|
||||
if (!m_command || !m_command->is_running()) {
|
||||
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
||||
m_log.trace("%s: Executing '%s'", name(), exec);
|
||||
|
||||
m_command = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec));
|
||||
m_command->exec(false);
|
||||
}
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("%s: %s", name(), err.what());
|
||||
throw module_error(name() + ": Failed to execute tail command, stopping module...");
|
||||
}
|
||||
// }}}
|
||||
|
||||
if (!m_command)
|
||||
return false;
|
||||
|
||||
if ((m_output = m_command->readline()) == m_prev)
|
||||
return false;
|
||||
|
||||
m_prev = m_output;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update() {
|
||||
// Handle tailing command {{{
|
||||
// Tailing commands always update
|
||||
if (m_tail)
|
||||
return true;
|
||||
// }}}
|
||||
// Handle non-tailing command {{{
|
||||
|
||||
try {
|
||||
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
||||
auto cmd = command_util::make_command(SHELL_CMD + exec);
|
||||
auto cmd = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec));
|
||||
|
||||
m_log.trace("%s: Executing '%s'", name(), exec);
|
||||
|
||||
cmd->exec();
|
||||
cmd->tail([this](string contents) { m_output = contents; });
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("%s: Failed to execute command, stopping module..", name());
|
||||
m_log.err("%s: %s", name(), err.what());
|
||||
stop();
|
||||
throw module_error(name() + ": Failed to execute command, stopping module...");
|
||||
}
|
||||
|
||||
if (m_output == m_prev)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_output != m_prev) {
|
||||
m_prev = m_output;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// }}}
|
||||
m_prev = m_output;
|
||||
return true;
|
||||
}
|
||||
|
||||
string get_output() {
|
||||
if (m_output.empty())
|
||||
return " ";
|
||||
|
||||
// Truncate output to the defined max length {{{
|
||||
|
||||
// Truncate output to the defined max length
|
||||
if (m_maxlen > 0 && m_output.length() > m_maxlen) {
|
||||
m_output.erase(m_maxlen);
|
||||
m_output += m_ellipsis ? "..." : "";
|
||||
}
|
||||
// }}}
|
||||
// Add mousebtn command handlers {{{
|
||||
auto counter_str = to_string(m_counter);
|
||||
|
||||
auto counter_str = to_string(m_counter);
|
||||
OUTPUT_ACTION(mousebtn::LEFT);
|
||||
OUTPUT_ACTION(mousebtn::MIDDLE);
|
||||
OUTPUT_ACTION(mousebtn::RIGHT);
|
||||
OUTPUT_ACTION(mousebtn::SCROLL_UP);
|
||||
OUTPUT_ACTION(mousebtn::SCROLL_DOWN);
|
||||
// }}}
|
||||
|
||||
m_builder->node(module::get_output());
|
||||
|
||||
return m_builder->flush();
|
||||
|
@ -156,7 +143,7 @@ namespace modules {
|
|||
|
||||
string m_exec;
|
||||
bool m_tail = false;
|
||||
interval_t m_interval = 1s;
|
||||
interval_t m_interval = 0s;
|
||||
size_t m_maxlen = 0;
|
||||
bool m_ellipsis = true;
|
||||
map<mousebtn, string> m_actions;
|
||||
|
|
|
@ -60,15 +60,8 @@ namespace command_util {
|
|||
}
|
||||
|
||||
~command() {
|
||||
if (is_running()) {
|
||||
try {
|
||||
m_log.trace("command: Sending SIGTERM to running child process (%d)", m_forkpid);
|
||||
killpg(m_forkpid, SIGTERM);
|
||||
wait();
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("command: %s", err.what());
|
||||
}
|
||||
}
|
||||
if (is_running())
|
||||
terminate();
|
||||
|
||||
if (m_stdin[PIPE_READ] > 0)
|
||||
close(m_stdin[PIPE_READ]);
|
||||
|
@ -119,13 +112,30 @@ namespace command_util {
|
|||
if ((m_stdout[PIPE_WRITE] = close(m_stdout[PIPE_WRITE])) == -1)
|
||||
throw command_strerror("Failed to close fd");
|
||||
|
||||
if (wait_for_completion)
|
||||
return wait();
|
||||
if (wait_for_completion) {
|
||||
auto status = wait();
|
||||
m_forkpid = -1;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void terminate() {
|
||||
try {
|
||||
if (is_running()) {
|
||||
m_log.trace("command: Sending SIGTERM to running child process (%d)", m_forkpid);
|
||||
killpg(m_forkpid, SIGTERM);
|
||||
wait();
|
||||
}
|
||||
} catch (const command_error& err) {
|
||||
m_log.warn("%s", err.what());
|
||||
}
|
||||
|
||||
m_forkpid = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the child processs to finish
|
||||
*/
|
||||
|
@ -133,11 +143,12 @@ namespace command_util {
|
|||
auto waitflags = WCONTINUED | WUNTRACED;
|
||||
|
||||
do {
|
||||
if (process_util::wait_for_completion(m_forkpid, &m_forkstatus, waitflags) == -1)
|
||||
throw command_error("Process did not finish successfully");
|
||||
process_util::wait_for_completion(m_forkpid, &m_forkstatus, waitflags);
|
||||
|
||||
if (WIFEXITED(m_forkstatus))
|
||||
m_log.trace("command: Exited with status %d", WEXITSTATUS(m_forkstatus));
|
||||
if (WIFEXITED(m_forkstatus) && m_forkstatus > 0)
|
||||
m_log.warn("command: Exited with failed status %d", WEXITSTATUS(m_forkstatus));
|
||||
else if (WIFEXITED(m_forkstatus))
|
||||
m_log.warn("command: Exited with status %d", WEXITSTATUS(m_forkstatus));
|
||||
else if (WIFSIGNALED(m_forkstatus))
|
||||
m_log.trace("command: killed by signal %d", WTERMSIG(m_forkstatus));
|
||||
else if (WIFSTOPPED(m_forkstatus))
|
||||
|
@ -197,7 +208,9 @@ namespace command_util {
|
|||
* Check if command is running
|
||||
*/
|
||||
bool is_running() {
|
||||
return process_util::wait_for_completion_nohang(m_forkpid, &m_forkstatus) > -1;
|
||||
if (m_forkpid > 0)
|
||||
return process_util::wait_for_completion_nohang(m_forkpid, &m_forkstatus) > -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue