Exemple #1
0
def _generate_sub_moved_events_for(src_dir_path, dest_dir_path,
                                   _walker=os.walk):
    """Generates an event list of :class:`DirMovedEvent` and :class:`FileMovedEvent`
    objects for all the files and directories within the given moved directory
    that were moved along with the directory.

    :param src_dir_path:
        The source path of the moved directory.
    :param dest_dir_path:
        The destination path of the moved directory.
    :param _walker:
        Walker used to walk directory trees :func:`os.walk` style. Sanity tests
        use this parameter to inject a mock walker that behaves like
        :func:`os.walk`.
    :returns:
        An iterable of file system events of type :class:`DirMovedEvent` and
        :class:`FileMovedEvent`.
    """
    src_dir_path = absolute_path(src_dir_path)
    dest_dir_path = absolute_path(dest_dir_path)
    for root, directories, filenames in _walker(dest_dir_path):
        for directory in directories:
            full_path = os.path.join(root, directory)
            renamed_path = full_path.replace(dest_dir_path, src_dir_path)
            yield DirMovedEvent(renamed_path, full_path)
        for filename in filenames:
            full_path = os.path.join(root, filename)
            renamed_path = full_path.replace(dest_dir_path, src_dir_path)
            yield FileMovedEvent(renamed_path, full_path)
Exemple #2
0
    def on_modified(self, event):
        template_processor = JinjaTemplateProcessor()

        output_dir = template_processor.mkdirs(event.src_path,
                path.absolute_path(config_dev.dest_path),
                path.absolute_path(config_dev.source_path))

        output_file = template_processor.write_templates(event.src_path,
                output_dir)

        print "jinja wrote file %s" % output_file
Exemple #3
0
 def __init__(self, path, is_directory):
     self._path = absolute_path(path)
     self._is_directory = is_directory
     self._fd = os.open(path, WATCHDOG_OS_OPEN_FLAGS)
     self._kev = select.kevent(
         self._fd, filter=WATCHDOG_KQ_FILTER, flags=WATCHDOG_KQ_EV_FLAGS, fflags=WATCHDOG_KQ_FFLAGS
     )
Exemple #4
0
    def __init__(self,
                 path,
                 recursive=False,
                 event_mask=WATCHDOG_ALL_EVENTS,
                 non_blocking=False):
    # The file descriptor associated with the inotify instance.
      if non_blocking:
        inotify_fd = inotify_init1(InotifyConstants.IN_NONBLOCK)
      else:
        inotify_fd = inotify_init()
      if inotify_fd == -1:
        Inotify._raise_error()
      self._inotify_fd = inotify_fd
      self._lock = threading.Lock()

      # Stores the watch descriptor for a given path.
      self._wd_for_path = dict()
      self._path_for_wd = dict()

      path = absolute_path(path)
      self._path = path
      self._event_mask = event_mask
      self._is_recursive = recursive
      self._is_non_blocking = non_blocking
      self._add_dir_watch(path, recursive, event_mask)
      self._moved_from_events = dict()
Exemple #5
0
    def __init__(self, path, recursive=True, walker_callback=(lambda p, s: None), _copying=False):
        self._path = absolute_path(path)
        self._stat_snapshot = {}
        self._inode_to_path = {}
        self.is_recursive = recursive

        if not _copying:
            stat_info = os.stat(self._path)
            self._stat_snapshot[self._path] = stat_info
            self._inode_to_path[stat_info.st_ino] = self._path
            walker_callback(self._path, stat_info)

            for root, directories, files in path_walk(self._path, recursive):
                for directory_name in directories:
                    try:
                        directory_path = os.path.join(root, directory_name)
                        stat_info = os.stat(directory_path)
                        self._stat_snapshot[directory_path] = stat_info
                        self._inode_to_path[stat_info.st_ino] = directory_path
                        walker_callback(directory_path, stat_info)
                    except OSError:
                        continue

                for file_name in files:
                    try:
                        file_path = os.path.join(root, file_name)
                        stat_info = os.stat(file_path)
                        self._stat_snapshot[file_path] = stat_info
                        self._inode_to_path[stat_info.st_ino] = file_path
                        walker_callback(file_path, stat_info)
                    except OSError:
                        continue
    def _queue_renamed(self, src_path, is_directory, ref_snapshot, new_snapshot):
        try:
            ref_stat_info = ref_snapshot.stat_info(src_path)
        except KeyError:
            if is_directory:
                self.queue_event(DirCreatedEvent(src_path))
                self.queue_event(DirDeletedEvent(src_path))
            else:
                self.queue_event(FileCreatedEvent(src_path))
                self.queue_event(FileDeletedEvent(src_path))
            return

        try:
            dest_path = absolute_path(new_snapshot.path_for_inode(ref_stat_info.st_ino))
            if is_directory:
                event = DirMovedEvent(src_path, dest_path)
                if self.watch.is_recursive:
                    for sub_event in event.sub_moved_events():
                        self.queue_event(sub_event)

                self.queue_event(event)
            else:
                self.queue_event(FileMovedEvent(src_path, dest_path))
        except KeyError:
            if is_directory:
                self.queue_event(DirDeletedEvent(src_path))
            else:
                self.queue_event(FileDeletedEvent(src_path))
