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)
|