2019-06-10 13:32:45 +00:00
|
|
|
import logging
|
2018-04-12 08:56:15 +00:00
|
|
|
from abc import ABC
|
|
|
|
from re import match
|
2018-05-26 20:39:27 +00:00
|
|
|
from shlex import split
|
2018-04-12 08:56:15 +00:00
|
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class TerminalCommands(ABC):
|
2018-07-16 09:17:06 +00:00
|
|
|
# pylint: disable=anomalous-backslash-in-string
|
2018-04-18 17:44:26 +00:00
|
|
|
"""
|
|
|
|
A class you can use to define hooks for terminal commands. This means that you can
|
|
|
|
have python code executed when the user enters a specific command to the terminal on
|
|
|
|
our frontend.
|
|
|
|
|
|
|
|
To receive events you need to subscribe TerminalCommand.callback to a HistoryMonitor
|
|
|
|
instance.
|
|
|
|
|
2018-06-01 14:20:20 +00:00
|
|
|
Inherit from this class and define methods which start with "command\_". When the user
|
2018-04-18 17:44:26 +00:00
|
|
|
executes the command specified after the underscore, your method will be invoked. All
|
2018-06-01 14:20:20 +00:00
|
|
|
such commands must expect the parameter \*args which will contain the arguments of the
|
2018-04-18 17:44:26 +00:00
|
|
|
command.
|
|
|
|
|
|
|
|
For example to define a method that runs when someone starts vim in the terminal
|
2018-06-01 14:20:20 +00:00
|
|
|
you have to define a method like: "def command_vim(self, \*args)"
|
2018-04-18 17:44:26 +00:00
|
|
|
|
|
|
|
You can also use this class to create new commands similarly.
|
|
|
|
"""
|
2019-07-12 21:25:16 +00:00
|
|
|
def __init__(self, bashrc):
|
2018-04-12 08:56:15 +00:00
|
|
|
self._command_method_regex = r'^command_(.+)$'
|
2018-04-13 08:01:45 +00:00
|
|
|
self.command_implemetations = self._build_command_to_implementation_dict()
|
2018-04-12 09:07:56 +00:00
|
|
|
if bashrc is not None:
|
|
|
|
self._setup_bashrc_aliases(bashrc)
|
|
|
|
|
2018-04-13 08:01:45 +00:00
|
|
|
def _build_command_to_implementation_dict(self):
|
2018-06-04 20:16:44 +00:00
|
|
|
return {
|
|
|
|
self._parse_command_name(fun): getattr(self, fun)
|
|
|
|
for fun in dir(self)
|
|
|
|
if callable(getattr(self, fun))
|
|
|
|
and self._is_command_implementation(fun)
|
|
|
|
}
|
2018-04-13 08:01:45 +00:00
|
|
|
|
2018-04-12 09:07:56 +00:00
|
|
|
def _setup_bashrc_aliases(self, bashrc):
|
|
|
|
with open(bashrc, 'a') as ofile:
|
2018-04-18 14:22:01 +00:00
|
|
|
alias_template = 'type {0} &> /dev/null || alias {0}="{0} &> /dev/null"\n'
|
2018-04-12 09:07:56 +00:00
|
|
|
for command in self.command_implemetations.keys():
|
|
|
|
ofile.write(alias_template.format(command))
|
2018-04-12 08:56:15 +00:00
|
|
|
|
|
|
|
def _is_command_implementation(self, method_name):
|
|
|
|
return bool(self._match_command_regex(method_name))
|
|
|
|
|
|
|
|
def _parse_command_name(self, method_name):
|
|
|
|
try:
|
|
|
|
return self._match_command_regex(method_name).groups()[0]
|
|
|
|
except AttributeError:
|
|
|
|
return ''
|
|
|
|
|
|
|
|
def _match_command_regex(self, string):
|
|
|
|
return match(self._command_method_regex, string)
|
|
|
|
|
2019-06-11 15:25:35 +00:00
|
|
|
def callback(self, command):
|
|
|
|
parts = split(command)
|
2018-04-12 08:56:15 +00:00
|
|
|
command = parts[0]
|
|
|
|
if command in self.command_implemetations.keys():
|
|
|
|
try:
|
|
|
|
self.command_implemetations[command](*parts[1:])
|
2018-05-26 20:48:28 +00:00
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
LOG.exception('Command "%s" failed:', command)
|