Watcher::ConsumeNotifyRet FSEventsWatcher::consumeNotify()

in watchman/watcher/fsevents.cpp [679:802]


Watcher::ConsumeNotifyRet FSEventsWatcher::consumeNotify(
    const std::shared_ptr<Root>& root,
    PendingChanges& coll) {
  char flags_label[128];
  std::vector<std::vector<watchman_fsevent>> items;
  std::vector<folly::Promise<folly::Unit>> syncs;
  bool cancelSelf = false;

  {
    auto wlock = items_.lock();
    std::swap(items, wlock->items);
    std::swap(syncs, wlock->syncs);
  }

  auto now = std::chrono::system_clock::now();

  for (auto& vec : items) {
    for (auto& item : vec) {
      w_expand_flags(kflags, item.flags, flags_label, sizeof(flags_label));
      logf(
          DBG,
          "fsevents: got {} {:x} {}\n",
          item.path,
          item.flags,
          flags_label);

      if (item.flags &
          (kFSEventStreamEventFlagUserDropped |
           kFSEventStreamEventFlagKernelDropped)) {
        if (!subdir) {
          root->scheduleRecrawl(flags_label);
          break;
        } else {
          w_assert(
              item.flags & kFSEventStreamEventFlagMustScanSubDirs,
              "dropped events should specify kFSEventStreamEventFlagMustScanSubDirs");
          auto reason = fmt::format("{}: {}", *subdir, flags_label);
          root->recrawlTriggered(reason.c_str());
        }
      }

      if (item.flags & kFSEventStreamEventFlagUnmount) {
        logf(
            ERR,
            "kFSEventStreamEventFlagUnmount {}, cancel watch\n",
            item.path);
        cancelSelf = true;
        break;
      }

      if ((item.flags & kFSEventStreamEventFlagItemRemoved) &&
          isRootRemoved(item.path, root->root_path, subdir)) {
        log(ERR, "Root directory removed, cancel watch\n");
        cancelSelf = true;
        break;
      }

      if (item.flags & kFSEventStreamEventFlagRootChanged) {
        logf(
            ERR,
            "kFSEventStreamEventFlagRootChanged {}, cancel watch\n",
            item.path);
        cancelSelf = true;
        break;
      }

      if (!hasFileWatching_ && item.path.size() < root->root_path.size()) {
        // The test_watch_del_all appear to trigger this?
        log(ERR,
            "Got an event on a directory parent to the root directory: {}?\n",
            item.path);
        continue;
      }

      PendingFlags flags = W_PENDING_VIA_NOTIFY;

      if (item.flags &
          (kFSEventStreamEventFlagMustScanSubDirs |
           kFSEventStreamEventFlagItemRenamed)) {
        flags.set(W_PENDING_RECURSIVE);
      } else if (item.flags & kFSEventStreamEventFlagItemRenamed) {
        // FSEvents does not reliably report the individual files renamed in the
        // hierarchy.
        flags.set(W_PENDING_NONRECURSIVE_SCAN);
      } else if (!hasFileWatching_) {
        flags.set(W_PENDING_NONRECURSIVE_SCAN);
      }

      if (item.flags &
          (kFSEventStreamEventFlagUserDropped |
           kFSEventStreamEventFlagKernelDropped)) {
        flags.set(W_PENDING_IS_DESYNCED);
      }

      coll.add(item.path, now, flags);

      if (hasFileWatching_ && item.path.size() > root->root_path.size() &&
          (item.flags &
           (kFSEventStreamEventFlagItemRenamed |
            kFSEventStreamEventFlagItemCreated |
            kFSEventStreamEventFlagItemRemoved))) {
        // When the list of directory entries is modified, we hear
        // about the modification, but perhaps not the directory
        // change itself. Its mtime probably changed, so synthesize
        // an event to consider it for examination.
        //
        // Note these two issues:
        // - https://github.com/facebook/watchman/issues/305
        // - https://github.com/facebook/watchman/issues/307
        //
        // Watchman does not guarantee minimal notifications, but limiting
        // the event types above should avoid unnecessary results in
        // queries.
        coll.add(item.path.dirName(), now, W_PENDING_VIA_NOTIFY);
      }
    }
  }

  for (auto& sync : syncs) {
    coll.addSync(std::move(sync));
  }

  return {cancelSelf};
}