Exemple #7
0
 def __init__(self, doc, dbs, update_delay=DEFAULT_UPDATE_DELAY, 
         noatomic=False):
     self.doc_path = absolute_path(doc.docdir)
     self.event_handler = CouchappEventHandler(doc, dbs,
             update_delay=update_delay, noatomic=noatomic)
     self.observer = Observer()
     self.observer.schedule(self.event_handler,
             self.doc_path, recursive=True)
Exemple #8
0
 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)
Exemple #9
0
    def get(self, path):
        """
        Obtains a :class:`KeventDescriptor` object for the specified path.

        :param path:
            Path for which the descriptor will be obtained.
        """
        with self._lock:
            path = absolute_path(path)
            return self._get(path)
Exemple #10
0
 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
Exemple #11
0
    def add_watch(self, path):
      """
      Adds a watch for the given path.

      :param path:
          Path to begin monitoring.
      """
      with self._lock:
        path = absolute_path(path)
        self._add_watch(path, self._event_mask)
Exemple #12
0
    def remove_watch(self, path):
      """
      Removes a watch for the given path.

      :param path:
          Path string for which the watch will be removed.
      """
      with self._lock:
        path = absolute_path(path)
        self._remove_watch(path)
Exemple #13
0
    def __contains__(self, path):
        """
        Determines whether a :class:`KeventDescriptor has been registered
        for the specified path.

        :param path:
            Path for which the descriptor will be obtained.
        """
        with self._lock:
            path = absolute_path(path)
            return self._has_path(path)
    def queue_events(self, timeout):
      with self._lock:
        dir_changes, nbytes = read_directory_changes(self._directory_handle,
                                                     self._buffer,
                                                     self.watch.is_recursive)
        last_renamed_src_path = ""
        for action, src_path in get_FILE_NOTIFY_INFORMATION(dir_changes,
                                                            nbytes):
          src_path = absolute_path(os.path.join(self.watch.path,
                                                src_path))

          if action == FILE_ACTION_RENAMED_OLD_NAME:
            continue
            last_renamed_src_path = src_path
          elif action == FILE_ACTION_RENAMED_NEW_NAME:
            continue
            dest_path = src_path
            src_path = last_renamed_src_path

            if os.path.isdir(dest_path):
              event = DirMovedEvent(src_path, dest_path)
              if self.watch.is_recursive:
                # HACK: We introduce a forced delay before
                # traversing the moved directory. This will read
                # only file movement that finishes within this
                # delay time.
                time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY)
                # The following block of code may not
                # obtain moved events for the entire tree if
                # the I/O is not completed within the above
                # delay time. So, it's not guaranteed to work.
                # TODO: Come up with a better solution, possibly
                # a way to wait for I/O to complete before
                # queuing events.
                for sub_moved_event in event.sub_moved_events():
                  self.queue_event(sub_moved_event)
              self.queue_event(event)
            else:
              self.queue_event(FileMovedEvent(src_path, dest_path))
          else:
            if os.path.isdir(src_path):
              continue
              event = DIR_ACTION_EVENT_MAP[action](src_path)
              if isinstance(event, DirCreatedEvent):
                # If a directory is moved from outside the watched folder to inside it
                # we only get a created directory event out of it, not any events for its children
                # so use the same hack as for file moves to get the child events
                time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY)
                sub_events = _generate_sub_created_events_for(src_path)
                for sub_created_event in sub_events:
                  self.queue_event(sub_created_event)
              self.queue_event(event)
            else:
              self.queue_event(FILE_ACTION_EVENT_MAP[action](src_path))
Exemple #15
0
    def remove(self, path):
        """
        Removes the :class:`KeventDescriptor` object for the given path
        if it already exists.

        :param path:
            Path for which the :class:`KeventDescriptor` object will be
            removed.
        """
        with self._lock:
            path = absolute_path(path)
            if self._has_path(path):
                self._remove_descriptor(self._get(path))
