Mac OS X FSEvent + RubyCococa で簡単ディレクトリ監視。

CouchApp は普通のファイルシステム上でアプリケーション開発をして、couchapp push コマンドをたたいてデータベース上にアプリケーションをコミットします。

しかしこれ、開発中の時、頻繁にコンソールとエディタを行ったり来たりするので面倒なのです。C-x C-s (保存) したら勝手にpushしてほしい。

ということで、ファイルの変更を検知して自動的にcouchapp push をかましましょう、という話。OSX 前提です。

  • OS X の FSEvent API を使うと、ディレクトリ単位でファイルの変更を検知できる。
  • Ruby Cocoa を使えばFSEvent APIのラッパーがあるので、意外と簡単に実装できる。

というわけで書いてみた。といっても、RubyCocoa 初めて使って、Example からコピペしただけ。。。
couchapp のディレクトリに .couchapprc をおいた状態で、以下のスクリプトを起動しておけばOKです。

require 'pathname'
require 'osx/foundation'
OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
include OSX

appdirs = [couchappdir1, couchappdir2, ...]

file_updated = lambda {  |stream, ctx, numEvents, paths, marks, eventIDs|
  paths.regard_as('*')
  numEvents.times do |n|
    dir = paths[n]
    appdirs.each do |appdir|
      if dir =~ /^#{appdir}/
         system("cd #{appdir}; couchapp push")
      end
    end
  end
}

stream = FSEventStreamCreate(
                             KCFAllocatorDefault,
                             file_updated,
                             nil,
                             appdirs,
                             KFSEventStreamEventIdSinceNow,
                             1.0,
                             0)
raise "Failed to create the FSEventStream" unless stream


FSEventStreamScheduleWithRunLoop(
  stream,
  CFRunLoopGetCurrent(),
  KCFRunLoopDefaultMode)

ok = FSEventStreamStart(stream)
raise "Failed to start the FSEventStream" unless ok

begin
  CFRunLoopRun()
rescue Interrupt
  FSEventStreamStop(stream)
  FSEventStreamInvalidate(stream)
  FSEventStreamRelease(stream)
end

couchapp 意外にも使えると思うのですが、ひとまず。

CouchDB ML のほうには FSEvents を使う http://github.com/ymendel/fsevents/tree/master の情報もあったのですが、せっかくなのでOS X標準だけでできるRubyCocoaで。