Sat, 29 Sep 07

Monitoring the Mac OSX Filesystem with ruby

On Thursday, James and I spent some time investigating remote pairing options. One tiny part of that investigation was finding a way to keep two remote filesystems in sync. I initially thought of using rsync at regular intervals with cron. Unless I’ve missed something, the smallest interval between cron jobs is one minute which is potentially too long. We wanted a way to rsync (or sync in general) whenever the filesystem changed. A little searching brought this fslogger tool to my attention. It simply writes some event details to STDOUT every time something changes on the filesystem. I figured that we could use this, with a little bit of ruby glue, to trigger rsync. Our glue script continuously reads from STDIN, tries to match some pre-defined patterns and triggers rsync if those patterns are matched. It’s very brittle but it gets the job done. Well, actually, it only partially gets the job done: I’m very unfamiliar with rsync but it seemed to take between 10 and 30 seconds to sync even if only one file had changed. I suspect that I may have been doing something wrong though.

#!/usr/bin/env ruby

REMOTE_SERVER = 'YOUR_REMOTE_SERVER'
REMOTE_PATH = 'YOUR_REMOTE_PATH'

DIRECTORY_PATTERN = ARGV.delete_at(0)
raise "You must specify a directory_pattern" unless DIRECTORY_PATTERN

def rsync!
  `rsync -rz #{File.join(DIRECTORY_PATTERN, '*')} #{REMOTE_SERVER}:#{REMOTE_PATH}`
end

while line=gets
  if line =~ /FSE_ARG_VNODE/ # CREATE FILE OR DIR
    rsync! if line[/path\s+=(.*)/, 1].strip =~ Regexp.new(DIRECTORY_PATTERN)
  elsif line =~ /FSE_ARG_STRING/ # REMOVE FILE OR DIR
    rsync! if line[/string\s+=(.*)/, 1].strip =~ Regexp.new(DIRECTORY_PATTERN)
  end
end