Macでの開発効率をアップする、マウントせずにローカルのソースコードをサーバーと同期するスクリプト書いた。


しかだよ。
変更があったローカルのソースコードをサーバーのソースコードと同期しながらwebアプリを開発できるスクリプトを作りました。
shikajiro/eventsync.py

2012/07/10 追記

下で説明するソースコードは古いので、shikajiro/eventsync.pyの方を見てくださいね。

webアプリ開発の問題点

  • マウントしたりsshでサーバーに接続してwebアプリを開発してると、回線が遅くて画面が固まることがあり、ストレスフルなコーディングを強いられている。
  • ローカルのソースをgitでpushしてサーバーに反映するのは複数人の場合はいいけど、一人用の場合は毎回add commit push がめんどい。

プログラマーが楽しくプログラミングできないのはです。直ちに懺悔するか解決しましょう。

開発中のwebアプリを動かす場所を比較検討

実行場所 公開範囲 反応スピード PC負荷 柔軟性
ローカルのmac × ×
vmwareLinux × ×
レンタルサーバ ×
  • ローカルでwebアプリを動かすとレスポンスとか速いんだけど、複数環境などで柔軟性に欠ける。
  • vmwareだと柔軟性高いんだけど、メモリとCPU消費が激しくて遅い。
  • 上記2つはさらにネットに公開されていないのでテストしにくい。
  • レンサバは公開されてて扱い易いけど、直接コーディングするにはレスポンスが遅い。

今この瞬間作っているものをストレス無くサーバーで確認したいのです!
というわけで、「サーバーに常時接続せず」「ローカルで開発できて」「ソースコードに変更があったらサーバーを更新する」方法を探りました。

ソースコードの同期はrsync

コードの同期はrsyncでできました。問題は「ソースコードの追加・変更・削除」をどうやって検知するかです。

lsync

Linuxディストリビューションならlsyncを使うとファイルの変更検知ができるみたいですが、Mac OS XBSDなので、これは使えませんでした。

フォルダアクション

Mac OS X にはフォルダアクションというフォルダ監視の仕組みがあります。フォルダに変更があるとautomatorを実行出来たりします。しかしこれは「フォルダへのファイルの追加」のみ検知可能だったため断念しました。

kevent kqueue

BSDLinuxとは別の方法でファイルを監視する事が可能でした。それが kevent kqueueです。
*BSD で kqueue・kevent を使ってみよう

pythonスクリプト

んで、色んなサイトのソースコードを参考にしてできました。
shikajiro/eventsync.py

import select
import os
import sys


def kevent(file):
    ke = select.kevent(file,
        filter=select.KQ_FILTER_VNODE,
        flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | select.KQ_EV_CLEAR,
        fflags=select.KQ_NOTE_DELETE | select.KQ_NOTE_WRITE
    )
    return ke

argvs = sys.argv
argc = len(argvs)
if(argc != 3):
    print 'Usage: python {} filename.'.format(argvs[0])
    quit()
folder = argvs[1]
ssh = argvs[2]
print '{} to {}'.format(folder, ssh)
print 'file update watching...'

dirs = os.walk(folder)
l = []
for root, dirs, files in dirs:
    f = os.open(root, os.O_RDONLY)
    l.append(kevent(f))
    for a in files:
        f = os.open(root + '/' + a, os.O_RDONLY)
        l.append(kevent(f))

kq = select.kqueue()
events = kq.control(l, 0, None)
while True:
    r_events = kq.control(l, 1, None)
    for event in r_events:
        print event
        if event.fflags & select.KQ_NOTE_DELETE or event.fflags & select.KQ_NOTE_WRITE:
            print "file was updated!"
            command = 'rsync -av --delete -e ssh {} {}'.format(os.path.join(os.getcwd(), folder), ssh)
            print command
            os.system(command)

python eventsync.py watchdir/ shikajiro@hostname:/dir/
第一引数に監視するディレクトリ名、第二引数に同期するsshサーバーとそのフォルダを指定します。

起動するとこんな感じ。

hogehoge/ to root@www.kojika-ya.me:/root/hogehoge/
file update watching...

ファイルに変更などがあると

building file list ... done
deleting urls.pyc
deleting settings.pyc
deleting middleware.pyc
deleting __init__.pyc
deleting api/urls.pyc
deleting api/handlers.pyc
deleting api/__init__.pyc
deleting app/models.pyc
deleting app/admin.pyc
deleting app/__init__.pyc
./
sqlite
test
api/
app/

sent 7501 bytes received 1876 bytes 6251.33 bytes/sec
total size is 3252109 speedup is 346.82
.....

こんな感じでどんどん同期されていきます。

これできっとストレスフリーな開発ができる(はず)です。