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
 
    