めもぶろぐ

お勉強したこと、趣味なんかを適当に書いてます。。。

inotify, incron ではなくpyinotify!!

inotifyやincronはよく使用されると思うが標準パッケージに入ってなかったり。

探してみるとpyinotifyがある。パッケージ名からしてpython版のinotifyだ。

調べてみればやはり。


inotifyをそのまま使ってもいいが、pythonで、モージュールとしてインポートしてカスタマイズもできるのでおすすめ。
標準でも入っているし、なかなかいい。

とりあえずインストールパッケージ探し

# yum search pyinotify
読み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * epel: ftp.riken.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
=============================== 一致: pyinotify ================================
python-inotify.noarch : Monitor filesystem events with Python under Linux
python-inotify-examples.noarch : Examples for Python inotify module

見つかったら、それでインストール。サンプルもいれてみる。

yum -y install python-inotify*

サンプルを見てみる
cat /usr/share/pyinotify/autocompile.py

#!/usr/bin/env python
#
# Usage:
#   ./autocompile.py path ext1,ext2,extn cmd
#
# Blocks monitoring |path| and its subdirectories for modifications on
# files ending with suffix |extk|. Run |cmd| each time a modification
# is detected. |cmd| is optional and defaults to 'make'.
#
# Example:
#   ./autocompile.py /my-latex-document-dir .tex,.bib "make pdf"
#
# Dependencies:
#   Linux, Python 2.6, Pyinotify
#
import subprocess
import sys
import pyinotify

class OnWriteHandler(pyinotify.ProcessEvent):
    def my_init(self, cwd, extension, cmd):
        self.cwd = cwd
        self.extensions = extension.split(',')
        self.cmd = cmd

    def _run_cmd(self):
        print '==> Modification detected'
        subprocess.call(self.cmd.split(' '), cwd=self.cwd)

    def process_IN_MODIFY(self, event):
        if all(not event.pathname.endswith(ext) for ext in self.extensions):
            return
        self._run_cmd()

def auto_compile(path, extension, cmd):
    wm = pyinotify.WatchManager()
    handler = OnWriteHandler(cwd=path, extension=extension, cmd=cmd)
    notifier = pyinotify.Notifier(wm, default_proc_fun=handler)
    wm.add_watch(path, pyinotify.ALL_EVENTS, rec=True, auto_add=True)
    print '==> Start monitoring %s (type c^c to exit)' % path
    notifier.loop()

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print >> sys.stderr, "Command line error: missing argument(s)."
        sys.exit(1)

    # Required arguments
    path = sys.argv[1]
    extension = sys.argv[2]

    # Optional argument
    cmd = 'make'
    if len(sys.argv) == 4:
        cmd = sys.argv[3]

    # Blocks monitoring
    auto_compile(path, extension, cmd)


使えそう。ちょうどコンパイルするinotifyのサンプルがあった
コンパイルはしなけれど、保存したら自動実行したい



なので、こんな形で作った。
vimで編集して、保存したら実行する感じ。

swpファイルは頻繁にできるので、無視。

import asyncore
import pyinotify
import subprocess

wm = pyinotify.WatchManager()  # Watch Manager
mask = pyinotify.IN_MODIFY  # watched events

class EventHandler(pyinotify.ProcessEvent):
    def process_IN_MODIFY(self, event):
      if "swp" in event.pathname or "~" in event.pathname:
        dummy = event.pathname
      else:
        try:
          rst = subprocess.check_output(['python', event.pathname, '>', 'tty'])
          print "\n"
          print "+-----------------+"
          print "| print result"
          print "+-----------------+"
          print rst
        except:
          print "failed to execute " + event.pathname

notifier = pyinotify.AsyncNotifier(wm, EventHandler())
wdd = wm.add_watch("/home/user/python", mask, rec=True)

asyncore.loop()

保存時にコマンドを実行するようにできたので、あとは保存時にShellCheckをしたり、ファイルオープン時にCREATEイベントでswpファイルができたらファイルをバックアップするなど、適当に作れるはず。

広告を非表示にする