watcher.py 3.79 KB
import os
import pyinotify
import argparse as ap

from redirector.utils import generators
from redirector.utils import logger
from redirector.utils import parser


from redirector.redirector import Redirector

redirector_watch = None


class RedirectorWatch:
    def __init__(self):
        self.logger = logger.Logger("redirector-watch.log")
        self.redirector = Redirector()
        self.parser = parser.ConfigReader(logger=self.logger)
        self.mask = pyinotify.ALL_EVENTS
        self.pool = {}


    def watch(self, yaml_file):
        if not yaml_file:
            raise self.RedirectorWatchException("yaml_file list is empty", Exception)
        Watch = self.create_watch_class(yaml_file)

        yaml_dir = os.path.dirname(os.path.abspath(yaml_file))

        for map_path, _ in self.parser.parse_yaml(yaml_file):
            rel_map_path = os.path.relpath(map_path, start=yaml_dir)
            abs_map_path = os.path.join(rel_map_path, yaml_dir, os.path.basename(map_path))
            abs_map_path = os.path.normpath(abs_map_path)

            self.redirector.generate(yaml_file, abs_map_path)
        try:
            self.set_inotify(yaml_file, Watch)
        except pyinotify.PyinotifyError as e:
            raise self.RedirectorWatchException("Can\'t set inotify for yamll file %s" % yaml_file, e)

    # creating class Watch with custom static 'yaml_file' argument
    def create_watch_class(self, yaml_file):
        global redirector_watch
        class Watch(pyinotify.ProcessEvent):
            def __init__(self, *args, **kwargs):
                self.redirector = kwargs.pop("redirector")
                super().__init__(*args, **kwargs)

            def process_IN_MODIFY(self, event):
                try:
                    redirector_watch.pool[yaml_file][1].stop()
                except RuntimeError as e:
                    print("There is a non cricital Exception {}".format(e))
                redirector_watch.pool[yaml_file] = None
                print("Proccessing...")
                self.redirector.generate(yaml_file, event.pathname)
                redirector_watch.watch(yaml_file)

            # fix bug with vim editing
            def process_default(self, event):
                if event.maskname == 'IN_MOVE_SELF':
                    redirector_watch.pool[yaml_file] = None
                    # correct path, deleting "-unknown-path" from path
                    corr_path = event.pathname.replace('-unknown-path', '')
                    print("Processing...")
                    self.redirector.generate(yaml_file, corr_path)
                    redirector_watch.watch(yaml_file)

        return Watch

    # we suggest that self.watch_manager already exists
    def set_inotify(self, yaml_file, Watch_class):
        wm = pyinotify.WatchManager()
        self.add_files(yaml_file, wm)
        notifier = pyinotify.ThreadedNotifier(wm, Watch_class(redirector=self.redirector))
        notifier.start()
        self.pool[yaml_file] = [wm, notifier]

    def add_files(self, file_, wm):
        file_list = self.parser.parse_yaml(file_)

        for map_path, _ in file_list:
            abs_map_path = os.path.abspath(map_path)
            wdd = wm.add_watch(abs_map_path, self.mask, rec=True, auto_add=True)
 
    class RedirectorWatchException(Exception):
        def __init__(self, message, errors):
            super().__init__(message)
            self.errors = errors


def watch(args=None):
    parser = ap.ArgumentParser(description='Redirector watchdog utility')
    parser.add_argument('filename', metavar='Y', type=str, nargs=1,
                        help='Sets watch on the content of .yaml file')
    if not args:
        args = parser.parse_args()

    global redirector_watch
    redirector_watch = RedirectorWatch()
    redirector_watch.watch(args.filename[0])


if __name__ == "__main__":
    watch()