Merge pull request #1053 from ZyX-I/fix-uv-watcher

Some fixes for libuv-based watcher
This commit is contained in:
Nikolai Aleksandrovich Pavlov 2014-09-02 22:22:43 +04:00
commit 77d311bdc8
8 changed files with 58 additions and 12 deletions

View File

@ -45,6 +45,7 @@ Common configuration is a subdictionary that is a value of ``common`` key in
auto Selects most performant watcher.
inotify Select inotify watcher. Linux only.
stat Select stat-based polling watcher.
uv Select libuv-based watcher.
======= ===================================
Default is ``auto``.

View File

@ -19,6 +19,8 @@ Generic requirements
repositories.
* ``bzr`` python package (note: *not* standalone executable). Required to work
with bazaar repositories.
* ``pyuv`` python package. Required for :ref:`libuv-based watcher
<config-common-watcher>` to work.
* ``i3-py``, `available on github <https://github.com/ziberna/i3-py>`_. Required
for i3wm bindings and segments.

View File

@ -53,7 +53,7 @@ def get_branch_name(directory, config_file, get_func, create_watcher):
with branch_lock:
# Check if the repo directory was moved/deleted
fw = branch_watcher(create_watcher)
is_watched = fw.is_watched(directory)
is_watched = fw.is_watching(directory)
try:
changed = fw(directory)
except OSError as e:

View File

@ -18,16 +18,17 @@ def create_file_watcher(pl, watcher_type='auto', expire_time=10):
Use ``.unwatch()`` method of the returned object to stop watching the file.
Uses inotify if available, otherwise tracks mtimes. expire_time is the
number of minutes after the last query for a given path for the inotify
watch for that path to be automatically removed. This conserves kernel
resources.
Uses inotify if available, then pyuv, otherwise tracks mtimes. expire_time
is the number of minutes after the last query for a given path for the
inotify watch for that path to be automatically removed. This conserves
kernel resources.
:param PowerlineLogger pl:
Logger.
:param str watcher_type:
One of ``inotify`` (linux only), ``stat``, ``auto``. Determines what
watcher will be used. ``auto`` will use ``inotify`` if available.
:param str watcher_type
One of ``inotify`` (linux only), ``uv``, ``stat``, ``auto``. Determines
what watcher will be used. ``auto`` will use ``inotify`` if available,
then ``libuv`` and then fall back to ``stat``.
:param int expire_time:
Number of minutes since last ``.__call__()`` before inotify watcher will
stop watching given file.
@ -67,7 +68,7 @@ def create_tree_watcher(pl, watcher_type='auto', expire_time=10):
Logger.
:param str watcher_type:
Watcher type. Currently the only supported types are ``inotify`` (linux
only), ``dummy`` and ``auto``.
only), ``uv``, ``dummy`` and ``auto``.
:param int expire_time:
Number of minutes since last ``.__call__()`` before inotify watcher will
stop watching given file.

View File

@ -101,7 +101,7 @@ class INotifyFileWatcher(INotify):
self.watches[path] = wd
self.modified[path] = False
def is_watched(self, path):
def is_watching(self, path):
with self.lock:
return realpath(path) in self.watches

View File

@ -23,7 +23,7 @@ class StatFileWatcher(object):
with self.lock:
self.watches.pop(path, None)
def is_watched(self, path):
def is_watching(self, path):
with self.lock:
return realpath(path) in self.watches

View File

@ -63,6 +63,7 @@ class UvWatcher(object):
self.loop = start_uv_thread()
def watch(self, path):
path = realpath(path)
with self.lock:
if path not in self.watches:
try:
@ -80,6 +81,7 @@ class UvWatcher(object):
raise
def unwatch(self, path):
path = realpath(path)
with self.lock:
try:
watch = self.watches.pop(path)
@ -87,6 +89,10 @@ class UvWatcher(object):
return
watch.close(partial(self._stopped_watching, path))
def is_watching(self, path):
with self.lock:
return realpath(path) in self.watches
def __del__(self):
try:
lock = self.lock
@ -115,6 +121,7 @@ class UvFileWatcher(UvWatcher):
self.events.pop(path, None)
def __call__(self, path):
path = realpath(path)
with self.lock:
events = self.events.pop(path, None)
if events:
@ -122,6 +129,7 @@ class UvFileWatcher(UvWatcher):
if path not in self.watches:
self.watch(path)
return True
return False
class UvTreeWatcher(UvWatcher):
@ -135,7 +143,7 @@ class UvTreeWatcher(UvWatcher):
self.watch_directory(self.basedir)
def watch_directory(self, path):
os.path.walk(path, self.watch_one_directory, None)
os.path.walk(realpath(path), self.watch_one_directory, None)
def watch_one_directory(self, arg, dirname, fnames):
try:

View File

@ -141,6 +141,40 @@ class TestFilesystemWatchers(TestCase):
tw = create_tree_watcher(get_fallback_logger(), 'uv')
return self.do_test_tree_watcher(tw)
def test_inotify_file_watcher_is_watching(self):
try:
w = create_file_watcher(pl=get_fallback_logger(), watcher_type='inotify')
except INotifyError:
raise SkipTest('INotify is not available')
return self.do_test_file_watcher_is_watching(w)
def test_stat_file_watcher_is_watching(self):
w = create_file_watcher(pl=get_fallback_logger(), watcher_type='stat')
return self.do_test_file_watcher_is_watching(w)
def test_uv_file_watcher_is_watching(self):
try:
w = create_file_watcher(pl=get_fallback_logger(), watcher_type='uv')
except UvNotFound:
raise SkipTest('Pyuv is not available')
return self.do_test_file_watcher_is_watching(w)
def do_test_file_watcher_is_watching(self, w):
try:
f1, f2, f3 = map(lambda x: os.path.join(INOTIFY_DIR, 'file%d' % x), (1, 2, 3))
with open(f1, 'wb'):
with open(f2, 'wb'):
with open(f3, 'wb'):
pass
ne = os.path.join(INOTIFY_DIR, 'notexists')
self.assertRaises(OSError, w, ne)
self.assertTrue(w(f1))
self.assertFalse(w.is_watching(ne))
self.assertTrue(w.is_watching(f1))
self.assertFalse(w.is_watching(f2))
finally:
clear_dir(INOTIFY_DIR)
old_cwd = None