def _generate_filename_to_mtime(self): filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(self._directory, followlinks=True): watcher_common.remove_ignored_dirs(dirnames) filenames = [ f for f in filenames if not watcher_common.ignore_file(f) ] for filename in filenames + dirnames: if num_files == 10000: warnings.warn( 'There are too many files in your application for ' 'changes in all of them to be monitored. You may have to ' 'restart the development server to see some changes to your ' 'files.') return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: mtime = os.path.getmtime(path) except (IOError, OSError): pass else: filename_to_mtime[path] = mtime return filename_to_mtime
def _generate_filename_to_mtime(directory): """Records the state of a directory. Args: directory: the root directory to traverse. Returns: A dictionary of subdirectories and files under directory associated with their timestamps. the keys are absolute paths and values are epoch timestamps. """ filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(directory, followlinks=True): watcher_common.skip_ignored_dirs(dirnames) filenames = [ f for f in filenames if not watcher_common.ignore_file(f) ] for filename in filenames + dirnames: if num_files == _MAX_MONITORED_FILES: warnings.warn( 'There are too many files in your application for ' 'changes in all of them to be monitored. You may have to ' 'restart the development server to see some changes to your ' 'files.') return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: filename_to_mtime[path] = os.path.getmtime(path) except (IOError, OSError): pass return filename_to_mtime
def _generate_filename_to_mtime(directory): """Records the state of a directory. Args: directory: the root directory to traverse. Returns: A dictionary of subdirectories and files under directory associated with their timestamps. the keys are absolute paths and values are epoch timestamps. """ filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(directory, followlinks=True): watcher_common.skip_ignored_dirs(dirnames) filenames = [f for f in filenames if not watcher_common.ignore_file(f)] for filename in filenames + dirnames: if num_files == _MAX_MONITORED_FILES: warnings.warn( 'There are too many files in your application for ' 'changes in all of them to be monitored. You may have to ' 'restart the development server to see some changes to your ' 'files.') return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: filename_to_mtime[path] = os.path.getmtime(path) except (IOError, OSError): pass return filename_to_mtime
def changes(self, timeout_ms=0): """Return paths for changed files and directories. start() must be called before this method. Args: timeout_ms: a timeout in milliseconds on which this watcher will block waiting for a change. It allows for external polling threads to react immediately on a change instead of waiting for a random polling delay. Returns: A set of strings representing file and directory paths that have changed since the last call to get_changed_paths. """ paths = set() while True: # Don't wait to detect subsequent changes after the initial one. if not self._inotify_poll.poll(0 if paths else timeout_ms): break self._inotify_events += os.read(self._inotify_fd, 1024) while len(self._inotify_events) > _INOTIFY_EVENT_SIZE: wd, mask, cookie, length = _INOTIFY_EVENT.unpack( self._inotify_events[:_INOTIFY_EVENT_SIZE]) if len(self._inotify_events) < _INOTIFY_EVENT_SIZE + length: break name = self._inotify_events[ _INOTIFY_EVENT_SIZE:_INOTIFY_EVENT_SIZE + length] name = name.rstrip('\0') logging.debug('wd=%s, mask=%s, cookie=%s, length=%s, name=%r', wd, _bit_str(mask, _ATTRIBUTE_MASK_NAMES), cookie, length, name) self._inotify_events = self._inotify_events[ _INOTIFY_EVENT_SIZE + length:] if mask & IN_IGNORED: continue try: directory = self._watch_to_directory[wd] except KeyError: logging.debug('Watch deleted for watch descriptor=%d', wd) continue path = os.path.join(directory, name) if os.path.isdir(path) or path in self._directory_to_watch_descriptor: if mask & IN_DELETE: self._remove_watch_for_path(path) elif mask & IN_MOVED_FROM: self._remove_watch_for_path(path) elif mask & IN_CREATE: self._add_watch_for_path(path) elif mask & IN_MOVED_TO: self._add_watch_for_path(path) if path not in paths and not watcher_common.ignore_file(path): paths.add(path) return paths
def _path_ignored(self, file_path): dir, filename = os.path.split(file_path) basedir, dirname = os.path.split(dir) return any([ watcher_common.ignore_file(file_path, self._skip_files_re, self._watcher_ignore_re), watcher_common.ignore_dir(basedir, dirname, self._skip_files_re), watcher_common.ignore_dir(basedir, dirname, self._watcher_ignore_re) ])
def changes(self): """Return paths for changed files and directories. start() must be called before this method. Returns: A set of strings representing file and directory paths that have changed since the last call to get_changed_paths. """ paths = set() while True: if not self._inotify_poll.poll(0): break self._inotify_events += os.read(self._inotify_fd, 1024) while len(self._inotify_events) > _INOTIFY_EVENT_SIZE: wd, mask, cookie, length = _INOTIFY_EVENT.unpack( self._inotify_events[:_INOTIFY_EVENT_SIZE]) if len(self._inotify_events) < _INOTIFY_EVENT_SIZE + length: break name = self._inotify_events[ _INOTIFY_EVENT_SIZE:_INOTIFY_EVENT_SIZE + length] name = name.rstrip('\0') logging.debug('wd=%s, mask=%s, cookie=%s, length=%s, name=%r', wd, _bit_str(mask, _ATTRIBUTE_MASK_NAMES), cookie, length, name) self._inotify_events = self._inotify_events[ _INOTIFY_EVENT_SIZE + length:] if mask & IN_IGNORED: continue try: directory = self._watch_to_directory[wd] except KeyError: logging.debug('Watch deleted for watch descriptor=%d', wd) continue path = os.path.join(directory, name) if os.path.isdir( path) or path in self._directory_to_watch_descriptor: if mask & IN_DELETE: self._remove_watch_for_path(path) elif mask & IN_MOVED_FROM: self._remove_watch_for_path(path) elif mask & IN_CREATE: self._add_watch_for_path(path) elif mask & IN_MOVED_TO: self._add_watch_for_path(path) if path not in paths and not watcher_common.ignore_file(path): paths.add(path) return paths
def changes(self): """Return paths for changed files and directories. start() must be called before this method. Returns: A set of strings representing file and directory paths that have changed since the last call to get_changed_paths. """ paths = set() while True: if not self._inotify_poll.poll(0): break self._inotify_events += os.read(self._inotify_fd, 1024) while len(self._inotify_events) > _INOTIFY_EVENT_SIZE: wd, mask, cookie, length = _INOTIFY_EVENT.unpack( self._inotify_events[:_INOTIFY_EVENT_SIZE]) if len(self._inotify_events) < _INOTIFY_EVENT_SIZE + length: break name = self._inotify_events[ _INOTIFY_EVENT_SIZE:_INOTIFY_EVENT_SIZE + length] name = name.rstrip('\0') logging.debug('wd=%s, mask=%s, cookie=%s, length=%s, name=%r', wd, _bit_str(mask, _ATTRIBUTE_MASK_NAMES), cookie, length, name) self._inotify_events = self._inotify_events[ _INOTIFY_EVENT_SIZE + length:] if mask & IN_IGNORED: continue try: directory = self._watch_to_directory[wd] except KeyError: logging.debug('Watch deleted for watch descriptor=%d', wd) continue path = os.path.join(directory, name) if os.path.isdir(path) or path in self._directory_to_watch_descriptor: if mask & IN_DELETE: self._remove_watch_for_path(path) elif mask & IN_MOVED_FROM: self._remove_watch_for_path(path) elif mask & IN_CREATE: self._add_watch_for_path(path) elif mask & IN_MOVED_TO: self._add_watch_for_path(path) if path not in paths and not watcher_common.ignore_file(path): paths.add(path) return paths
def _path_ignored(self, file_path): """Determines if a path is ignored or not. Args: file_path: The full (string) filepath. Returns: Boolean, True if ignored else False. """ return watcher_common.ignore_file( file_path, self._skip_files_re, self._watcher_ignore_re)
def _generate_filename_to_mtime(self): """Records the state of a directory. Returns: A dictionary of subdirectories and files under directory associated with their timestamps. the keys are absolute paths and values are epoch timestamps. Raises: ShutdownError: if the quit event has been fired during processing. """ filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(self._directory, followlinks=True): if self._quit_event.is_set(): raise ShutdownError() relative_dirpath = os.path.relpath(dirname, self._directory) if relative_dirpath == '.': relative_dirpath = '' if relative_dirpath != '..': # never skip the top-level directory watcher_common.skip_ignored_dirs(dirnames, relative_dirpath, self._skip_files_re) filenames = [ f for f in filenames if not watcher_common.ignore_file( os.path.join(relative_dirpath, f), self._skip_files_re) ] for filename in filenames + dirnames: if self._quit_event.is_set(): raise ShutdownError() if num_files == _MAX_MONITORED_FILES: warnings.warn( 'There are too many files in your application for ' 'changes in all of them to be monitored. You may have to ' 'restart the development server to see some changes to your ' 'files.') return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: filename_to_mtime[path] = os.path.getmtime(path) except (IOError, OSError): pass return filename_to_mtime
def _generate_filename_to_mtime(self): """Records the state of a directory. Returns: A dictionary of subdirectories and files under directory associated with their timestamps. the keys are absolute paths and values are epoch timestamps. Raises: ShutdownError: if the quit event has been fired during processing. """ filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(self._directory, followlinks=True): if self._quit_event.is_set(): raise ShutdownError() relative_dirpath = os.path.relpath(dirname, self._directory) if relative_dirpath == ".": relative_dirpath = "" if relative_dirpath != "..": # never skip the top-level directory watcher_common.skip_ignored_dirs(dirnames, relative_dirpath, self._skip_files_re) filenames = [ f for f in filenames if not watcher_common.ignore_file(os.path.join(relative_dirpath, f), self._skip_files_re) ] for filename in filenames + dirnames: if self._quit_event.is_set(): raise ShutdownError() if num_files == _MAX_MONITORED_FILES: warnings.warn( "There are too many files in your application for " "changes in all of them to be monitored. You may have to " "restart the development server to see some changes to your " "files." ) return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: filename_to_mtime[path] = os.path.getmtime(path) except (IOError, OSError): pass return filename_to_mtime
def _fsevents_callback(self, stream_ref, client_call_back_info, num_events, event_paths, event_flags, event_ids): changes = set() for absolute_path, flag in zip(event_paths, event_flags): directory = next(d for d in self._directories if absolute_path.startswith(d)) skip_files_re = self._skip_files_re if not flag & (FSEvents.kFSEventStreamEventFlagItemCreated | FSEvents.kFSEventStreamEventFlagItemRemoved | FSEvents.kFSEventStreamEventFlagItemInodeMetaMod | FSEvents.kFSEventStreamEventFlagItemRenamed | FSEvents.kFSEventStreamEventFlagItemModified | FSEvents.kFSEventStreamEventFlagItemFinderInfoMod | FSEvents.kFSEventStreamEventFlagItemChangeOwner | FSEvents.kFSEventStreamEventFlagItemXattrMod): continue if watcher_common.ignore_file(absolute_path, skip_files_re): continue # We also want to ignore a path if we should ignore any directory # that the path is in. def _recursive_ignore_dir(dirname): assert not os.path.isabs( dirname) # or the while will never terminate (dir_dirpath, dir_base) = os.path.split(dirname) while dir_base: if watcher_common.ignore_dir(dir_dirpath, dir_base, skip_files_re): return True (dir_dirpath, dir_base) = os.path.split(dir_dirpath) return False relpath = os.path.relpath(absolute_path, directory) if _recursive_ignore_dir(os.path.dirname(relpath)): continue logging.warning("Reloading instances due to change in %s", relpath) changes.add(absolute_path) self._changes = changes self._change_event.set()
def _fsevents_callback(self, stream_ref, client_call_back_info, num_events, event_paths, event_flags, event_ids): changes = set() for absolute_path, flag in zip(event_paths, event_flags): directory = next( d for d in self._directories if absolute_path.startswith(d)) skip_files_re = self._skip_files_re if not flag & (FSEvents.kFSEventStreamEventFlagItemCreated | FSEvents.kFSEventStreamEventFlagItemRemoved | FSEvents.kFSEventStreamEventFlagItemInodeMetaMod | FSEvents.kFSEventStreamEventFlagItemRenamed | FSEvents.kFSEventStreamEventFlagItemModified | FSEvents.kFSEventStreamEventFlagItemFinderInfoMod | FSEvents.kFSEventStreamEventFlagItemChangeOwner | FSEvents.kFSEventStreamEventFlagItemXattrMod): continue if watcher_common.ignore_file(absolute_path, skip_files_re): continue # We also want to ignore a path if we should ignore any directory # that the path is in. def _recursive_ignore_dir(dirname): assert not os.path.isabs(dirname) # or the while will never terminate (dir_dirpath, dir_base) = os.path.split(dirname) while dir_base: if watcher_common.ignore_dir(dir_dirpath, dir_base, skip_files_re): return True (dir_dirpath, dir_base) = os.path.split(dir_dirpath) return False relpath = os.path.relpath(absolute_path, directory) if _recursive_ignore_dir(os.path.dirname(relpath)): continue logging.warning("Reloading instances due to change in %s", relpath) changes.add(absolute_path) self._changes = changes self._change_event.set()
def _generate_filename_to_mtime(self): filename_to_mtime = {} num_files = 0 for dirname, dirnames, filenames in os.walk(self._directory, followlinks=True): watcher_common.remove_ignored_dirs(dirnames) filenames = [f for f in filenames if not watcher_common.ignore_file(f)] for filename in filenames + dirnames: if num_files == 10000: warnings.warn( 'There are too many files in your application for ' 'changes in all of them to be monitored. You may have to ' 'restart the development server to see some changes to your ' 'files.') return filename_to_mtime num_files += 1 path = os.path.join(dirname, filename) try: mtime = os.path.getmtime(path) except (IOError, OSError): pass else: filename_to_mtime[path] = mtime return filename_to_mtime
def changes(self, timeout_ms=0): """Return paths for changed files and directories. start() must be called before this method. Args: timeout_ms: a timeout in milliseconds on which this watcher will block waiting for a change. It allows for external polling threads to react immediately on a change instead of waiting for a random polling delay. Returns: A set of strings representing file and directory paths that have changed since the last call to get_changed_paths. """ paths = set() while True: with self._inotify_fd_lock: if self._inotify_fd < 0: return set() # Don't wait to detect subsequent changes after the initial one. if not self._inotify_poll.poll( _AGGREGATE_CHANGES_MS_APART if paths else timeout_ms): break self._inotify_events += os.read(self._inotify_fd, 1024) while len(self._inotify_events) > _INOTIFY_EVENT_SIZE: wd, mask, cookie, length = _INOTIFY_EVENT.unpack( self._inotify_events[:_INOTIFY_EVENT_SIZE]) if len(self._inotify_events ) < _INOTIFY_EVENT_SIZE + length: break name = self._inotify_events[ _INOTIFY_EVENT_SIZE:_INOTIFY_EVENT_SIZE + length] name = name.rstrip('\0') logging.debug( 'wd=%s, mask=%s, cookie=%s, length=%s, name=%r', wd, _bit_str(mask, _ATTRIBUTE_MASK_NAMES), cookie, length, name) self._inotify_events = self._inotify_events[ _INOTIFY_EVENT_SIZE + length:] if mask & IN_IGNORED: continue try: directory = self._watch_to_directory[wd] except KeyError: logging.debug('Watch deleted for watch descriptor=%d', wd) continue path = os.path.join(directory, name) if os.path.isdir( path ) or path in self._directory_to_watch_descriptor: if mask & IN_DELETE: self._remove_watch_for_path(path) elif mask & IN_MOVED_FROM: self._remove_watch_for_path(path) elif mask & IN_CREATE: self._add_watch_for_path(path) elif mask & IN_MOVED_TO: self._add_watch_for_path(path) if path not in paths and not watcher_common.ignore_file( path): paths.add(path) return paths