Merge pull request #461 from rrhuffy/shell
[modules/shell] Add shell module: Execute command in shell and print …
This commit is contained in:
commit
2a504ded78
2 changed files with 92 additions and 1 deletions
|
@ -5,7 +5,7 @@
|
||||||
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
||||||
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
||||||
|
|
||||||
**Many, many thanks to all contributors! As of now, 50 of the modules are from various contributors (!), and only 19 from myself.**
|
**Many, many thanks to all contributors! As of now, 51 of the modules are from various contributors (!), and only 19 from myself.**
|
||||||
|
|
||||||
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
||||||
|
|
||||||
|
|
91
bumblebee/modules/shell.py
Normal file
91
bumblebee/modules/shell.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
# pylint: disable=C0111,R0903,W1401
|
||||||
|
|
||||||
|
""" Execute command in shell and print result
|
||||||
|
|
||||||
|
Few command examples:
|
||||||
|
'ping 1.1.1.1 -c 1 | grep -Po "(?<=time=)\d+(\.\d+)? ms"'
|
||||||
|
'echo "BTC=$(curl -s rate.sx/1BTC | grep -Po \"^\d+\")USD"'
|
||||||
|
'curl -s https://wttr.in/London?format=%l+%t+%h+%w'
|
||||||
|
'pip3 freeze | wc -l'
|
||||||
|
'any_custom_script.sh | grep arguments'
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* shell.command: Command to execute
|
||||||
|
Use single parentheses if evaluating anything inside
|
||||||
|
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.interval: Update interval in minutes
|
||||||
|
(defaults to 1s == every bumblebee-status update)
|
||||||
|
* shell.async: Run update in async mode. Won't run next thread if
|
||||||
|
previous one didn't finished yet. Useful for long
|
||||||
|
running scripts to avoid bumblebee-status freezes
|
||||||
|
(defaults to False)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import bumblebee.engine
|
||||||
|
import bumblebee.input
|
||||||
|
import bumblebee.output
|
||||||
|
|
||||||
|
|
||||||
|
class Module(bumblebee.engine.Module):
|
||||||
|
def __init__(self, engine, config):
|
||||||
|
widget = bumblebee.output.Widget(full_text=self.get_output)
|
||||||
|
super(Module, self).__init__(engine, config, widget)
|
||||||
|
|
||||||
|
if self.parameter('interval'):
|
||||||
|
self.interval(self.parameter('interval'))
|
||||||
|
|
||||||
|
self._command = self.parameter('command')
|
||||||
|
self._async = bumblebee.util.asbool(self.parameter('async'))
|
||||||
|
if self._async:
|
||||||
|
self._output = 'Computing...'
|
||||||
|
self._current_thread = None
|
||||||
|
else:
|
||||||
|
self._output = ''
|
||||||
|
|
||||||
|
# LMB and RMB will update output regardless of timer
|
||||||
|
engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self.update)
|
||||||
|
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self.update)
|
||||||
|
|
||||||
|
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 = self._get_command_output_or_error(self._command)
|
||||||
|
return
|
||||||
|
|
||||||
|
# if previous thread didn't end yet then don't do anything
|
||||||
|
if self._current_thread:
|
||||||
|
return
|
||||||
|
|
||||||
|
# spawn new thread to execute command and pass callback method to get output from it
|
||||||
|
self._current_thread = threading.Thread(target=self._run_command_in_thread,
|
||||||
|
args=(self._command, self._output_function))
|
||||||
|
self._current_thread.start()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_command_output_or_error(command):
|
||||||
|
try:
|
||||||
|
command_output = subprocess.check_output(command,
|
||||||
|
shell=True,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
return command_output.decode('utf-8').strip()
|
||||||
|
except subprocess.CalledProcessError as exception:
|
||||||
|
exception_output = exception.output.decode('utf-8').replace('\n', '')
|
||||||
|
return 'Status:{} output:{}'.format(exception.returncode, exception_output)
|
||||||
|
|
||||||
|
def _run_command_in_thread(self, command, output_callback):
|
||||||
|
output_callback(self._get_command_output_or_error(command))
|
||||||
|
|
||||||
|
def _output_function(self, text):
|
||||||
|
self._output = text
|
||||||
|
# clear this thread data, so next update will spawn a new one
|
||||||
|
self._current_thread = None
|
||||||
|
|
||||||
|
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
Loading…
Reference in a new issue