// // FileSystemWatcher.m // Pulse // // Created by Matt Attaway on 1/9/14. // Copyright (c) 2014 Zen of the Monkey. All rights reserved. // #import "PLSFileEvent.h" #import "FileSystemWatcher.h" void fsevents_callback(ConstFSEventStreamRef streamRef, void * userData, size_t numEvents, void * eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]); @implementation FileSystemWatcher -(void)dealloc { [self stopWatching]; } - (void)watchPath:(NSString*)path target:(NSObject< FileSystemWatcherDelegate > *)target { listener = target; NSArray* pathsToWatch = [NSArray arrayWithObjects:path, nil]; void* appPointer = (__bridge void *)self; FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL}; NSTimeInterval latency = 1.0; stream = FSEventStreamCreate( NULL, &fsevents_callback, &context, (__bridge CFArrayRef) pathsToWatch, kFSEventStreamEventIdSinceNow, (CFAbsoluteTime) latency, kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer ); FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); } -(void)fileEvent:(PLSFileEvent*)event { [listener fileEvent:event]; } - (void)startWatching { if(stream) { FSEventStreamStart(stream); } } - (void)pauseWatching { if(stream) { FSEventStreamStop(stream); } } - (void)stopWatching { FSEventStreamStop(stream); FSEventStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamInvalidate(stream); FSEventStreamRelease(stream); } @end void fsevents_callback(ConstFSEventStreamRef streamRef, void * userData, size_t numEvents, void * eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) { uint32 modifiedFiles = kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemRemoved | kFSEventStreamEventFlagItemRenamed |kFSEventStreamEventFlagItemModified; FileSystemWatcher * watcher = (__bridge FileSystemWatcher *)userData; NSLog(@"File Changed! %zu", numEvents); char **paths = eventPaths; NSMutableArray* fileActions = [[NSMutableArray alloc] init]; NSMutableArray* files = [[NSMutableArray alloc] init]; for( int i = 0; i < numEvents; i++ ) { if(eventFlags[i] & modifiedFiles) { [files addObject:[NSString stringWithUTF8String:paths[i]]]; [fileActions addObject:[[NSNumber alloc] initWithUnsignedInt:(unsigned int)eventFlags[i]]]; NSLog(@"Change %llu in %s, flags %x\n", eventIds[i], paths[i], (unsigned int)eventFlags[i]); } else { NSLog(@"Ignoring %llu in %s, flags %x\n", eventIds[i], paths[i], (unsigned int)eventFlags[i]); } } if([files count] > 0) { PLSFileEvent* event = [[PLSFileEvent alloc] init]; event.fileActions = fileActions; event.files = files; [watcher fileEvent:event]; } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 8706 | Matt Attaway |
Infrastructure work to more intelligently handle FSEvents Prior to this change all file system events were equal; chown-ing a file was considered the same as changing the content. With this change we: 1) bundle all of the file events into one operation instead or doing it one file at a time 2) ignore any file events that are not create/delete/modify/rename The interfaces are all in place, but the Overseers are still not taking advantage of this information, so there’s no user visible change at this time. (hopefully) Infrastructure only change |
||
#4 | 8523 | Matt Attaway |
Prevent double start call to FSEvents This was a bit of shuffling, but the behavior is much tidier now. Overseers do not start overseeing until they are explicitly told to do so. This makes their behavior much more predictable. |
||
#3 | 8522 | Matt Attaway |
Clean up the behavior of the connections dialog All of the Overseers are now paused while the connection dialog is up so that the user can fiddle with their settings in peace. |
||
#2 | 8509 | Matt Attaway |
Add support for loading multiple connections The code is rough, but Pulse can now load up and start watching multiple paths, each associated with a separate Perforce server. Also cleaned up some white space and normalized the ‘*’ used to denote pointers. |
||
#1 | 8502 | Matt Attaway |
Initial checkin of Pulse, a lightweight Perforce client for the Mac This is a sketch of what a Perforce client inspired by the UX of cloud synchronization software would look like. I’m not trying to build something production worthy yet; at this point I’m just trying to get something up and running as fast as possible so I can play with the UX. At this point I can monitor a directory and kick off ‘p4 info’ calls anytime a file changes. It is the polar opposite of useful. Do note I’ve never written code in Objective-C before. Here be ugly, malformed dragons. |