mirror of
https://github.com/avatao-content/baseimage-tutorial-framework
synced 2025-06-28 23:45:11 +00:00
Make files observable and refactor event handlers
This commit is contained in:
@ -1,6 +1,10 @@
|
||||
# Copyright (C) 2018 Avatao.com Innovative Learning Kft.
|
||||
# All Rights Reserved. See LICENSE file for details.
|
||||
|
||||
from pwd import getpwnam
|
||||
from grp import getgrnam
|
||||
from pathlib import Path
|
||||
from os import chown
|
||||
from os.path import dirname
|
||||
from re import findall
|
||||
from re import compile as compileregex
|
||||
@ -22,30 +26,39 @@ class HistoryMonitor(ABC, InotifyObserver):
|
||||
command pattern property and optionally the sanitize_command method.
|
||||
See examples below.
|
||||
"""
|
||||
def __init__(self, domain, histfile):
|
||||
self.domain = domain
|
||||
def __init__(self, uplink, histfile):
|
||||
self._domain = ''
|
||||
self.histfile = histfile
|
||||
self._history = []
|
||||
self._last_length = len(self._history)
|
||||
self.uplink = TFWServerUplinkConnector()
|
||||
super().__init__(dirname(self.histfile), [self.histfile])
|
||||
self.history = []
|
||||
self._last_length = len(self.history)
|
||||
self.uplink = uplink
|
||||
uid = getpwnam('user').pw_uid
|
||||
gid = getgrnam('users').gr_gid
|
||||
path = Path(self.histfile)
|
||||
path.touch()
|
||||
chown(self.histfile, uid, gid)
|
||||
super().__init__(self.histfile)
|
||||
|
||||
@property
|
||||
def domain(self):
|
||||
return self._domain
|
||||
|
||||
@domain.setter
|
||||
def domain(self, domain):
|
||||
self._domain = domain
|
||||
|
||||
def on_modified(self, event):
|
||||
self._fetch_history()
|
||||
if self._last_length < len(self._history):
|
||||
for command in self._history[self._last_length:]:
|
||||
if self._last_length < len(self.history):
|
||||
for command in self.history[self._last_length:]:
|
||||
self.send_message(command)
|
||||
|
||||
@property
|
||||
def history(self):
|
||||
return self._history
|
||||
|
||||
def _fetch_history(self):
|
||||
self._last_length = len(self._history)
|
||||
self._last_length = len(self.history)
|
||||
with open(self.histfile, 'r') as ifile:
|
||||
pattern = compileregex(self.command_pattern)
|
||||
data = ifile.read()
|
||||
self._history = [
|
||||
self.history = [
|
||||
self.sanitize_command(command)
|
||||
for command in findall(pattern, data)
|
||||
]
|
||||
@ -76,8 +89,9 @@ class BashMonitor(HistoryMonitor):
|
||||
shopt -s histappend
|
||||
unset HISTCONTROL
|
||||
"""
|
||||
def __init__(self, histfile):
|
||||
super().__init__('bash', histfile)
|
||||
def __init__(self, uplink, histfile):
|
||||
super().__init__(uplink, histfile)
|
||||
self.domain = 'bash'
|
||||
|
||||
@property
|
||||
def command_pattern(self):
|
||||
@ -93,7 +107,8 @@ class GDBMonitor(HistoryMonitor):
|
||||
For this to work "set trace-commands on" must be set in GDB.
|
||||
"""
|
||||
def __init__(self, histfile):
|
||||
super().__init__('gdb', histfile)
|
||||
super().__init__(histfile)
|
||||
self.domain = 'gdb'
|
||||
|
||||
@property
|
||||
def command_pattern(self):
|
||||
|
@ -1,7 +1,8 @@
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
from time import time
|
||||
from typing import Iterable
|
||||
from time import time
|
||||
from os.path import abspath, dirname, isfile
|
||||
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemMovedEvent, PatternMatchingEventHandler
|
||||
@ -65,28 +66,44 @@ class InotifyDirDeletedEvent(InotifyEvent):
|
||||
|
||||
|
||||
class InotifyObserver:
|
||||
def __init__(self, paths, patterns=None, exclude=None, recursive=False):
|
||||
self._paths = paths
|
||||
def __init__(self, path, patterns=[], exclude=None, recursive=False):
|
||||
self._files = []
|
||||
self._paths = path
|
||||
self._patterns = patterns
|
||||
self._exclude = exclude
|
||||
self._recursive = recursive
|
||||
self._observer = Observer()
|
||||
self._reset(paths, patterns, exclude)
|
||||
self._reset()
|
||||
|
||||
def _reset(self, paths, patterns, exclude):
|
||||
_dispatch_event = self._dispatch_event
|
||||
def _reset(self):
|
||||
dispatch_event = self._dispatch_event
|
||||
class TransformerEventHandler(PatternMatchingEventHandler):
|
||||
def on_any_event(self, event):
|
||||
_dispatch_event(event)
|
||||
self.handler = TransformerEventHandler(patterns, exclude)
|
||||
self._observer.unschedule_all()
|
||||
if isinstance(paths, str):
|
||||
self._observer.schedule(self.handler, paths, self._recursive)
|
||||
elif isinstance(paths, Iterable):
|
||||
for path in paths:
|
||||
self._observer.schedule(self.handler, path, self._recursive)
|
||||
dispatch_event(event)
|
||||
|
||||
if isinstance(self._paths, str):
|
||||
self._paths = [self._paths]
|
||||
if isinstance(self._paths, Iterable):
|
||||
self._extract_files_from_paths()
|
||||
else:
|
||||
raise ValueError('Expected one or more strings representing paths.')
|
||||
raise ValueError('Expected one or more string paths.')
|
||||
|
||||
patterns = self._files+self.patterns
|
||||
self.handler = TransformerEventHandler(patterns if patterns else None, self.exclude)
|
||||
self._observer.unschedule_all()
|
||||
for path in self.paths:
|
||||
self._observer.schedule(self.handler, path, self._recursive)
|
||||
|
||||
def _extract_files_from_paths(self):
|
||||
files, paths = [], []
|
||||
for path in self._paths:
|
||||
if isfile(path):
|
||||
new_file = abspath(path)
|
||||
files.append(new_file)
|
||||
paths.append(dirname(new_file))
|
||||
else:
|
||||
paths.append(path)
|
||||
self._files, self._paths = files, paths
|
||||
|
||||
@property
|
||||
def paths(self):
|
||||
@ -95,7 +112,7 @@ class InotifyObserver:
|
||||
@paths.setter
|
||||
def paths(self, paths):
|
||||
self._paths = paths
|
||||
self._reset(paths, self._patterns, self._exclude)
|
||||
self._reset()
|
||||
|
||||
@property
|
||||
def patterns(self):
|
||||
@ -104,7 +121,7 @@ class InotifyObserver:
|
||||
@patterns.setter
|
||||
def patterns(self, patterns):
|
||||
self._patterns = patterns
|
||||
self._reset(self._paths, patterns, self._exclude)
|
||||
self._reset()
|
||||
|
||||
@property
|
||||
def exclude(self):
|
||||
@ -113,7 +130,7 @@ class InotifyObserver:
|
||||
@exclude.setter
|
||||
def exclude(self, exclude):
|
||||
self._exclude = exclude
|
||||
self._reset(self._paths, self._patterns, exclude)
|
||||
self._reset()
|
||||
|
||||
def start(self):
|
||||
self._observer.start()
|
||||
|
@ -11,8 +11,8 @@ from tempfile import TemporaryDirectory
|
||||
import watchdog
|
||||
import pytest
|
||||
|
||||
from inotify import InotifyObserver
|
||||
from inotify import (
|
||||
from .inotify import InotifyObserver
|
||||
from .inotify import (
|
||||
InotifyFileCreatedEvent, InotifyFileModifiedEvent, InotifyFileMovedEvent,
|
||||
InotifyFileDeletedEvent, InotifyDirCreatedEvent, InotifyDirModifiedEvent,
|
||||
InotifyDirMovedEvent, InotifyDirDeletedEvent
|
||||
@ -113,8 +113,8 @@ def test_create(context):
|
||||
assert context.check_any()
|
||||
|
||||
def test_modify(context):
|
||||
with open(context.subfile, 'w') as ofile:
|
||||
ofile.write('text')
|
||||
with open(context.subfile, 'wb', buffering=0) as ofile:
|
||||
ofile.write(b'text')
|
||||
context.check_event(InotifyFileModifiedEvent, context.subfile)
|
||||
while True:
|
||||
try:
|
||||
|
Reference in New Issue
Block a user