Skip to content

Commit

Permalink
Merge 85d033e into de61cd2
Browse files Browse the repository at this point in the history
  • Loading branch information
david415 committed Aug 25, 2016
2 parents de61cd2 + 85d033e commit b329e25
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ install:
# ~/.local/bin is on $PATH by default, but on OS-X, --user puts it elsewhere
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then export PATH=$HOME/Library/Python/2.7/bin:$PATH; fi
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then wget https://bootstrap.pypa.io/get-pip.py && sudo python ./get-pip.py; fi
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then pip install --user watchdog; fi
- pip list
- pip install --user coveralls tox
- echo $PATH; which python; which pip; which tox
Expand Down
4 changes: 4 additions & 0 deletions src/allmydata/_auto_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@
install_requires.append('pypiwin32')
package_imports.append(('pypiwin32', 'win32api'))

if sys.platform != "win32" and not sys.platform.startswith("linux"):
install_requires.append('watchdog')
package_imports.append(('watchdog', 'watchdog'))

setup_requires = []


Expand Down
2 changes: 2 additions & 0 deletions src/allmydata/frontends/magic_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def get_inotify_module():
from allmydata.windows import inotify
elif runtime.platform.supportsINotify():
from twisted.internet import inotify
elif sys.platform != "linux":
from allmydata.watchdog import inotify
else:
raise NotImplementedError("filesystem notification needed for Magic Folder is not supported.\n"
"This currently requires Linux or Windows.")
Expand Down
Empty file.
136 changes: 136 additions & 0 deletions src/allmydata/watchdog/inotify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

from twisted.internet import reactor
from twisted.python.filepath import FilePath
from allmydata.util.fileutil import abspath_expanduser_unicode

from allmydata.util.pollmixin import PollMixin
from allmydata.util.assertutil import _assert, precondition
from allmydata.util import log, encodingutil
from allmydata.util.encodingutil import unicode_from_filepath
from allmydata.util.fake_inotify import humanReadableMask, \
IN_WATCH_MASK, IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_NOWRITE, IN_CLOSE_WRITE, \
IN_OPEN, IN_MOVED_FROM, IN_MOVED_TO, IN_CREATE, IN_DELETE, IN_DELETE_SELF, \
IN_MOVE_SELF, IN_UNMOUNT, IN_Q_OVERFLOW, IN_IGNORED, IN_ONLYDIR, IN_DONT_FOLLOW, \
IN_MASK_ADD, IN_ISDIR, IN_ONESHOT, IN_CLOSE, IN_MOVED, IN_CHANGED
[humanReadableMask, \
IN_WATCH_MASK, IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_NOWRITE, IN_CLOSE_WRITE, \
IN_OPEN, IN_MOVED_FROM, IN_MOVED_TO, IN_CREATE, IN_DELETE, IN_DELETE_SELF, \
IN_MOVE_SELF, IN_UNMOUNT, IN_Q_OVERFLOW, IN_IGNORED, IN_ONLYDIR, IN_DONT_FOLLOW, \
IN_MASK_ADD, IN_ISDIR, IN_ONESHOT, IN_CLOSE, IN_MOVED, IN_CHANGED]


TRUE = 0
FALSE = 1

NOT_STARTED = "NOT_STARTED"
STARTED = "STARTED"
STOPPING = "STOPPING"
STOPPED = "STOPPED"

class INotifyEventHandler(FileSystemEventHandler):

def __init__(self, path, mask, callbacks, pending_delay):
print "init INotifyEventHandler"
FileSystemEventHandler.__init__(self)
self._path = path
self._mask = mask
self._callbacks = callbacks
self._pending_delay = pending_delay
self._pending = set()

def process(self, event):
event_filepath_u = event.src_path.decode(encodingutil.get_filesystem_encoding())
event_filepath_u = abspath_expanduser_unicode(event_filepath_u, base=self._path)

if event_filepath_u == unicode_from_filepath(self._path):
# ignore events for parent directory
return

def _maybe_notify(path):
if path in self._pending:
return
self._pending.add(path)
def _do_callbacks():
print "DO CALLBACKS"
self._pending.remove(path)
event_mask = IN_CHANGED
if event.is_directory:
event_mask = event_mask | IN_ISDIR
for cb in self._callbacks:
try:
cb(None, FilePath(path), event_mask)
except Exception, e:
log.err(e)
_do_callbacks()
reactor.callFromThread(_maybe_notify, event_filepath_u)

def on_any_event(self, event):
print "PROCESS EVENT %r" % (event,)
self.process(event)

class INotify(PollMixin):
"""
I am a prototype INotify, made to work on Mac OS X (Darwin)
using the Watchdog python library. This is actually a simplified subset
of the twisted Linux INotify class because we do not utilize the watch mask
and only implement the following methods:
- watch
- startReading
- stopReading
- wait_until_stopped
- set_pending_delay
"""
def __init__(self):
self._pending_delay = 1.0
self.recursive_includes_new_subdirectories = False
self._observer = Observer(timeout=self._pending_delay)
self._callbacks = {}
self._state = NOT_STARTED

def set_pending_delay(self, delay):
print "set pending delay"
self._pending_delay = delay
self._observer = Observer(timeout=self._pending_delay)

def startReading(self):
print "START READING BEGIN"
try:
_assert(len(self._callbacks) != 0, "no watch set")
self._observer.start()
self._state = STARTED
except Exception, e:
log.err(e)
self._state = STOPPED
raise
print "START READING END"

def stopReading(self):
print "stopReading begin"
if self._state != STOPPED:
self._state = STOPPING
self._observer.stop()
self._observer.join()
self._state = STOPPED
print "stopReading end"

def wait_until_stopped(self):
print "wait until stopped"
return self.poll(lambda: self._state == STOPPED)

def watch(self, path, mask=IN_WATCH_MASK, autoAdd=False, callbacks=None, recursive=False):
precondition(isinstance(autoAdd, bool), autoAdd=autoAdd)
precondition(isinstance(recursive, bool), recursive=recursive)
assert autoAdd == False

self._recursive = TRUE if recursive else FALSE
path_u = path.path
if not isinstance(path_u, unicode):
path_u = path_u.decode('utf-8')
_assert(isinstance(path_u, unicode), path_u=path_u)

if path_u not in self._callbacks.keys():
self._callbacks[path_u] = callbacks or []
self._observer.schedule(INotifyEventHandler(path, mask, self._callbacks[path_u], self._pending_delay), path=path_u, recursive=recursive)

0 comments on commit b329e25

Please sign in to comment.