ファイル監視のwatchman

Tags : ユーティリティー   Linux   Laravel4  

ファイル監視を説明するために困るのは、OSにより方法が異なることでした。

Windows上で本格開発というのは、無理とは言いませんが、シェアが少ないでしょう。ほとんどはMacで、一部はLinux、もうちょっと少なければUnixというところでしょう。(MacはUNIXですね。)

そのため、MacとUnix間で共通に使えるものがないか、探していましたが、今年になってFacebookがwatchmanというツールをリリースしました。

誰かが情報を出してくれるのを待っていましたが、なかなか出ません。そこで使ってみました。

インストール

c言語で開発されています。Linuxの場合、inotifyツールが必要です。(通常、パッケージのリポにあるでしょう。openSUSEならパッケージ検索から探せば、openSUSEリポのFilesystemsかEducationにinotify-toolsが見つかり、ワンクリックインストール可能です。)Macでは特別なパッケージは必要ないようです。

cのコンパイラとmakeなどの、基本開発ツールは必要です。事前に用意してください。

https://github.com/facebook/watchmanのページのリポジトリーからクローンしてください。

git clone https://github.com/facebook/watchman.git watchman

後は、watchmanディレクトリーへ移動し、Readmeに書かれている通り、以下の3コマンドを叩けば、簡単に作成されます。

./autogen.sh
./configure
make

watchmanという実行ファイルができていますので、実行パスが通っている場所へコピーしてください。

使用法

これがよく分かりません。:D

英語の解説を探しましたが、見つかりませんでした。いまだ、マイナーな存在のようです。

分かったのは、監視対象と実行するコマンドを指定する方法です。

watchman -- trigger 監視対象パス 監視対象名 監視対象 -- コマンド

具体例は:

watchman -- trigger ~/src buildme '*.css' -- minify-css

triggerはサブコマンド名です。

監視対象パスは絶対パスか、~/でホーム以下を指定する必要があるようです。指定したディレクトリー下を再帰的に監視します。

監視対象名は文字列です。単なる名前です。

監視対象はファイル種を指定します。シングルコーティーションでくくるのを忘れずに。全ファイル対象であれば'*'ですね。

コマンドはコマンドです。監視対象のファイル名が途中に来るようなコマンドでどう指定すれば良いのか不明です。(シェルが書ければ回避可能ですね。)

watchmanコマンドは、最初に実行するとサーバーとして動作します。つまり、制御が戻ってきます。

Laravelのstorageファイル監視に使用する

/home/myuser/project1/にLaravelのプロジェクトが存在する場合、storageファイルを監視するには、ルート権限で以下のように行います。

watchman -- trigger /home/myuser/project1/app/storage '*' -- chmod 777

個人の開発環境であれば、777パーミッションでも許されることはあるでしょうが、もうちょっと真面目に行うなら、ファイルグループの設定の記事を参照に、グループとパーミッションを設定しましょう。その場合、複数コマンドを実行する必要が起きます。

複数コマンドを実行する場合は、一度シェルを作成します。例えばファイルのグループをwww-groupにし、パーミッションを664に変更する場合、次のようになります。

#!/bin/bash

#
# ファイルの所有グループ変更とパーミッション変更
#
# wwwaccess ファイル名
#


if [ ! -f $1 ]
then
    echo ファイルが存在しません 1>&2
    exit 1
fi

chgrp www-group $1
chmod 664 $1

このシェルを/home/myuser/bin/www664として作成し、実行パーミッションを付けておき、これをwatchmanで登録します。

後は先ほどと同様に、ルートユーザーの権限で、登録します。

watchman -- trigger /home/myuser/project1/app/storage '*' -- /home/myuser/bin/www664

留意点

ファイル監視にしては、今のところLinuxで実行すると、多少CPUを食い過ぎるようです。Linux使用者であれば、inotify-toolsを使用して、シェルを組んだほうが、CPUの消費は抑えられます。特に、watchmanからシェルを実行すると更に増えるようです。

inotifyを直接使用する場合は、以下のシェルをご利用ください。引数に監視対象ディレクトリーのフルパスを指定し、ルートの権限で実行します。今回は/home/myuser/bin/watch-storageというスクリプト名にしたとしましょう。

#!/bin/bash

#
# Laravel storage下ファイル監視設定
#
# 使用法:
# watch-storage 対象ディレクトリー
#

if [ $# -ne 1 ]
then
  echo 監視対象ディレクトリーを指定してください。 1>&2
  exit 1
fi

if [ ! -d $1 ]
then
  echo 監視対象ディレクトリーが存在しません 1>&2
  exit 1
fi

while :
do
  # 生成と対象ディレクトリー内への移動を監視
  result=$(inotifywait -rq -e moved_to,create $1)

  # 監視対象ディレクトリー内でのサブディレクトリー削除で
  # 発生する空イベントを無視する。
  if [ -z "${result}" ]
  then
    continue
  fi

  # イベントの発生源がディレクトリーによるものであれば、何もしない
  is_dir=$(echo $result | grep 'ISDIR')

  if [ $? -ne 0 ]
  then
    dirname=$(echo $result | cut -f1 -d ' ')
    filename=$(echo $result | cut -f3 -d ' ')

    # グループのセットビットを指定してある場合、
    # chgrpでグループ変更する必要はありません。
    chgrp www-group ${dirname}${filename}

    chmod 664 ${dirname}${filename}
  fi
done

例えば、ルートの権限でこのシェルを走らせるには、/etc/rc.d/boot.localに追加します。

/home/myuser/bin/watch-storage /home/myuser/project1/app/storage >& /dev/null &

大した手間でもありませんので、毎回接続ごとにコマンドを叩くこともできます。

sudo /home/myuser.....

但し、複数回実行されないように気をつけてください。.bashrcや.bash_profileなどに登録してしまうと、複数回起動する可能性があります。バックグランドで実行したコマンドは、監視を続けているので、意図的にkillしない限り、ずっと続いています。