Exemple #16
0
    def _queue_renamed(self,
                       src_path,
                       is_directory,
                       ref_snapshot,
                       new_snapshot):
        """
        Compares information from two directory snapshots (one taken before
        the rename operation and another taken right after) to determine the
        destination path of the file system object renamed, and adds
        appropriate events to the event queue.
        """
        try:
            ref_stat_info = ref_snapshot.stat_info(src_path)
        except KeyError:
            # Probably caught a temporary file/directory that was renamed
            # and deleted. Fires a sequence of created and deleted events
            # for the path.
            if is_directory:
                self.queue_event(DirCreatedEvent(src_path))
                self.queue_event(DirDeletedEvent(src_path))
            else:
                self.queue_event(FileCreatedEvent(src_path))
                self.queue_event(FileDeletedEvent(src_path))
                # We don't process any further and bail out assuming
            # the event represents deletion/creation instead of movement.
            return

        try:
            dest_path = absolute_path(
                new_snapshot.path_for_inode(ref_stat_info.st_ino))
            if is_directory:
                event = DirMovedEvent(src_path, dest_path)
                # TODO: Do we need to fire moved events for the items
                # inside the directory tree? Does kqueue does this
                # all by itself? Check this and then enable this code
                # only if it doesn't already.
                # A: It doesn't. So I've enabled this block.
                if self.watch.is_recursive:
                    for sub_event in event.sub_moved_events():
                        self.queue_event(sub_event)
                self.queue_event(event)
            else:
                self.queue_event(FileMovedEvent(src_path, dest_path))
        except KeyError:
            # If the new snapshot does not have an inode for the
            # old path, we haven't found the new name. Therefore,
            # we mark it as deleted and remove unregister the path.
            if is_directory:
                self.queue_event(DirDeletedEvent(src_path))
            else:
                self.queue_event(FileDeletedEvent(src_path))
Exemple #17
0
    def add(self, path, is_directory):
        """
        Adds a :class:`KeventDescriptor` to the collection for the given
        path.

        :param path:
            The path for which a :class:`KeventDescriptor` object will be
            added.
        :param is_directory:
            ``True`` if the path refers to a directory; ``False`` otherwise.
        :type is_directory:
            ``bool``
        """
        with self._lock:
            path = absolute_path(path)
            if not self._has_path(path):
                self._add_descriptor(KeventDescriptor(path, is_directory))
    def queue_events(self, timeout):
      with self._lock:
        dir_changes, nbytes = read_directory_changes(self._directory_handle,
                                                     self._buffer,
                                                     self.watch.is_recursive)
        last_renamed_src_path = ""
        for action, src_path in get_FILE_NOTIFY_INFORMATION(dir_changes,
                                                            nbytes):
          src_path = absolute_path(os.path.join(self.watch.path,
                                                src_path))

          if action == FILE_ACTION_RENAMED_OLD_NAME:
            last_renamed_src_path = src_path
          elif action == FILE_ACTION_RENAMED_NEW_NAME:
            dest_path = src_path
            src_path = last_renamed_src_path

            if os.path.isdir(dest_path):
              event = DirMovedEvent(src_path, dest_path)
              if self.watch.is_recursive:
                # HACK: We introduce a forced delay before
                # traversing the moved directory. This will read
                # only file movement that finishes within this
                # delay time.
                time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY)
                # The following block of code may not
                # obtain moved events for the entire tree if
                # the I/O is not completed within the above
                # delay time. So, it's not guaranteed to work.
                # TODO: Come up with a better solution, possibly
                # a way to wait for I/O to complete before
                # queuing events.
                for sub_moved_event in event.sub_moved_events():
                  self.queue_event(sub_moved_event)
              self.queue_event(event)
            else:
              self.queue_event(FileMovedEvent(src_path,
                                              dest_path))
          else:
            if os.path.isdir(src_path):
              action_event_map = DIR_ACTION_EVENT_MAP
            else:
              action_event_map = FILE_ACTION_EVENT_MAP
            self.queue_event(action_event_map[action](src_path))
Exemple #19
0
def schedule_tricks(observer, tricks, pathname, recursive):
    """
    Schedules tricks with the specified observer and for the given watch
    path.

    :param observer:
        The observer thread into which to schedule the trick and watch.
    :param tricks:
        A list of tricks.
    :param pathname:
        A path name which should be watched.
    :param recursive:
        ``True`` if recursive; ``False`` otherwise.
    """
    for trick in tricks:
        for name, value in trick.items():
            TrickClass = load_class(name)
            handler = TrickClass(**value)
            trick_pathname = absolute_path(getattr(handler, 'source_directory') or pathname)
            observer.schedule(handler, trick_pathname, recursive)
