From 8e36dbc4a547cf3faae368852ca622cd7db311f0 Mon Sep 17 00:00:00 2001 From: Thomas Oettli Date: Sun, 8 Nov 2020 00:47:10 +0100 Subject: [PATCH] fix reload --- pyinotifyd/__init__.py | 63 +++++++++++++++++++++-------------------- pyinotifyd/scheduler.py | 2 +- pyinotifyd/watch.py | 18 +++++++++--- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/pyinotifyd/__init__.py b/pyinotifyd/__init__.py index 529bae6..18a43e3 100755 --- a/pyinotifyd/__init__.py +++ b/pyinotifyd/__init__.py @@ -18,7 +18,6 @@ import argparse import asyncio import logging import logging.handlers -import pyinotify import signal import sys @@ -28,18 +27,6 @@ from pyinotifyd._install import install, uninstall __version__ = "0.0.2" -def get_pyinotifyd_from_config(name, config_file): - config = {} - exec(f"from {name}.scheduler import *", config) - with open(config_file, "r") as c: - exec(c.read(), globals(), config) - daemon = config[f"{name}"] - assert isinstance(daemon, Pyinotifyd), \ - f"{name}: expected {type(Pyinotifyd)}, " \ - f"got {type(daemon)}" - return daemon - - class Pyinotifyd: def __init__(self, watches=[], shutdown_timeout=30, logname="daemon"): self.set_watches(watches) @@ -47,8 +34,6 @@ class Pyinotifyd: logname = (logname or __name__) self._log = logging.getLogger(logname) self._loop = asyncio.get_event_loop() - self._notifiers = [] - self._wm = pyinotify.WatchManager() def set_watches(self, watches): if not isinstance(watches, list): @@ -58,7 +43,8 @@ class Pyinotifyd: assert isinstance(watch, Watch), \ f"watches: expected {type(Watch)}, got {type(watch)}" - self._watches = watches + self._watches = [] + self._watches.extend(watches) def add_watch(self, *args, **kwargs): self._watches.append(Watch(*args, **kwargs)) @@ -73,36 +59,48 @@ class Pyinotifyd: if not loop: loop = self._loop - self._log.info("starting") if len(self._watches) == 0: self._log.warning( "no watches configured, the daemon will not do anything") + for watch in self._watches: self._log.info( f"start listening for inotify events on '{watch.path()}'") - self._notifiers.append(watch.event_notifier(self._wm, loop)) + watch.start(loop) def stop(self): - self._log.info("stop listening for inotify events") - for notifier in self._notifiers: - notifier.stop() + for watch in self._watches: + self._log.info(f"stop listening for inotify events on '{watch.path()}'") + watch.stop() - self._notifiers = [] return self._shutdown_timeout +def get_pyinotifyd_from_config(name, config_file): + config = {} + exec(f"from {name} import Pyinotifyd", {}, config) + exec(f"from {name}.scheduler import *", {}, config) + exec(f"from {name}.watch import EventMap, Watch", {}, config) + with open(config_file, "r") as c: + exec(c.read(), {}, config) + daemon = config[f"{name}"] + assert isinstance(daemon, Pyinotifyd), \ + f"{name}: expected {type(Pyinotifyd)}, " \ + f"got {type(daemon)}" + return daemon + + class DaemonInstance: def __init__(self, instance, logname="daemon"): self._instance = instance self._shutdown = False self._log = logging.getLogger(logname) - self._timeout = None def start(self): self._instance.start() def stop(self): - self._timeout = self._instance.stop() + return self._instance.stop() def _get_pending_tasks(self): return [t for t in asyncio.all_tasks() @@ -110,23 +108,23 @@ class DaemonInstance: async def shutdown(self, signame): if self._shutdown: - self._log.info( + self._log.warning( f"got signal {signame}, but shutdown already in progress") return self._shutdown = True self._log.info(f"got signal {signame}, shutdown") - self.stop() + timeout = self.stop() pending = self._get_pending_tasks() if pending: - if self._timeout: + if timeout: future = asyncio.gather(*pending) self._log.info( - f"wait {self._timeout} seconds for {len(pending)} " + f"wait {timeout} seconds for {len(pending)} " f"remaining task(s) to complete") try: - await asyncio.wait_for(future, self._timeout) + await asyncio.wait_for(future, timeout) pending = [] except asyncio.TimeoutError: future.cancel() @@ -149,7 +147,7 @@ class DaemonInstance: self._shutdown = False self._log.info("shutdown complete") - async def reload(self, signame, name, config): + async def reload(self, signame, name, config, debug=False): if self._shutdown: self._log.info( f"got signal {signame}, but shutdown already in progress") @@ -161,6 +159,8 @@ class DaemonInstance: except Exception as e: logging.exception(f"unable to reload config '{config}': {e}") else: + if debug: + logging.getLogger().setLevel(logging.DEBUG) self.stop() self._instance = instance self.start() @@ -258,6 +258,7 @@ def main(): if args.debug: root_logger.setLevel(loglevel) + formatter = logging.Formatter( f"%(asctime)s - {myname}/%(name)s - %(levelname)s - %(message)s") ch.setFormatter(formatter) @@ -272,7 +273,7 @@ def main(): loop.add_signal_handler( getattr(signal, "SIGHUP"), lambda: asyncio.ensure_future( - daemon.reload(signame, myname, args.config))) + daemon.reload("SIGHUP", myname, args.config, args.debug))) daemon.start() loop.run_forever() diff --git a/pyinotifyd/scheduler.py b/pyinotifyd/scheduler.py index b52092d..5a85435 100755 --- a/pyinotifyd/scheduler.py +++ b/pyinotifyd/scheduler.py @@ -276,7 +276,7 @@ class FileManagerScheduler(TaskScheduler): if os.path.exists(dst): raise RuntimeError( f"unable to move file from '{path} " - f"to '{dst}', dstination path exists already") + f"to '{dst}', destination path exists already") dst_dir = os.path.dirname(dst) if not os.path.isdir(dst_dir) and rule.auto_create: diff --git a/pyinotifyd/watch.py b/pyinotifyd/watch.py index 0042d3e..d1c4155 100755 --- a/pyinotifyd/watch.py +++ b/pyinotifyd/watch.py @@ -98,15 +98,25 @@ class Watch: self._rec = rec self._auto_add = auto_add + self._watch_manager = pyinotify.WatchManager() + self._notifier = None + def path(self): return self._path - def event_notifier(self, wm, loop=asyncio.get_event_loop()): + 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) - wm.add_watch(self._path, pyinotify.ALL_EVENTS, rec=self._rec, - auto_add=self._auto_add, do_glob=True) + self._watch_manager.add_watch(self._path, pyinotify.ALL_EVENTS, + rec=self._rec, auto_add=self._auto_add, + do_glob=True) - return pyinotify.AsyncioNotifier(wm, loop, default_proc_fun=handler) + self._notifier = pyinotify.AsyncioNotifier( + self._watch_manager, loop, default_proc_fun=handler) + + def stop(self): + self._notifier.stop() + + self._notifier = None