12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/Path.h" 15 #include <CoreServices/CoreServices.h> 18 using namespace clang;
31 FSEventStreamRef EventStream,
34 llvm::StringRef WatchedDirPath)
35 : EventStream(EventStream), Receiver(Receiver),
36 WatchedDirPath(WatchedDirPath) {}
38 ~DirectoryWatcherMac()
override {
40 EventStream =
nullptr;
44 DirectoryWatcher::Event::EventKind::WatcherGotInvalidated,
""),
49 FSEventStreamRef EventStream;
50 std::function<void(llvm::ArrayRef<Event>,
bool)> Receiver;
51 const std::string WatchedDirPath;
54 struct EventStreamContextData {
55 std::string WatchedPath;
56 std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>,
bool)> Receiver;
58 EventStreamContextData(
59 std::string &&WatchedPath,
62 : WatchedPath(
std::move(WatchedPath)), Receiver(Receiver) {}
65 static void dispose(
const void *ctx) {
66 delete static_cast<const EventStreamContextData *
>(ctx);
72 kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped |
73 kFSEventStreamEventFlagMustScanSubDirs;
76 kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemRenamed |
77 kFSEventStreamEventFlagItemModified;
80 void *ClientCallBackInfo,
size_t NumEvents,
82 const FSEventStreamEventFlags EventFlags[],
83 const FSEventStreamEventId EventIds[]) {
84 auto *ctx =
static_cast<EventStreamContextData *
>(ClientCallBackInfo);
86 std::vector<DirectoryWatcher::Event> Events;
87 for (
size_t i = 0;
i < NumEvents; ++
i) {
88 StringRef Path = ((
const char **)EventPaths)[
i];
89 const FSEventStreamEventFlags Flags = EventFlags[
i];
91 if (Flags & StreamInvalidatingFlags) {
93 DirectoryWatcher::Event::EventKind::WatcherGotInvalidated,
""});
95 }
else if (!(Flags & kFSEventStreamEventFlagItemIsFile)) {
98 if ((Flags & kFSEventStreamEventFlagItemRemoved) &&
99 Path == ctx->WatchedPath) {
101 DirectoryWatcher::Event::EventKind::WatchedDirRemoved,
""});
103 DirectoryWatcher::Event::EventKind::WatcherGotInvalidated,
""});
108 }
else if (Flags & kFSEventStreamEventFlagItemRemoved) {
109 Events.emplace_back(DirectoryWatcher::Event::EventKind::Removed,
110 llvm::sys::path::filename(Path));
112 }
else if (Flags & ModifyingFileEvents) {
114 Events.emplace_back(DirectoryWatcher::Event::EventKind::Removed,
115 llvm::sys::path::filename(Path));
117 Events.emplace_back(DirectoryWatcher::Event::EventKind::Modified,
118 llvm::sys::path::filename(Path));
125 DirectoryWatcher::Event::EventKind::WatcherGotInvalidated,
""});
126 llvm_unreachable(
"Unknown FSEvent type.");
129 if (!Events.empty()) {
130 ctx->Receiver(Events,
false);
137 dispatch_queue_t Queue) {
141 CFMutableArrayRef PathsToWatch = [&]() {
142 CFMutableArrayRef PathsToWatch =
143 CFArrayCreateMutable(
nullptr, 0, &kCFTypeArrayCallBacks);
144 CFStringRef CfPathStr =
145 CFStringCreateWithBytes(
nullptr, (
const UInt8 *)Path.data(),
146 Path.size(), kCFStringEncodingUTF8,
false);
147 CFArrayAppendValue(PathsToWatch, CfPathStr);
148 CFRelease(CfPathStr);
152 FSEventStreamContext Context = [&]() {
153 std::string RealPath;
156 StringRef
P = llvm::Twine(Path).toNullTerminatedStringRef(Storage);
157 char Buffer[PATH_MAX];
158 if (::realpath(P.begin(), Buffer) !=
nullptr)
164 FSEventStreamContext Context;
166 Context.info =
new EventStreamContextData(std::move(RealPath), Receiver);
167 Context.retain =
nullptr;
168 Context.release = EventStreamContextData::dispose;
169 Context.copyDescription =
nullptr;
173 FSEventStreamRef Result = FSEventStreamCreate(
175 kFSEventStreamEventIdSinceNow, 0.0,
176 kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer);
177 CFRelease(PathsToWatch);
185 FSEventStreamStop(EventStream);
186 FSEventStreamInvalidate(EventStream);
187 FSEventStreamRelease(EventStream);
193 bool WaitForInitialSync) {
194 dispatch_queue_t Queue =
195 dispatch_queue_create(
"DirectoryWatcher", DISPATCH_QUEUE_SERIAL);
205 std::unique_ptr<DirectoryWatcher> Result =
206 llvm::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path);
210 const std::string CopiedPath = Path;
217 FSEventStreamSetDispatchQueue(EventStream, Queue);
218 FSEventStreamStart(EventStream);
222 dispatch_release(Queue);
226 if (WaitForInitialSync) {
227 dispatch_sync(Queue, InitWork);
229 dispatch_async(Queue, InitWork);
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
std::vector< DirectoryWatcher::Event > getAsFileEvents(const std::vector< std::string > &Scan)
Create event with EventKind::Added for every element in Scan.
static FSEventStreamRef createFSEventStream(StringRef Path, std::function< void(llvm::ArrayRef< DirectoryWatcher::Event >, bool)>, dispatch_queue_t)
std::vector< std::string > scanDirectory(StringRef Path)
constexpr const FSEventStreamEventFlags StreamInvalidatingFlags
constexpr const FSEventStreamEventFlags ModifyingFileEvents
static void stopFSEventStream(FSEventStreamRef)
Optional< sys::fs::file_status > getFileStatus(StringRef Path)
Dataflow Directional Tag Classes.
static void eventStreamCallback(ConstFSEventStreamRef Stream, void *ClientCallBackInfo, size_t NumEvents, void *EventPaths, const FSEventStreamEventFlags EventFlags[], const FSEventStreamEventId EventIds[])
static std::unique_ptr< DirectoryWatcher > create(llvm::StringRef Path, std::function< void(llvm::ArrayRef< DirectoryWatcher::Event > Events, bool IsInitial)> Receiver, bool WaitForInitialSync)
Returns nullptr if.
Provides notifications for file changes in a directory.