def close(self): """ Closes the inotify instance and removes all associated watches. """ with self._lock: path = unicode_paths.encode(absolute_path(self._path)) wd = self._wd_for_path[path] inotify_rm_watch(self._inotify_fd, wd)
def _add_watch(self, path, mask): """ Adds a watch for the given path to monitor events specified by the mask. :param path: Path to monitor :param mask: Event bit mask. """ wd = inotify_add_watch(self._inotify_fd, unicode_paths.encode(path), mask) if wd == -1: Inotify._raise_error() self._wd_for_path[path] = wd self._path_for_wd[wd] = path return wd
def _add_dir_watch(self, path, recursive, mask): """ Adds a watch (optionally recursively) for the given directory path to monitor events specified by the mask. :param path: Path to monitor :param recursive: ``True`` to monitor recursively. :param mask: Event bit mask. """ path = unicode_paths.encode(path) if not os.path.isdir(path): raise OSError('Path is not a directory') self._add_watch(path, mask) if recursive: for root, dirnames, _ in os.walk(path): for dirname in dirnames: full_path = absolute_path(os.path.join(root, dirname)) if os.path.islink(full_path): continue self._add_watch(full_path, mask)
def read_events(self, event_buffer_size=DEFAULT_EVENT_BUFFER_SIZE): """ Reads events from inotify and yields them. """ while True: try: event_buffer = os.read(self._inotify_fd, event_buffer_size) except OSError as e: if e.errno == errno.EINTR: continue break with self._lock: event_list = [] for wd, mask, cookie, name in Inotify._parse_event_buffer(event_buffer): if wd == -1: continue wd_path = unicode_paths.encode(self._path_for_wd[wd]) src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_moved_from: # check if next event if moved_to # otherwise we might be remembering # something that we will never need # and the event will be lost if idx < len(parsed_events) - 1 and\ parsed_events[idx+1][2] == cookie: self.remember_move_from_event(inotify_event) else: inotify_event = InotifyEvent(wd, mask, -1, name, src_path) elif inotify_event.is_moved_to: move_src_path = self.source_for_move(inotify_event) if move_src_path in self._wd_for_path: # update old path -> new path moved_wd = self._wd_for_path[move_src_path] del self._wd_for_path[move_src_path] self._wd_for_path[inotify_event.src_path] = moved_wd self._path_for_wd[moved_wd] = inotify_event.src_path src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_ignored: # Clean up book-keeping for deleted watches. self._remove_watch_bookkeeping(src_path) continue event_list.append(inotify_event) if self.is_recursive and inotify_event.is_directory and inotify_event.is_create: # HACK: We need to traverse the directory path # recursively and simulate events for newly # created subdirectories/files. This will handle # mkdir -p foobar/blah/bar; touch foobar/afile # TODO: When a directory from another part of the # filesystem is moved into a watched directory, this # will not generate events for the directory tree. # We need to coalesce IN_MOVED_TO events and those # IN_MOVED_TO events which don't pair up with # IN_MOVED_FROM events should be marked IN_CREATE # instead relative to this directory. try: self._add_watch(src_path, self._event_mask) except OSError: continue for root, dirnames, filenames in os.walk(src_path): for dirname in dirnames: try: full_path = absolute_path(os.path.join(root, dirname)) wd_dir = self._add_watch(full_path, self._event_mask) event_list.append(InotifyEvent(wd_dir, InotifyConstants.IN_CREATE | InotifyConstants.IN_ISDIR, 0, dirname, full_path)) except OSError: pass for filename in filenames: full_path = absolute_path(os.path.join(root, filename)) wd_parent_dir = self._wd_for_path[absolute_path(os.path.dirname(full_path))] event_list.append(InotifyEvent(wd_parent_dir, InotifyConstants.IN_CREATE, 0, filename, full_path)) return event_list
def on_thread_start(self): path = unicode_paths.encode(self.watch.path) self._inotify = InotifyBuffer(path, self.watch.is_recursive)
def read_events(self, event_buffer_size=DEFAULT_EVENT_BUFFER_SIZE): """ Reads events from inotify and yields them. """ # HACK: We need to traverse the directory path # recursively and simulate events for newly # created subdirectories/files. This will handle # mkdir -p foobar/blah/bar; touch foobar/afile def _recursive_simulate(src_path): events = [] for root, dirnames, filenames in os.walk(src_path): for dirname in dirnames: try: full_path = absolute_path(os.path.join(root, dirname)) wd_dir = self._add_watch(full_path, self._event_mask) e = InotifyEvent( wd_dir, InotifyConstants.IN_CREATE | InotifyConstants.IN_ISDIR, 0, dirname, full_path) events.append(e) except OSError: pass for filename in filenames: full_path = absolute_path(os.path.join(root, filename)) wd_parent_dir = self._wd_for_path[absolute_path( os.path.dirname(full_path))] e = InotifyEvent(wd_parent_dir, InotifyConstants.IN_CREATE, 0, filename, full_path) events.append(e) return events while True: try: event_buffer = os.read(self._inotify_fd, event_buffer_size) except OSError as e: if e.errno == errno.EINTR: continue break with self._lock: event_list = [] for wd, mask, cookie, name in Inotify._parse_event_buffer( event_buffer): if wd == -1: continue wd_path = unicode_paths.encode(self._path_for_wd[wd]) src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_moved_from: self.remember_move_from_event(inotify_event) elif inotify_event.is_moved_to: move_src_path = self.source_for_move(inotify_event) if move_src_path in self._wd_for_path: moved_wd = self._wd_for_path[move_src_path] del self._wd_for_path[move_src_path] self._wd_for_path[inotify_event.src_path] = moved_wd self._path_for_wd[moved_wd] = inotify_event.src_path src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_ignored: # Clean up book-keeping for deleted watches. self._remove_watch_bookkeeping(src_path) continue event_list.append(inotify_event) if (self.is_recursive and inotify_event.is_directory and inotify_event.is_create): # TODO: When a directory from another part of the # filesystem is moved into a watched directory, this # will not generate events for the directory tree. # We need to coalesce IN_MOVED_TO events and those # IN_MOVED_TO events which don't pair up with # IN_MOVED_FROM events should be marked IN_CREATE # instead relative to this directory. try: self._add_watch(src_path, self._event_mask) except OSError: continue event_list.extend(_recursive_simulate(src_path)) return event_list
def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT): EventEmitter.__init__(self, event_queue, watch, timeout) self._lock = threading.Lock() self._inotify = InotifyBuffer(unicode_paths.encode(watch.path), watch.is_recursive)
def read_events(self, event_buffer_size = DEFAULT_EVENT_BUFFER_SIZE): """ Reads events from inotify and yields them. """ def _recursive_simulate(src_path): events = [] for root, dirnames, filenames in os.walk(src_path): for dirname in dirnames: try: full_path = absolute_path(os.path.join(root, dirname)) wd_dir = self._add_watch(full_path, self._event_mask) e = InotifyEvent(wd_dir, InotifyConstants.IN_CREATE | InotifyConstants.IN_ISDIR, 0, dirname, full_path) events.append(e) except OSError: pass for filename in filenames: full_path = absolute_path(os.path.join(root, filename)) wd_parent_dir = self._wd_for_path[absolute_path(os.path.dirname(full_path))] e = InotifyEvent(wd_parent_dir, InotifyConstants.IN_CREATE, 0, filename, full_path) events.append(e) return events while True: try: event_buffer = os.read(self._inotify_fd, event_buffer_size) except OSError as e: if e.errno == errno.EINTR: continue break with self._lock: event_list = [] for wd, mask, cookie, name in Inotify._parse_event_buffer(event_buffer): if wd == -1: continue wd_path = unicode_paths.encode(self._path_for_wd[wd]) src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_moved_from: self.remember_move_from_event(inotify_event) elif inotify_event.is_moved_to: move_src_path = self.source_for_move(inotify_event) if move_src_path in self._wd_for_path: moved_wd = self._wd_for_path[move_src_path] del self._wd_for_path[move_src_path] self._wd_for_path[inotify_event.src_path] = moved_wd self._path_for_wd[moved_wd] = inotify_event.src_path src_path = absolute_path(os.path.join(wd_path, name)) inotify_event = InotifyEvent(wd, mask, cookie, name, src_path) if inotify_event.is_ignored: self._remove_watch_bookkeeping(src_path) continue event_list.append(inotify_event) if self.is_recursive and inotify_event.is_directory and inotify_event.is_create: try: self._add_watch(src_path, self._event_mask) except OSError: continue event_list.extend(_recursive_simulate(src_path)) return event_list