Loading...

2023-11-20(月) 15:00

🗂️ Watchmanでディレクトリの監視と指定条件下でのスクリプト実行を自動化する

UbuntuShell
Meta社(旧Facebook社)がオープンソースで開発しているWatchmanを使って特定のディレクトリを監視して、条件が満たされた時にスクリプトを実行できるようにします。

目次

前提と注意事項

以下が前提と注意事項になります。

  • Ubuntu 22.04
  • Ubuntu が動作する端末の CPU は x64

この記事のゴール

特定のディレクトリを監視して、条件が満たされた時にスクリプトを自動実行します。 例えば、ディレクトリ A に動画ファイル(拡張子が.mp4であるファイルとします。)が新規追加や更新、削除されたら、その動画ファイルをディレクトリ B に自動でコピーするようにします。
これだけだと Watchman を使うメリットは少ないように感じますが、Watchman を使って特定のディレクトリを監視、条件が満たされた時にスクリプトを実行するということができるようになると、様々なことが自動化できるようになります。

Watchman について

Watchman は Meta 社(旧 Facebook 社)がオープンソースで開発しています。以下が公式サイトとリポジトリです。
Watchman は Windows、macOS、Linux に対応しています。

Watchman - A file watching service -

Watches files and records, or triggers actions, when they change.

facebook.github.io

facebook / watchman

Watchman exists to watch files and record when they actually change. It can also trigger actions (such as rebuilding assets) when matching files change.

github.com

Watchman をインストールする

公式ドキュメントに従って Watchman をインストールします。 この記事では Ubuntu へのインストールを行いますが、公式ドキュメントには Windows、macOS へのインストール方法も記載されています。

まずはじめに、Ubuntu 用にビルド済みの.debパッケージの最新版を公式リポジトリのリリースページからダウンロードします。 以下のように公式リポジトリのリリースページの中で、今回インストールを行う Ubuntu 用の.debパッケージを確認します。

watchmanリリースページ

リリースページのリンクをクリックしてダウンロードするか、以下のようにwgetコマンドでダウンロードしても OK です。

ターミナル
$ wget https://github.com/facebook/watchman/releases/download/v2023.10.09.00/watchman_ubuntu22.04_v2023.10.09.00.deb

なお、リリースページの中にある一番新しいバージョンだと Ubuntu 用のパッケージや Windows 用のパッケージがまだ用されていない場合があります。 どうしても最新版を使いたい場合は、ソースからビルドすることもできます。ビルド方法も公式ドキュメントに記載されています。 記事公開時点では、Ubuntu 用にビルド済みのdebパッケージの最新版はv2023.10.09でした。

ダウンロードした.debファイルを以下のようにdpkgコマンドを使ってインストールします。

ターミナル
$ sudo dpkg -i watchman_ubuntu22.04_v2023.10.09.00.deb

上記を実行すると以下のようにエラーが表示されますが、エラーが出ること自体も公式ドキュメントに記載されているのでそのまま進みます。

ターミナル
$ sudo dpkg -i watchman_ubuntu22.04_v2023.10.09.00.deb
[sudo] hisui のパスワード:
以前に未選択のパッケージ watchman を選択しています。
(データベースを読み込んでいます ... 現在 225056 個のファイルとディレクトリがインストールされています。)
watchman_ubuntu22.04_v2023.10.09.00.deb を展開する準備をしています ...
watchman (20231008.002904.0) を展開しています...
dpkg: 依存関係の問題により watchman の設定ができません:
 watchman は以下に依存 (depends) します: libgoogle-glog0v5 ...しかし:
  パッケージ libgoogle-glog0v5 はまだインストールされていません。
 watchman は以下に依存 (depends) します: libboost-context1.74.0 ...しかし:
  パッケージ libboost-context1.74.0 はまだインストールされていません。
 watchman は以下に依存 (depends) します: libevent-2.1-7 ...しかし:
  パッケージ libevent-2.1-7 はまだインストールされていません。
 
dpkg: パッケージ watchman の処理中にエラーが発生しました (--install):
 依存関係の問題 - 設定を見送ります
処理中にエラーが発生しました:
 watchman

上記のエラーを解決するために以下を実行します。

ターミナル
$ sudo apt-get -f install

上記で依存関係のインストールが完了したら Watchman のインストールも完了です。 試しに以下でバージョンを表示してみてください。

ターミナル
$ watchman version
version: 20231008.002904.0
buildinfo: 5ebaad98ba4ac71edc1c904b30e7ca6bae4703b3

上記のようにバージョン情報が表示されれば正常にインストールが完了しています。 なお、もしcargoコマンドが使える場合は、Ubuntu 用にビルドされたものではなく最新のものをソースからビルドしてももちろん OK です。

watchman を使ってディレクトリを監視する

以下を実行することで指定したディレクトリを監視することができます。

ターミナル
$ watchman watch testa
{
    "version": "20231008.002904.0",
    "watcher": "inotify",
    "watch": "/home/hisui/workspace/watchman-script/testa"
}