Exemple #20
0
        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.
            """
            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))
                        self._add_watch(full_path, mask)
Exemple #21
0
        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 = 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:
                            # 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
Exemple #22
0
 def __contains__(self, path):
    
     with self._lock:
         path = absolute_path(path)
         return self._has_path(path)
Exemple #23
0
 def add(self, path, is_directory):
     
     with self._lock:
         path = absolute_path(path)
         if not self._has_path(path):
             self._add_descriptor(KeventDescriptor(path, is_directory))
Exemple #24
0
    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
Exemple #25
0
  from cStringIO import StringIO
except ImportError:
  from StringIO import StringIO

from argh import arg, alias, ArghParser

from watchdog.version import VERSION_STRING
from watchdog.utils import\
  read_text_file,\
  load_class
from pathtools.path import absolute_path, parent_dir_path


logging.basicConfig(level=logging.DEBUG)

CURRENT_DIR = absolute_path(os.getcwd())
DEFAULT_TRICKS_FILE_NAME = 'tricks.yaml'
DEFAULT_TRICKS_FILE_PATH = os.path.join(CURRENT_DIR, DEFAULT_TRICKS_FILE_NAME)
CONFIG_KEY_TRICKS = 'tricks'
CONFIG_KEY_PYTHON_PATH = 'python-path'


def path_split(pathname_spec, separator=os.path.sep):
  """
  Splits a pathname specification separated by an OS-dependent separator.

  :param pathname_spec:
      The pathname specification.
  :param separator:
      (OS Dependent) `:` on Unix and `;` on Windows or user-specified.
  """
Exemple #26
0
 def __init__(self, path, recursive):
     self._path = absolute_path(path)
     self._is_recursive = recursive
 def test___repr__(self):
   observed_watch = ObservedWatch('/foobar', True)
   self.assertEqual('<ObservedWatch: path=' + absolute_path('/foobar') + ', is_recursive=True>',
                    observed_watch.__repr__())
  def test_generate_sub_moved_events_for(self):
    mock_walker_path = [
      (absolute_path('/path'),
       ['ad', 'bd'],
       ['af', 'bf', 'cf']),
      (absolute_path('/path/ad'),
       [],
       ['af', 'bf', 'cf']),
      (absolute_path('/path/bd'),
       [],
       ['af', 'bf', 'cf']),
    ]
    dest_path = absolute_path('/path')
    src_path = absolute_path('/foobar')
    expected_events = set([
      DirMovedEvent(absolute_path('/foobar/ad'), absolute_path('/path/ad')),
      DirMovedEvent(absolute_path('/foobar/bd'), absolute_path('/path/bd')),
      FileMovedEvent(absolute_path('/foobar/af'), absolute_path('/path/af')),
      FileMovedEvent(absolute_path('/foobar/bf'), absolute_path('/path/bf')),
      FileMovedEvent(absolute_path('/foobar/cf'), absolute_path('/path/cf')),
      FileMovedEvent(absolute_path('/foobar/ad/af'), absolute_path('/path/ad/af')),
      FileMovedEvent(absolute_path('/foobar/ad/bf'), absolute_path('/path/ad/bf')),
      FileMovedEvent(absolute_path('/foobar/ad/cf'), absolute_path('/path/ad/cf')),
      FileMovedEvent(absolute_path('/foobar/bd/af'), absolute_path('/path/bd/af')),
      FileMovedEvent(absolute_path('/foobar/bd/bf'), absolute_path('/path/bd/bf')),
      FileMovedEvent(absolute_path('/foobar/bd/cf'), absolute_path('/path/bd/cf')),
      ])

    def _mock_os_walker(path):
      for root, directories, filenames in mock_walker_path:
        yield (root, directories, filenames)

    calculated_events = set(
      _generate_sub_moved_events_for(
        src_path, dest_path, _walker=_mock_os_walker))
    self.assertEqual(expected_events, calculated_events)
Exemple #29
0
 def remove(self, path):
     
     with self._lock:
         path = absolute_path(path)
         if self._has_path(path):
             self._remove_descriptor(self._get(path))
Exemple #30
0
        def read_events(self, event_buffer_size=DEFAULT_EVENT_BUFFER_SIZE):
            """
            Reads events from inotify and yields them.
            """
            with self._lock:
                event_buffer = os.read(self._inotify_fd, event_buffer_size)
                event_list = []
                for wd, mask, cookie, name in Inotify._parse_event_buffer(
                        event_buffer):
                    wd_path = 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:
                            # 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 inotify_event.is_directory:
                        if 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.
                            self._add_watch(src_path, self._event_mask)

                            for root, dirnames, filenames in os.walk(src_path):
                                for dirname in dirnames:
                                    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))
                                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
Exemple #31
0
    def queue_events(self, timeout):
      for idx in xrange(len(self.pathnames)):
        event_path = absolute_path(self.pathnames[idx])
        event_flags = self.flags[idx]

        if not self.watch.is_recursive and self.watch.path != event_path:
          return

        recursive_update = bool(event_flags & FSEventsStreamFlag.MustScanSubDirs)

        # try to build only partial snapshot
        new_snapshot = DirectorySnapshot(
          event_path,
          recursive_update
        )

        if recursive_update and self.watch.path == event_path:
          # no optimization is possible
          events = new_snapshot - self.snapshot
          self.snapshot = new_snapshot
        else:
          # partial comparison will be done
          previous_snapshot = self.snapshot.copy(event_path, recursive_update)

          # compare them
          events = new_snapshot - previous_snapshot

          if events.dirs_deleted or events.dirs_created or events.dirs_moved:
            # add files from deleted dir to previous snapshot
            previous_snapshot.add_entries(self.snapshot.copy_multiple(events.dirs_deleted, True))

            # add files from created dir to new_snapshot, create a recursive snapshot of new dir
            for new_path in events.dirs_created:
              new_snapshot.add_entries(DirectorySnapshot(new_path, True))

            previous_snapshot.add_entries(
              self.snapshot.copy_multiple(
                [old_path for (old_path, new_path) in events.dirs_moved],
                True
              )
            )
            for old_path, new_path in events.dirs_moved:
              new_snapshot.add_entries(DirectorySnapshot(new_path, True))

            # re-do diff
            events = new_snapshot - previous_snapshot

          # update last snapshot
          self.snapshot.remove_entries(previous_snapshot)
          self.snapshot.add_entries(new_snapshot)

        # Files.
        for src_path in events.files_deleted:
          self.queue_event(FileDeletedEvent(src_path))
        for src_path in events.files_modified:
          self.queue_event(FileModifiedEvent(src_path))
        for src_path in events.files_created:
          self.queue_event(FileCreatedEvent(src_path))
        for src_path, dest_path in events.files_moved:
          self.queue_event(FileMovedEvent(src_path, dest_path))

        # Directories.
        for src_path in events.dirs_deleted:
          self.queue_event(DirDeletedEvent(src_path))
        for src_path in events.dirs_modified:
          self.queue_event(DirModifiedEvent(src_path))
        for src_path in events.dirs_created:
          self.queue_event(DirCreatedEvent(src_path))
        for src_path, dest_path in events.dirs_moved:
          self.queue_event(DirMovedEvent(src_path, dest_path))
    def test_generate_sub_moved_events_for(self):
        mock_walker_path = [
            (absolute_path('/path'), ['ad', 'bd'], ['af', 'bf', 'cf']),
            (absolute_path('/path/ad'), [], ['af', 'bf', 'cf']),
            (absolute_path('/path/bd'), [], ['af', 'bf', 'cf']),
        ]
        dest_path = absolute_path('/path')
        src_path = absolute_path('/foobar')
        expected_events = set([
            DirMovedEvent(absolute_path('/foobar/ad'),
                          absolute_path('/path/ad')),
            DirMovedEvent(absolute_path('/foobar/bd'),
                          absolute_path('/path/bd')),
            FileMovedEvent(absolute_path('/foobar/af'),
                           absolute_path('/path/af')),
            FileMovedEvent(absolute_path('/foobar/bf'),
                           absolute_path('/path/bf')),
            FileMovedEvent(absolute_path('/foobar/cf'),
                           absolute_path('/path/cf')),
            FileMovedEvent(absolute_path('/foobar/ad/af'),
                           absolute_path('/path/ad/af')),
            FileMovedEvent(absolute_path('/foobar/ad/bf'),
                           absolute_path('/path/ad/bf')),
            FileMovedEvent(absolute_path('/foobar/ad/cf'),
                           absolute_path('/path/ad/cf')),
            FileMovedEvent(absolute_path('/foobar/bd/af'),
                           absolute_path('/path/bd/af')),
            FileMovedEvent(absolute_path('/foobar/bd/bf'),
                           absolute_path('/path/bd/bf')),
            FileMovedEvent(absolute_path('/foobar/bd/cf'),
                           absolute_path('/path/bd/cf')),
        ])

        def _mock_os_walker(path):
            for root, directories, filenames in mock_walker_path:
                yield (root, directories, filenames)

        calculated_events = set(
            _generate_sub_moved_events_for(src_path,
                                           dest_path,
                                           _walker=_mock_os_walker))
        self.assertEqual(expected_events, calculated_events)