diff --git a/pyinotifyd/__init__.py b/pyinotifyd/__init__.py index 5681353..f59eb69 100755 --- a/pyinotifyd/__init__.py +++ b/pyinotifyd/__init__.py @@ -15,25 +15,125 @@ # __all__ = [ + "EventMap" + "Watch", "Pyinotifyd", "DaemonInstance", - "main", - "scheduler", - "watch"] + "scheduler"] import argparse import asyncio import logging import logging.handlers +import pyinotify import signal import sys -from pyinotifyd.watch import EventMap, Watch +from pyinotify import ProcessEvent + from pyinotifyd._install import install, uninstall +from pyinotifyd.scheduler import Task __version__ = "0.0.2" +class _TaskList: + def __init__(self, tasks=[]): + if not isinstance(tasks, list): + tasks = [tasks] + + self._tasks = tasks + + def add(self, task): + self._tasks.append(task) + + def remove(self, task): + self._tasks.remove(task) + + def execute(self, event): + for task in self._tasks: + task.start(event) + + +class EventMap(ProcessEvent): + flags = { + **pyinotify.EventsCodes.OP_FLAGS, + **pyinotify.EventsCodes.EVENT_FLAGS} + + def __init__(self, event_map=None, default_task=None, *args, **kwargs): + super().__init__(*args, *kwargs) + + if default_task is not None: + for flag in EventMap.flags: + self.set(flag, default_task) + + if event_map is not None: + assert isinstance(event_map, dict), \ + f"event_map: expected {type(dict)}, got {type(event_map)}" + for flag, tasks in event_map.items(): + self.set(flag, tasks) + + def set(self, flag, tasks): + assert flag in EventMap.flags, \ + f"event_map: invalid flag: {flag}" + if tasks is not None: + if not isinstance(tasks, list): + tasks = [tasks] + + task_instances = [] + for task in tasks: + if not issubclass(type(task), Task): + task = Task(task) + + task_instances.append(task) + setattr(self, f"process_{flag}", _TaskList(task_instances).execute) + + elif hasattr(self, flag): + delattr(self, f"process_{flag}") + + +class Watch: + def __init__(self, path, event_map=None, default_task=None, rec=False, + auto_add=False, logname="watch"): + assert isinstance(path, str), \ + f"path: expected {type('')}, got {type(path)}" + + if isinstance(event_map, EventMap): + self._event_map = event_map + else: + self._event_map = EventMap(event_map, default_task) + + assert isinstance(rec, bool), \ + f"rec: expected {type(bool)}, got {type(rec)}" + assert isinstance(auto_add, bool), \ + f"auto_add: expected {type(bool)}, got {type(auto_add)}" + logname = (logname or __name__) + + self._path = path + self._rec = rec + self._auto_add = auto_add + + self._watch_manager = pyinotify.WatchManager() + self._notifier = None + self._log = logging.getLogger(logname) + + def path(self): + return self._path + + def start(self, loop=asyncio.get_event_loop()): + self._watch_manager.add_watch(self._path, pyinotify.ALL_EVENTS, + rec=self._rec, auto_add=self._auto_add, + do_glob=True) + + self._notifier = pyinotify.AsyncioNotifier( + self._watch_manager, loop, default_proc_fun=self._event_map) + + def stop(self): + self._notifier.stop() + + self._notifier = None + + class Pyinotifyd: name = "pyinotifyd" @@ -48,10 +148,9 @@ class Pyinotifyd: def from_cfg_file(config_file): config = {} name = Pyinotifyd.name - exec(f"import logging", {}, config) - exec(f"from {name} import Pyinotifyd", {}, config) + exec("import logging", {}, config) + exec(f"from {name} import Pyinotifyd, EventMap, Watch", {}, config) exec(f"from {name}.scheduler import *", {}, config) - exec(f"from {name}.watch import *", {}, config) with open(config_file, "r") as fh: exec(fh.read(), {}, config) instance = config[f"{name}"] diff --git a/pyinotifyd/scheduler.py b/pyinotifyd/scheduler.py index dd0f8eb..fb15c50 100755 --- a/pyinotifyd/scheduler.py +++ b/pyinotifyd/scheduler.py @@ -14,6 +14,7 @@ __all__ = [ "Task", + "Cancel", "TaskScheduler", "ShellScheduler", "FileManagerRule", @@ -53,8 +54,18 @@ class Task: event, task_id, *args, **kwargs)) return (task_id, task) - def log(self, event): - self._log.info(f"LOG: {event}") + def cancel(self, event): + pass + + +class Cancel(Task): + def __init__(self, task): + assert issubclass(type(task), Task), \ + f"task: expected {type(Task)}, got {type(task)}" + self._task = task + + def start(self, event, *args, **kwargs): + self._task.cancel(event) @dataclass diff --git a/pyinotifyd/watch.py b/pyinotifyd/watch.py deleted file mode 100755 index 48a2a1d..0000000 --- a/pyinotifyd/watch.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -# pyinotifyd is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# pyinotifyd is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with pyinotifyd. If not, see . -# - -__all__ = [ - "EventMap", - "Watch"] - -import asyncio -import pyinotify - - -class EventMap: - flags = { - **pyinotify.EventsCodes.OP_FLAGS, - **pyinotify.EventsCodes.EVENT_FLAGS} - - def __init__(self, event_map=None, default_task=None): - self._map = {} - - if default_task is not None: - assert callable(default_task), \ - f"default_task: expected callable, got {type(default_task)}" - for flag in EventMap.flags: - self.set(flag, default_task) - - if event_map is not None: - assert isinstance(event_map, dict), \ - f"event_map: expected {type(dict)}, got {type(event_map)}" - for flag, task in event_map.items(): - self.set(flag, task) - - def items(self): - return self._map.items() - - def set(self, flag, values): - assert flag in EventMap.flags, \ - f"event_map: invalid flag: {flag}" - if values is not None: - if not isinstance(values, list): - values = [values] - - for value in values: - assert callable(value), \ - f"event_map: {flag}: expected callable, got {type(value)}" - - self._map[flag] = values - elif flag in self._map: - del self._map[flag] - - -class _TaskList: - def __init__(self, tasks=[]): - if not isinstance(tasks, list): - tasks = [tasks] - - self._tasks = tasks - - def add(self, task): - self._tasks.append(task) - - def remove(self, task): - self._tasks.remove(task) - - def execute(self, event): - for task in self._tasks: - task(event) - - -class Watch: - def __init__(self, path, event_map, rec=False, auto_add=False, - logname="watch"): - assert isinstance(path, str), \ - f"path: expected {type('')}, got {type(path)}" - if isinstance(event_map, EventMap): - self._event_map = event_map - elif isinstance(event_map, dict): - self._event_map = EventMap(event_map) - else: - raise AssertionError( - f"event_map: expected {type(EventMap)} or {type(dict)}, " - f"got {type(event_map)}") - - assert isinstance(rec, bool), \ - f"rec: expected {type(bool)}, got {type(rec)}" - assert isinstance(auto_add, bool), \ - f"auto_add: expected {type(bool)}, got {type(auto_add)}" - - self._path = path - self._rec = rec - self._auto_add = auto_add - - self._watch_manager = pyinotify.WatchManager() - self._notifier = None - - def path(self): - return self._path - - def start(self, loop=asyncio.get_event_loop()): - handler = pyinotify.ProcessEvent() - for flag, values in self._event_map.items(): - setattr(handler, f"process_{flag}", _TaskList(values).execute) - - self._watch_manager.add_watch(self._path, pyinotify.ALL_EVENTS, - rec=self._rec, auto_add=self._auto_add, - do_glob=True) - - self._notifier = pyinotify.AsyncioNotifier( - self._watch_manager, loop, default_proc_fun=handler) - - def stop(self): - self._notifier.stop() - - self._notifier = None