mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -04:00
Implement auto reload on windows
This commit is contained in:
parent
74c50bf11a
commit
6ac01f3560
@ -9,14 +9,34 @@ __copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import os, sys, subprocess, signal, time
|
import os, sys, subprocess, signal, time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
from calibre.constants import islinux
|
from calibre.constants import islinux, iswindows
|
||||||
|
|
||||||
class NoAutoReload(EnvironmentError):
|
class NoAutoReload(EnvironmentError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
EXTENSIONS_TO_WATCH = frozenset('py pyj css js xml'.split())
|
EXTENSIONS_TO_WATCH = frozenset('py pyj'.split())
|
||||||
BOUNCE_INTERVAL = 2 # seconds
|
BOUNCE_INTERVAL = 2 # seconds
|
||||||
|
|
||||||
|
class WatcherBase(object):
|
||||||
|
|
||||||
|
def __init__(self, server, log):
|
||||||
|
self.server, self.log = server, log
|
||||||
|
fpath = os.path.abspath(__file__)
|
||||||
|
d = os.path.dirname
|
||||||
|
self.base = d(d(d(d(fpath))))
|
||||||
|
self.last_restart_time = time.time()
|
||||||
|
|
||||||
|
def handle_modified(self, modified):
|
||||||
|
if modified:
|
||||||
|
if time.time() - self.last_restart_time > BOUNCE_INTERVAL:
|
||||||
|
modified = {os.path.relpath(x, self.base) if x.startswith(self.base) else x for x in modified if x}
|
||||||
|
changed = os.pathsep.join(sorted(modified))
|
||||||
|
self.log('')
|
||||||
|
self.log('Restarting server because of changed files:', changed)
|
||||||
|
self.log('')
|
||||||
|
self.server.restart()
|
||||||
|
self.last_restart_time = time.time()
|
||||||
|
|
||||||
if islinux:
|
if islinux:
|
||||||
import select
|
import select
|
||||||
from calibre.utils.inotify import INotifyTreeWatcher
|
from calibre.utils.inotify import INotifyTreeWatcher
|
||||||
@ -24,18 +44,14 @@ if islinux:
|
|||||||
def ignore_event(path, name):
|
def ignore_event(path, name):
|
||||||
return name and name.rpartition('.')[-1] not in EXTENSIONS_TO_WATCH
|
return name and name.rpartition('.')[-1] not in EXTENSIONS_TO_WATCH
|
||||||
|
|
||||||
class Watcher(object):
|
class Watcher(WatcherBase):
|
||||||
|
|
||||||
def __init__(self, root_dirs, server, log):
|
def __init__(self, root_dirs, server, log):
|
||||||
self.server, self.log = server, log
|
WatcherBase.__init__(self, server, log)
|
||||||
self.fd_map = {}
|
self.fd_map = {}
|
||||||
for d in frozenset(root_dirs):
|
for d in frozenset(root_dirs):
|
||||||
w = INotifyTreeWatcher(d, ignore_event)
|
w = INotifyTreeWatcher(d, ignore_event)
|
||||||
self.fd_map[w._inotify_fd] = w
|
self.fd_map[w._inotify_fd] = w
|
||||||
self.last_restart_time = time.time()
|
|
||||||
fpath = os.path.abspath(__file__)
|
|
||||||
d = os.path.dirname
|
|
||||||
self.base = d(d(d(d(fpath))))
|
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
while True:
|
while True:
|
||||||
@ -44,15 +60,73 @@ if islinux:
|
|||||||
for fd in r:
|
for fd in r:
|
||||||
w = self.fd_map[fd]
|
w = self.fd_map[fd]
|
||||||
modified |= w()
|
modified |= w()
|
||||||
if modified:
|
self.handle_modified()
|
||||||
if time.time() - self.last_restart_time > BOUNCE_INTERVAL:
|
|
||||||
modified = {os.path.relpath(x, self.base) if x.startswith(self.base) else x for x in modified if x}
|
elif iswindows:
|
||||||
changed = os.pathsep.join(sorted(modified))
|
import win32file, win32con
|
||||||
self.log('')
|
from Queue import Queue
|
||||||
self.log('Restarting server because of changed files:', changed)
|
FILE_LIST_DIRECTORY = 0x0001
|
||||||
self.log('')
|
from calibre.srv.utils import HandleInterrupt
|
||||||
self.server.restart()
|
|
||||||
self.last_restart_time = time.time()
|
class TreeWatcher(Thread):
|
||||||
|
daemon = True
|
||||||
|
|
||||||
|
def __init__(self, path_to_watch, modified_queue):
|
||||||
|
Thread.__init__(self, name='TreeWatcher')
|
||||||
|
self.modified_queue = modified_queue
|
||||||
|
self.path_to_watch = path_to_watch
|
||||||
|
self.dir_handle = win32file.CreateFile(
|
||||||
|
path_to_watch,
|
||||||
|
FILE_LIST_DIRECTORY,
|
||||||
|
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE,
|
||||||
|
None,
|
||||||
|
win32con.OPEN_EXISTING,
|
||||||
|
win32con.FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
results = win32file.ReadDirectoryChangesW(
|
||||||
|
self.dir_handle,
|
||||||
|
8192, # Buffer size for storing events
|
||||||
|
True, # Watch sub-directories as well
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_SIZE |
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||||
|
win32con.FILE_NOTIFY_CHANGE_SECURITY,
|
||||||
|
None, None
|
||||||
|
)
|
||||||
|
for action, filename in results:
|
||||||
|
if filename and filename.rpartition('.')[-1] in EXTENSIONS_TO_WATCH:
|
||||||
|
self.modified_queue.put(os.path.join(self.path_to_watch, filename))
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
class Watcher(WatcherBase):
|
||||||
|
|
||||||
|
def __init__(self, root_dirs, server, log):
|
||||||
|
WatcherBase.__init__(self, server, log)
|
||||||
|
self.watchers = []
|
||||||
|
self.modified_queue = Queue()
|
||||||
|
for d in frozenset(root_dirs):
|
||||||
|
self.watchers.append(TreeWatcher(d, self.modified_queue))
|
||||||
|
|
||||||
|
def loop(self):
|
||||||
|
for w in self.watchers:
|
||||||
|
w.start()
|
||||||
|
with HandleInterrupt(lambda : self.modified_queue.put(None)):
|
||||||
|
while True:
|
||||||
|
path = self.modified_queue.get()
|
||||||
|
if path is None:
|
||||||
|
break
|
||||||
|
modified = {path}
|
||||||
|
self.handle_modified(modified)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
Watcher = None
|
Watcher = None
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user