fswatch: Ruby and FSEvents

|

The latest script I added to the dld-tools project (in my public Mercurial repositories) is called fswatch. The script, as of this writing, is available here. Click on “raw” to get a file you can save and run. Check the repository for newer updates.

fswatch is a Ruby script that uses the built-in RubyCocoa bridge to access the new File System Events (FSEvents) framework added in Leopard and watches for filesystem modifications while a command is run. Since FSEvents can efficiently watch a directory hierarchy, you can see what files a command touches or spews anywhere on the filesystem. One use case would be to see what a make install actually does. Here’s an example installing the GNU Hello program:

% sudo fswatch -o /tmp/hello-install.txt make install
% cat /tmp/hello-install.txt 
/
  tmp
/private/tmp/
  .
  hello-install.txt
/usr/local/bin/
  .
  hello
/usr/local/share/
  .
  info
/usr/local/share/info/
  .
  ..
  dir
  hello.info
/usr/local/share/man/man1/
  .
  hello.1

From the output, you can see that a binary, info documentation, and a man page were all installed at their standard locations in /usr/local. The implementation of this script is fairly simple. I used the watcher.rb example code as a starting point, which is installed with Xcode at:

/Developer/Examples/Ruby/RubyCocoa/Scripts/watcher.rb

Here’s the pseudo-code for the meat of fswatch:

startId = FSEventsGetCurrentEventId()
run_command
stream = FSEventStreamCreate(pathsToWatch => ["/"],
                             sinceWhen => startId)
FSEventStreamScheduleWithRunLoop(stream)
FSEventStreamStart(stream)
FSEventStreamFlushSync(stream)

The call to FSEventsGetCurrentEventId gets the event ID just before the command is executed. When the stream is created after the command is executed, you can use this as the sinceWhen argument to get all file system events from the pre-command state. The FSEventStreamFlushSync call gets all the file system events that have happened since before the command was run. It calls a callback setup in FSEventStreamCreate. See the API documentation for details on the FSEvents functions.

The only tricky part is that FSEvents only tells you directories that have been updated, not files. The script fudges this by scanning each directory that FSEvents gives it for files that have been modified since the command ran. This means, that there’s no way to list removed files. Another limitation is that FSEvents tells you all file system activity. If some other application happens to be writing to, say, ~/Library/Caches during execution of the command, then fswatch will pick this up, too. But, even with these limitations, I think this will be a fairly useful script.

blog comments powered by Disqus

About this Entry

This page contains a single entry by Dave published on January 4, 2008 3:53 PM.

My Public Mercurial Repositories was the previous entry in this blog.

Fun with Fast Enumeration is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Links

Powered by Movable Type 4.1