Auto-reload for OS X

This commit is contained in:
Kovid Goyal 2015-06-05 12:59:48 +05:30
parent 6ac01f3560
commit 131d18eec7
2 changed files with 44 additions and 6 deletions

View File

@ -9,7 +9,7 @@ __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, iswindows from calibre.constants import islinux, iswindows, isosx
class NoAutoReload(EnvironmentError): class NoAutoReload(EnvironmentError):
pass pass
@ -17,6 +17,9 @@ class NoAutoReload(EnvironmentError):
EXTENSIONS_TO_WATCH = frozenset('py pyj'.split()) EXTENSIONS_TO_WATCH = frozenset('py pyj'.split())
BOUNCE_INTERVAL = 2 # seconds BOUNCE_INTERVAL = 2 # seconds
def file_is_watched(fname):
return fname and fname.rpartition('.')[-1] in EXTENSIONS_TO_WATCH
class WatcherBase(object): class WatcherBase(object):
def __init__(self, server, log): def __init__(self, server, log):
@ -42,7 +45,7 @@ if islinux:
from calibre.utils.inotify import INotifyTreeWatcher from calibre.utils.inotify import INotifyTreeWatcher
def ignore_event(path, name): def ignore_event(path, name):
return name and name.rpartition('.')[-1] not in EXTENSIONS_TO_WATCH return not file_is_watched(name)
class Watcher(WatcherBase): class Watcher(WatcherBase):
@ -101,7 +104,7 @@ elif iswindows:
None, None None, None
) )
for action, filename in results: for action, filename in results:
if filename and filename.rpartition('.')[-1] in EXTENSIONS_TO_WATCH: if file_is_watched(filename):
self.modified_queue.put(os.path.join(self.path_to_watch, filename)) self.modified_queue.put(os.path.join(self.path_to_watch, filename))
except Exception: except Exception:
import traceback import traceback
@ -124,8 +127,37 @@ elif iswindows:
path = self.modified_queue.get() path = self.modified_queue.get()
if path is None: if path is None:
break break
modified = {path} self.handle_modified({path})
self.handle_modified(modified)
elif isosx:
from fsevents import Observer, Stream
class Watcher(WatcherBase):
def __init__(self, root_dirs, server, log):
WatcherBase.__init__(self, server, log)
self.stream = Stream(self.notify, *(x.encode('utf-8') for x in root_dirs), file_events=True)
def loop(self):
observer = Observer()
observer.schedule(self.stream)
observer.daemon = True
observer.start()
try:
while True:
# Cannot use observer.join() as it is not interrupted by
# Ctrl-C
time.sleep(10000)
finally:
observer.unschedule(self.stream)
observer.stop()
def notify(self, ev):
name = ev.name
if isinstance(name, bytes):
name = name.decode('utf-8')
if file_is_watched(name):
self.handle_modified({name})
else: else:
Watcher = None Watcher = None

View File

@ -13,7 +13,7 @@ Test a binary calibre build to ensure that all needed binary images/libraries ha
''' '''
import cStringIO, os, ctypes import cStringIO, os, ctypes
from calibre.constants import plugins, iswindows, islinux from calibre.constants import plugins, iswindows, islinux, isosx
def test_dlls(): def test_dlls():
import win32api import win32api
@ -79,6 +79,10 @@ def test_certgen():
from calibre.utils.certgen import create_key_pair from calibre.utils.certgen import create_key_pair
create_key_pair() create_key_pair()
def test_fsevents():
from fsevents import Observer, Stream
del Observer, Stream
def test_winutil(): def test_winutil():
from calibre.devices.scanner import win_pnp_drives from calibre.devices.scanner import win_pnp_drives
from calibre.constants import plugins from calibre.constants import plugins
@ -245,6 +249,8 @@ def test():
test_terminal() test_terminal()
if islinux: if islinux:
test_dbus() test_dbus()
if isosx:
test_fsevents()
if __name__ == '__main__': if __name__ == '__main__':
test() test()