上記はディレクトリ/home/hisui/workspace/watchman-script/testaを監視すること意味します。
監視状態にしただけでは何も起きませんが、監視状態のディレクトリに対して処理を実行する条件と実行するコマンド(以降、これらをトリガと呼びます。)を設定します。設定方法を後述します。

監視中のディレクトリ一覧を確認する

watch-listを使うことで監視対象としているディレクトリ一覧を確認できます。 なお、監視しているだけで何もトリガを登録していない場合でも表示されます。

ターミナル
$ watchman watch-list
{
    "version": "20231008.002904.0",
    "roots": [
        "/home/hisui/workspace/watchman-script/testa"
    ]
}

特定のディレクトリの 監視状態を確認する

watch-project ディレクトリパスを使うことで特定のディレクトリの監視有無を確認できます。

ターミナル
$ watchman watch-project ./testa/
{
    "version": "20231008.002904.0",
    "watcher": "inotify",
    "watch": "/home/hisui/workspace/watchman-script/testa"
}

トリガを設定する

監視対象のディレクトリに対して、トリガを設定して条件と処理内容を指定します。
トリガを設定のためのコマンドは、以下の構文になっています。

ターミナル
$ watchman -- trigger [監視するディレクトリパス] [任意のトリガ名] [トリガ条件] -- [実行するコマンド]

具体例は以下になります。

ターミナル
$ watchman -- trigger /home/hisui/workspace/watchman-script/testa cpmp4 '*.mp4' -- 'sh /home/hisui/workspace/watchman-script/cp_script.sh'

以下が実行結果です。

ターミナル
$ watchman -- trigger /home/hisui/workspace/watchman-script/testa cpmp4 '*.mp4' -- 'sh /home/hisui/workspace/watchman-script/cp_script.sh'
{
    "version": "20231008.002904.0",
    "triggerid": "cpmp4",
    "disposition": "created"
}

上記は、以下の内容を指定しています。

  • /home/hisui/workspace/watchman-script/testaを監視する
  • トリガ名はcpmp4とする
  • ディレクトリtestaにファイルの拡張子が.mp4であるファイルが作成、更新、削除されたことを条件とする
  • 条件が満たされた時にsh /home/hisui/workspace/watchman-script/cp_script.shを実行する

ここのcp_script.shは、以下のような内容にしており、testaディレクトリにある.mp4ファイルをtestbディレクトリにコピーするようにしています。

cp_script.sh
#!/bin/bash
# testaの.mp4ファイルをtestbにコピーする
cp /home/hisui/workspace/watchman-script/testa/*.mp4 /home/hisui/workspace/watchman-script/testb/

上記はただただファイルをコピーするだけですが、シェルスクリプトを実行できるため、シェルスクリプトでできることならば何でもできます。 ただし、上記だとファイルの作成だけでなく、ファイルの更新と削除もトリガとなり、その度に指定したスクリプトが実行されます。

動作確認

前節で設定したトリガが正しく動作するか確認します。 ディレクトリtestaに適当な.mp4ファイルを作成します。

ターミナル
$ touch ./testa/test.mp4

すると、testbディレクトリに.mp4ファイルがコピーされます。

ターミナル
$ ls ./testb
test.mp4

このように、testaディレクトリに.mp4ファイルが新規作成されたら、testbディレクトリに.mp4ファイルをコピーするように設定できました。

トリガ一覧を確認する

以下で設定したトリガ一覧を確認できます。
trigger-listの後には、トリガを設定したディレクトリのパスを指定する必要があります。

ターミナル
$ watchman trigger-list testa
{
    "version": "20231008.002904.0",
    "triggers": [
        {
            "append_files": true,
            "stdin": [
                "name",
                "exists",
                "new",
                "size",
                "mode"
            ],
            "expression": [
                "anyof",
                [
                    "match",
                    "*.mp4",
                    "wholename"
                ]
            ],
            "name": "cpmp4",
            "command": [
                "sh",
                "/home/hisui/workspace/watchman-script/cp_script.sh"
            ]
        }
    ]
}

もしどのディレクトリにトリガを設定したか忘れてしまった場合は、すでに解説したwatch-listコマンドを使うことで監視対象としたディレクトリのパスを確認できます。

ちなみに、トリガ未設定のディレクトリに対してtrigger-listコマンドを実行すると以下のようにエラーが表示されます。

ターミナル
$ watchman trigger-list testb
{
    "version": "20231008.002904.0",
    "error": "watchman::RootResolveError: failed to resolve root: unable to resolve root /home/hisui/workspace/watchman-script/testb: failed to resolve root: directory /home/hisui/workspace/watchman-script/testb is not watched"
}

トリガを削除する

設定したトリガを削除するには、trigger-delコマンドを使います。

ターミナル
$ watchman trigger-del [ディレクトリのパス] [トリガー名]

トリガー名については、すでに解説したtrigger-listコマンドで確認できます。

まとめ

Watchman を使うことで、指定したディレクトリを監視して、条件が満たされた時にスクリプトを実行できます。スクリプトを色々と工夫すればかなり柔軟に色々なことができます。インストールも簡単なので、何かディレクトリの監視と操作を自動化したいという場合はぜひ使ってみてください。