summaryrefslogtreecommitdiff
path: root/postgresqleu/util/reload.py
blob: 9822ed119c4283a012c87eb9ca399ed9fbae7ac0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from django.core.management.base import BaseCommand

from django.conf import settings

import os
import sys
import threading

if settings.RELOAD_WATCH_DIRECTORIES:
    import pyinotify
else:
    from django.utils import autoreload


class ReloadCommand(BaseCommand):
    """
    A subclass of BaseCommand that will watch for changes and automatically exit (for reload)
    if something has changed.

    If configured, use a simple inotify check against configured directories and react on all
    changes. If not configured, fall back on the django implementation.

    Subclasses should *NOT* override handle(), instead they should implement handle_with_reload().
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.run_args = None
        self.run_options = None

    def handle(self, *args, **options):
        # Set up our background thread to run the inner handler
        self.run_args = args
        self.run_options = options

        if settings.RELOAD_WATCH_DIRECTORIES:
            wm = pyinotify.WatchManager()

            class EventHandler(pyinotify.ProcessEvent):
                def __init__(self, parent):
                    self.parent = parent
                    super().__init__()

                def process_default(self, event):
                    # We only exit if it's a python or precompiled python change
                    if not event.pathname.endswith('.py') and not event.pathname.endswith('.pyc'):
                        return

                    self.parent.stderr.write("Detected change in {}\n".format(event.pathname))
                    self.parent.stderr.write("Exiting for restart\n")
                    os._exit(0)

            notifier = pyinotify.ThreadedNotifier(wm, EventHandler(self))
            notifier.start()
            for d in settings.RELOAD_WATCH_DIRECTORIES:
                wm.add_watch(d, pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY | pyinotify.IN_ATTRIB, rec=True)

            # Runt he main task on the primary thread
            self._inner_handle()
        else:
            bthread = threading.Thread(target=self._inner_handle)
            bthread.setDaemon(True)
            bthread.start()

            reloader = autoreload.get_reloader()
            while not reloader.should_stop:
                reloader.run(bthread)

            self.stderr.write("Underlying code changed, exiting for a restart\n")
            sys.exit(0)

    def _inner_handle(self):
        self.handle_with_reload(self.run_args, self.run_options)