真性PHPerでも分かった?FabricでWindowsからファイルアップロード
Windows7 (MinGW / MSYS) で Fabric の続きです。
- Windows7 (MinGW / MSYS) に Python 2.7 + virtualenv + Fabric を入れたメモ
- Windows7 (MinGW / MSYS) に virtualenvwrapper を入れたメモ
- Fabricで接続情報を指定する方法いろいろ&FabricからPHPスクリプトを実行してみたメモ
ファイルは作業ディレクトリに上げてからサーバ上でPHPスクリプトを実行すれば思いのままに…!とか考えてましたが、色々やるうちにまどろっこしく感じてしまい、結局Python/Fabricで何とかすることにしました。
同じことで迷わないためのメモです。環境は Windows7 / MSYS 1.0 / Python 2.7 / Fabric 1.6 です。
ローカルにカレントディレクトリ以下のhogeディレクトリがあればサーバ上にも作成し、ディレクトリ内の拡張子phpのファイルをアップロードして所有者apacheで実行できるように
なんだかえらく状況を限定してますが、そういうことをしたかったのです。
ローカルでのファイル/ディレクトリのパス操作には os.path モジュールが利用できます。
Fabricでサーバのファイル/ディレクトリ操作には fabric.contrib.files モジュールが利用できます。
fabfile.py
from fabric.api import env, run, local, put from fabric.contrib.files import exists import os, glob env.hosts = ['192.168.4.130'] env.port = 22 env.user = 'k_horii' env.key_filename = '~/.ssh/id_rsa' env.password = 'hoge' def test_copy_dir_files(): local_dir = '%s\\hoge' % (os.path.dirname(__file__)) server_dir = '~/hoge' if os.path.exists(local_dir): if not exists(server_dir): run('mkdir -p %s' % (server_dir)) put('%s\\*.php' % (local_dir), server_dir, use_sudo=True, mode=0755) run('sudo chown -R apache: %s' % (server_dir))
上記の変数 local_path ですが、Windowsなので os.path に使えるディレクトリの区切り文字は '\' になるため、あのような記述にしています。詳しくは後ほど。
Fabricの put() などでは適宜読み替えてくれるようですが、os.path ではそうはいきませんでした。~/hoge も解釈してくれません。
put() してから chown していますが、ローカルでも所有者や権限が適切に設定されていれば put(local_path, remote_path, mirror_local_mode=True) でいいかもしれません。
chown を sudo('chown') ではなく run('sudo chown') でやってるのは、sudo() だと ~/hoge が /root/hoge になってしまうためです。
put() のオプション引数に use_sudo と mode があるのは便利ですが user とか owner のようなオプションが、更に贅沢を言えばディレクトリがなければ再帰的に作ってくれるオプションがあれば非常に便利なのですが…。
なお、ディレクトリ内ファイルの取得は当初は glob モジュールを使ってみましたが、マニュアルをよく読めば put() でワイルドカードと設置先のディレクトリを指定できました。
参考 Operations — Fabric 1.6 documentation
実行結果はこうなります。
(oppy)[k_horii@horii ~]$ fab test_copy_dir_files
[192.168.4.130] Executing task 'test_copy_dir_files'
[192.168.4.130] run: mkdir -p ~/hoge
[192.168.4.130] put: c:\Users\k_horii\hoge\a.php -> /home/k_horii/hoge/a.php
[192.168.4.130] put: c:\Users\k_horii\hoge\b.php -> /home/k_horii/hoge/b.php
[192.168.4.130] put: c:\Users\k_horii\hoge\c.php -> /home/k_horii/hoge/c.php
[192.168.4.130] run: sudo chown -R apache: ~/hoge
Done.
Disconnecting from 192.168.4.130... done.
サーバ側で確認
[k_horii@cent6h01 ~]$ ls -lap ~/hoge
total 20
drwxrwxr-x. 2 apache apache 4096 Apr 11 18:11 ./
drwx------. 7 k_horii k_horii 4096 Apr 11 18:11 ../
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:11 a.php
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:11 b.php
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:11 c.php
ちゃんと所有者と権限が設定されています。
真性PHPerでも分かる os.path
os.path モジュールとPHP関数の比較をしてみます。
PHP : __FILE__
Python: __file__
PHP : dirname()
Python: os.path.dirname()
PHP : basename()
Python: os.path.basename()
PHP : file_exists()
Python: os.path.exists()
PHP : realpath()
Python: os.path.realpath()
PHP : is_dir()
Python: os.path.isdir()
PHP : is_file()
Python: os.path.isfile()
PHP : filemtime()
Python: os.path.getmtime()
PHP : filesize()
Python: os.path.getsize()
なんだか大丈夫そうな気がしてきませんか?
他にもPHPにはない os.path.normpath() や os.path.relpath() なんかもあります。
とりあえず、ローカルで事前に用意したファイルがあるかチェックしてサーバに設置するだけなら、この os.path モジュールを使って何とかできたということで。
Windowsのパス問題
前述の「os.path に使えるディレクトリの区切り文字は '\'」の問題について。
MSYSやFabricは ~/hoge といったローカルのパスを解釈してくれますが、os.path はそうはいきません。
たとえばMSYS環境でFabricを実行する場合はk_horiiのホームで fabric.api.local() を使って current_dir = local('pwd', capture=True) とすれば /c/Users/k_horii が返ります。
しかし、それを os.path.normpath() で変換すると \c\Users\k_horii に、os.path.realpath() で変換すると c:\c\Users\k_horii になり、結局いずれも os.path で扱えない無効なものになってしまいます。
ただ、ローカルでのファイル/ディレクトリの存在チェックやカレントディレクトリの参照が必要なければ、普通に fabric.api.put() だけで問題ないと思います。
それに、ファイルの設置先が接続中ユーザのホームディレクトリではなく固定のディレクトリであれば、もっと自然な形で書けそうです。
試しに書き換えてみました。
fabfile.py
from fabric.api import env, run, local, put from fabric.contrib.files import exists env.hosts = ['192.168.4.130'] env.port = 22 env.user = 'k_horii' env.key_filename = '~/.ssh/id_rsa' env.password = 'hoge' def test_copy_dir_files(): server_dir = '/tmp/hoge' if not exists(server_dir): run('mkdir -p %s' % (server_dir)) put('~/hoge/*.php', server_dir, use_sudo=True, mode=0755) sudo('chown -R apache: %s' % (server_dir))
実行結果はこうなります。
(oppy)[k_horii@horii ~]$ fab test_copy_dir_files
[192.168.4.130] Executing task 'test_copy_dir_files'
[192.168.4.130] put: c:/Users/k_horii/hoge\a.php -> /tmp/hoge/a.php
[192.168.4.130] put: c:/Users/k_horii/hoge\b.php -> /tmp/hoge/b.php
[192.168.4.130] put: c:/Users/k_horii/hoge\c.php -> /tmp/hoge/c.php
[192.168.4.130] sudo: chown -R apache: /tmp/hoge
Done.
Disconnecting from 192.168.4.130... done.
put() のローカル側のパスがおかしなことになってますが、エラーにはなりませんでした。
PHPでもWindowsのディレクトリセパレータ対策は施されていますが、Fabricでも同様のようです。これは嬉しい。
サーバ側で確認
[k_horii@cent6h01 ~]$ ls -lap /tmp/hoge
total 20
drwxrwxr-x. 2 apache apache 4096 Apr 11 18:42 ./
drwxrwxrwt. 9 root root 4096 Apr 11 18:42 ../
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:42 a.php
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:42 b.php
-rwxr-xr-x. 1 apache apache 6 Apr 11 18:42 c.php
ちゃんとファイルが設置され、所有者と権限も設定されました。結局、PHPer的なos.pathの説明は意味なかった…?
Fabricの機能もまだきちんと把握できていないので、もっと楽な方法があるかもしれません。引き続き勉強します…。