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

Adding shell command execution on click for shell module #990

Closed
wants to merge 4 commits into from
Closed
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
36 changes: 34 additions & 2 deletions bumblebee_status/modules/contrib/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
For example shell.command='echo $(date +'%H:%M:%S')'
But NOT shell.command='echo $(date +'%H:%M:%S')'
Second one will be evaluated only once at startup
* shell.left_click_command: Command to execute on
left mouse button click. Clicked commands are always
executed synchronously.
Command formatting rules described above applies here
* shell.right_click_command: Command to execute on
right mouse button click. See above.
* shell.interval: Update interval in seconds
(defaults to 1s == every bumblebee-status update)
* shell.async: Run update in async mode. Won't run next thread if
Expand All @@ -28,19 +34,28 @@
import os
import subprocess
import threading
import functools

import core.module
import core.widget
import core.input
import core.event
import util.format
import util.cli


class Module(core.module.Module):
def __init__(self, config, theme):
super().__init__(config, theme, core.widget.Widget(self.get_output))
self.widget = core.widget.Widget(self.get_output)
super().__init__(config, theme, self.widget)

self.__command = self.parameter("command", 'echo "no command configured"')
self.__left_click_command = self.parameter(
"left_click_command", 'echo "no left_click_command configured"'
)
self.__right_click_command = self.parameter(
"right_click_command", 'echo "no right_click_command configured"'
)
self.__async = util.format.asbool(self.parameter("async"))

if self.__async:
Expand All @@ -50,17 +65,34 @@ def __init__(self, config, theme):
if self.parameter("scrolling.makewide") is None:
self.set("scrolling.makewide", False)

for command, button in (
(self.__left_click_command, core.input.LEFT_MOUSE),
(self.__right_click_command, core.input.RIGHT_MOUSE),
):
if command is not None:
core.input.register(
self.widget,
button=button,
cmd=functools.partial(self.click_command, command=command),
)

def set_output(self, value):
self.__output = value

def click_command(self, event, command=None):
util.cli.execute(command, shell=True, ignore_errors=True, wait=True)
core.event.trigger("update", [self.id], redraw_only=True)

@core.decorators.scrollable
def get_output(self, _):
return self.__output

def update(self):
# if requested then run not async version and just execute command in this thread
if not self.__async:
self.__output = util.cli.execute(self.__command, shell=True, ignore_errors=True).strip()
self.set_output(
util.cli.execute(self.__command, shell=True, ignore_errors=True).strip()
)
return

# if previous thread didn't end yet then don't do anything
Expand Down
14 changes: 13 additions & 1 deletion bumblebee_status/util/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ def execute(
raise RuntimeError("{} not found".format(cmd))

if wait:
out, _ = proc.communicate()
timeout = 60 # seconds
try:
out, _ = proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired as e:
logging.warning(
f"""
Communication with process pid={proc.pid} hangs for more
than {timeout} seconds.
If this is not expected, the process is stale, or
you might have run in stdout / stderr deadlock.
"""
)
out, _ = proc.communicate()
if proc.returncode != 0:
err = "{} exited with code {}".format(cmd, proc.returncode)
logging.warning(err)
Expand Down