mirror of
https://github.com/avatao-content/baseimage-tutorial-framework
synced 2025-06-28 18:25:12 +00:00
Add a huge bunch of docstrings
This commit is contained in:
@ -24,6 +24,17 @@ class CallbackEventHandler(PatternMatchingEventHandler, ABC):
|
||||
|
||||
|
||||
class HistoryMonitor(CallbackMixin, ObserverMixin, ABC):
|
||||
"""
|
||||
Abstract class capable of monitoring and parsing a history file such as
|
||||
bash HISTFILEs. Monitoring means detecting when the file was changed and
|
||||
notifying subscribers about new content in the file.
|
||||
|
||||
This is useful for monitoring CLI sessions.
|
||||
|
||||
To specify a custom HistoryMonitor inherit from this class and override the
|
||||
command pattern property and optionally the sanitize_command method.
|
||||
See examples below.
|
||||
"""
|
||||
def __init__(self, histfile):
|
||||
CallbackMixin.__init__(self)
|
||||
ObserverMixin.__init__(self)
|
||||
@ -61,6 +72,15 @@ class HistoryMonitor(CallbackMixin, ObserverMixin, ABC):
|
||||
|
||||
|
||||
class BashMonitor(HistoryMonitor):
|
||||
"""
|
||||
HistoryMonitor for monitoring bash CLI sessions.
|
||||
This requires the following to be set in bash
|
||||
(note that this is done automatically by TFW):
|
||||
PROMPT_COMMAND="history -a"
|
||||
shopt -s cmdhist
|
||||
shopt -s histappend
|
||||
unset HISTCONTROL
|
||||
"""
|
||||
@property
|
||||
def command_pattern(self):
|
||||
return r'.+'
|
||||
@ -70,6 +90,10 @@ class BashMonitor(HistoryMonitor):
|
||||
|
||||
|
||||
class GDBMonitor(HistoryMonitor):
|
||||
"""
|
||||
HistoryMonitor to monitor GDB sessions.
|
||||
For this to work "set trace-commands on" must be set in GDB.
|
||||
"""
|
||||
@property
|
||||
def command_pattern(self):
|
||||
return r'(?<=\n)\+(.+)\n'
|
||||
|
@ -23,6 +23,18 @@ class ProcessManager(SupervisorMixin):
|
||||
|
||||
|
||||
class ProcessManagingEventHandler(EventHandlerBase):
|
||||
"""
|
||||
Event handler that can manage processes managed by supervisor.
|
||||
|
||||
This EventHandler accepts messages that have a data["command"] key specifying
|
||||
a command to be executed.
|
||||
Every message must contain a data["process_name"] field with the name of the
|
||||
process to manage. This is the name specified in supervisor config files like so:
|
||||
[program:someprogram]
|
||||
|
||||
Commands available: start, stop, restart, readlog
|
||||
(the names are as self-documenting as it gets)
|
||||
"""
|
||||
def __init__(self, key, dirmonitor=None):
|
||||
super().__init__(key)
|
||||
self.key = key
|
||||
|
@ -11,7 +11,20 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TerminadoEventHandler(EventHandlerBase):
|
||||
"""
|
||||
Event handler responsible for managing terminal sessions for frontend xterm
|
||||
sessions to connect to. You need to instanciate this in order for frontend
|
||||
terminals to work.
|
||||
|
||||
This EventHandler accepts messages that have a data["command"] key specifying
|
||||
a command to be executed.
|
||||
The API of each command is documented in their respective handlers.
|
||||
"""
|
||||
def __init__(self, key, monitor):
|
||||
"""
|
||||
:param key: key this EventHandler listens to
|
||||
:param monitor: tfw.components.HistoryMonitor instance to read command history from
|
||||
"""
|
||||
super().__init__(key)
|
||||
self.working_directory = TFWENV.TERMINADO_DIR
|
||||
self._historymonitor = monitor
|
||||
@ -37,9 +50,21 @@ class TerminadoEventHandler(EventHandlerBase):
|
||||
LOG.error('IGNORING MESSAGE: Invalid message received: %s', message)
|
||||
|
||||
def write(self, data):
|
||||
"""
|
||||
Writes a string to the terminal session (on the pty level).
|
||||
Useful for pre-typing and executing commands for the user.
|
||||
|
||||
:param data['shellcmd']: command to be written to the pty
|
||||
"""
|
||||
self.terminado_server.pty.write(data['shellcmd'])
|
||||
|
||||
def read(self, data):
|
||||
"""
|
||||
Reads the history of commands executed.
|
||||
|
||||
:param data['count']: the number of history elements to return
|
||||
:return: message with list of commands in data['history']
|
||||
"""
|
||||
data['count'] = int(data.get('count', 1))
|
||||
if self.historymonitor:
|
||||
data['history'] = self.historymonitor.history[-data['count']:]
|
||||
|
@ -10,6 +10,24 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TerminalCommands(ABC):
|
||||
"""
|
||||
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.
|
||||
|
||||
Inherit from this class and define methods which start with "command_". When the user
|
||||
executes the command specified after the underscore, your method will be invoked. All
|
||||
such commands must expect the parameter *args which will contain the arguments of the
|
||||
command.
|
||||
|
||||
For example to define a method that runs when someone starts vim in the terminal
|
||||
you have to define a method like: "def command_vim(self, *args)"
|
||||
|
||||
You can also use this class to create new commands similarly.
|
||||
"""
|
||||
def __init__(self, bashrc=None):
|
||||
self._command_method_regex = r'^command_(.+)$'
|
||||
self.command_implemetations = self._build_command_to_implementation_dict()
|
||||
|
@ -93,7 +93,23 @@ class FileManager: # pylint: disable=too-many-instance-attributes
|
||||
|
||||
class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
# pylint: disable=too-many-arguments
|
||||
"""
|
||||
Event handler implementing the backend of our browser based IDE.
|
||||
By default all files in the directory specified in __init__ are displayed
|
||||
on the fontend. Note that this is a stateful component.
|
||||
|
||||
This EventHandler accepts messages that have a data["command"] key specifying
|
||||
a command to be executed.
|
||||
The API of each command is documented in their respective handlers.
|
||||
"""
|
||||
def __init__(self, key, directory, allowed_directories, selected_file=None, exclude=None):
|
||||
"""
|
||||
:param key: the key this instance should listen to
|
||||
:param directory: working directory which the EventHandler should serve files from
|
||||
:param allowed_directories: list of directories that can be switched to using the selectdir command
|
||||
:param selected_file: file that is selected by default
|
||||
:param exclude: list of filenames that should not appear between files (for *.o, *.pyc, etc.)
|
||||
"""
|
||||
super().__init__(key)
|
||||
self.filemanager = FileManager(allowed_directories=allowed_directories, working_directory=directory,
|
||||
selected_file=selected_file, exclude=exclude)
|
||||
@ -106,6 +122,11 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
'exclude': self.exclude}
|
||||
|
||||
def read(self, data):
|
||||
"""
|
||||
Read the currently selected file.
|
||||
|
||||
:return: message with the contents of the file in data['content']
|
||||
"""
|
||||
try:
|
||||
data['content'] = self.filemanager.file_contents
|
||||
except PermissionError:
|
||||
@ -117,6 +138,11 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
return data
|
||||
|
||||
def write(self, data):
|
||||
"""
|
||||
Overwrites a file with the desired string.
|
||||
|
||||
:param data['content']: string containing the desired file contents
|
||||
"""
|
||||
self.monitor.ignore = self.monitor.ignore + 1
|
||||
try:
|
||||
self.filemanager.file_contents = data['content']
|
||||
@ -126,6 +152,11 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
return data
|
||||
|
||||
def select(self, data):
|
||||
"""
|
||||
Selects a file from the current directory.
|
||||
|
||||
:param data['filename']: name of file to select relative to the current directory
|
||||
"""
|
||||
try:
|
||||
self.filemanager.filename = data['filename']
|
||||
except EnvironmentError:
|
||||
@ -133,6 +164,13 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
return data
|
||||
|
||||
def select_dir(self, data):
|
||||
"""
|
||||
Select a new working directory to display files from.
|
||||
|
||||
:param data['directory']: absolute path of diretory to select.
|
||||
must be a path whitelisted in
|
||||
self.allowed_directories
|
||||
"""
|
||||
try:
|
||||
self.filemanager.workdir = data['directory']
|
||||
self.reload_monitor()
|
||||
@ -146,6 +184,11 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
return data
|
||||
|
||||
def exclude(self, data):
|
||||
"""
|
||||
Overwrite list of excluded files
|
||||
|
||||
:param data['exclude']: list of filename patterns to be excluded, e.g.: ["*.pyc", "*.o"]
|
||||
"""
|
||||
try:
|
||||
self.filemanager.exclude = list(data['exclude'])
|
||||
except TypeError:
|
||||
@ -153,6 +196,9 @@ class WebideEventHandler(EventHandlerBase, MonitorManagerMixin):
|
||||
return data
|
||||
|
||||
def attach_fileinfo(self, data):
|
||||
"""
|
||||
Basic information included in every response to the frontend.
|
||||
"""
|
||||
data['filename'] = self.filemanager.filename
|
||||
data['files'] = self.filemanager.files
|
||||
data['directory'] = self.filemanager.workdir
|
||||
|
Reference in New Issue
Block a user