Rakeでgruntやgulpのようなファイル変更を監視してビルドしてMacで通知を出す
やりたいこと
- 特定のディレクトリ以下のファイルに変更があったときに、rakeが走るようにしたい
- rakeが走ったあとに、Macで通知を出したい
- 複数のファイルが一挙もしくは短い間に変更された際に、ファイル1個ごとでビルドが走らないようにしたい
- .git/index.lockとかが変更されたときに、ビルドが走らないようにしたい
- Rubyのfswatchをわざわざ入れなくても、コマンドのfswatchが入っていれば走るようにしたい
- ビルド中にまたファイルに変更があったら、ビルドを即中止して新しいビルドを走らせたい
既存のもの
gulpにもmakeにも不満なWebデベロッパーためのRake(コンパイル・パターンマッチ・ファイル監視・通知)というものがある。
- 複数のファイルが一挙もしくは短い間に変更された際に、ファイル1個ごとでビルドが走ってしまう
- .git/index.lockとかが変更されたときに、ビルドが走ってしまう
- ビルドを中止してくれない
- notify-sendがHomebrewにない
改造したヤツ
Rakefileこうなった。あんまりかっこよくない。パスとかの空白には弱そうだから適宜対処して欲しい。pid一周誤爆kill気にしないねー。
require 'mkmf' APP_NAME = 'Super Slow Build Project' IGNORE_REGEX = %r{/\.git/} WAIT_BUFFER_SECOND = 2.0 task :watch do |t| mac = (RbConfig::CONFIG['host_os'] =~ /\Adarwin[\d.]+\z/) unless mac puts 'Cannot use rake watch except MacOSX' exit(1) end unless find_executable('fswatch') `brew install fswatch` end IO.popen("fswatch TARGET_PATH1 TARGET_PATH2", 'r') {|io| buffer = [] pid = nil last_load = 0 loop { begin r = io.read_nonblock(1024) buffer << [r] last_load = Time.now.to_f rescue IO::WaitReadable if Time.now.to_f - last_load < WAIT_BUFFER_SECOND sleep 0.5 retry end lines, cr, rest = buffer.join('').rpartition("\n") buffer = [rest] build = lines.split("\n").any? {|line| IGNORE_REGEX.match(line).nil? } if build if pid Process.kill(9, pid) end pid = fork { sh %{rake} do |ok, res| if ok notify('Build succeed') else notify('Build ERROR') end end } end IO.select([io]) end } } end def notify(message) puts message `osascript -e 'display notification "#{message}" with title "#{APP_NAME}"'` end