2021/APR/02
更新履歴
日付
変更内容 2020/AUG
新規作成 2020/APR/02
Version 26
ちょいちょいこのサイト kon page を更新しております。
昔ながらのftpコマンドの対話モードでファイルをアップロードしたり削除したり。
ダウンロード方向は wget コマンドで良いのですが、 アップロード方向の手間が面倒です。
瞬間芸でちょっとだけ自動化してみました。
音楽ファイルの分割 2020冬 に続き、 このツールも pythonのユーティリティ・プログラム 2020冬 の使用が前提です。
kon_pageのpythonモジュールのインストール の手順でどこかに置いて、kon_page.pth でパスを通しておきましょう。;-p)
既にこれで完成してる感もありますが...
機能は基本的にファイルのアップロードと削除。
ftpサイトにログインして、引数で指定したパスのファイルをアップロードしたり、 削除したりします。
あとディレクトリの作成と削除を入れてみましたが、 ちょっと使い勝手が悪いかもです。
ファイルのパスはカレントディレクトリからの相対ディレクトリ指定します。
ftpサイトにログインしたときのサイトのディレクトリが、 カレントディレクトリと対応します。
$ ./ftp_ut.py Usage: ./ftp_ut.py -h host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path ..
サイトにログインしたときに foo/ というサブディレクトリがあるとします。
例えばカレントディレクトリ相対で
index.html foo/bar.html
のindex.html, bar.htmlの2つのファイルをアップロードする場合は
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx index.html foo/bar.html open ftp.hoge.fuga.jp user kondoh ---- bin prompt put index.html cd foo lcd foo put bar.html cd .. lcd .. quit # しばらく待機 $
実行するコマンドを表示してから、実行して終了します。
上記の2ファイルを削除する場合は
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx del index.html foo/bar.html open ftp.hoge.fuga.jp user kondoh ---- bin prompt del index.html cd foo del bar.html cd .. quit # しばらく待機 $
サブディレクトリへのファイルのアップロードは、「ディレクトリが有る事」が前提です。
なので、ディレクトリが無い場合は、作ってからアップロードします。
サイト側のディレクトリの有無まで自動で判定をさせようとすると、 ちょっと難しくなるので、手動に頼ります。
例えばサイト側に
foo bar hoge fuga kon
つまり
foo/bar/hoge foo/bar/fuga foo/kon
を作りたい場合
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx mkdir foo/bar/hoge foo/bar/fuga foo/kon open ftp.hoge.fuga.jp user kondoh ---- bin prompt mkdir foo mkdir foo/bar mkdir foo/bar/hoge mkdir foo mkdir foo/bar mkdir foo/bar/fuga mkdir foo mkdir foo/kon quit # しばらく待機 $
2回目の "mkdir foo" では既に存在するのでエラーになりますが ...
まぁ後続の処理は続行されるでしょう。
そこを考慮して避けようとすると、複雑になるのでサボってます。
引数の指定方法は作成と同じですが、動作が違うのでご注意を。
例えばサイト側のディレクトリ
foo bar hoge fuga kon
つまり
foo/bar/hoge foo/bar/fuga foo/bar foo/kon foo
を削除したい場合。
深い空のディレクトリから順に削除していく必要があります。
ディレクトリにファイルが残ってると削除に失敗するので、 ファイルは既に無くなっている事が前提です。
1つのパスの指定につき、一番深いディレクトリが1つ削除されるだけです。
まず
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx rmdir foo/bar/hoge open ftp.hoge.fuga.jp user kondoh ---- bin prompt rmdir foo/bar/hoge quit
この実行では foo/bar にあるhoge が1つ削除されるだけです。
なのでfoo以下を全て手動で指定する必要があります。
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx rmdir \ foo/bar/hoge \ foo/bar/fuga \ foo/bar \ foo/kon \ foo \ open ftp.hoge.fuga.jp user kondoh ---- bin prompt rmdir foo/bar/hoge rmdir foo/bar/fuga rmdir foo/bar rmdir foo/kon rmdir foo quit # しばらく待機 $
プログラムで手抜きした分、指定方法を良く考える必要があります。;-p)
サイトのディレクトリのファイル一覧を表示する機能を追加してみました。
$ cat v2.patch | patch -p1
$ ./ftp_ut.py Usage: ./ftp_ut.py -h -v host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path ..
ls と lst を追加しました。
ls は FTP の表示のままです。
例えば、まずローカル側にファイルを用意。
$ mkdir -p hoge/fuga $ echo foo > hoge/fuga/foo.txt $ echo bar > hoge/fuga/bar.txt $ mkdir -p hoge/kon $ echo hello > hoge/kon/hello.txt $ find hoge hoge hoge/fuga hoge/fuga/bar.txt hoge/fuga/foo.txt hoge/kon hoge/kon/hello.txt
サイトにディレクトリを作って...
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx mkdir hoge/fuga hoge/kon open ftp.hoge.fuga.jp user kondoh ---- bin prompt mkdir hoge mkdir hoge/fuga mkdir hoge mkdir hoge/kon quit
サイトにファイルをアップロードします。
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx hoge/fuga/foo.txt hoge/fuga/bar.txt hoge/kon/hello.txt open ftp.hoge.fuga.jp user kondoh ---- bin prompt cd hoge/fuga lcd hoge/fuga put foo.txt cd ../.. lcd ../.. cd hoge/fuga lcd hoge/fuga put bar.txt cd ../.. lcd ../.. cd hoge/kon lcd hoge/kon put hello.txt cd ../.. lcd ../.. quit
ls を実行してみます。
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx ls hoge drwx---r-x 4 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:10 . drwxr-xr-x 30 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:10 .. drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:14 fuga drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:14 kon $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx ls hoge hoge/fuga drwx---r-x 4 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:10 . drwxr-xr-x 30 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:10 .. drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:14 fuga drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:14 kon drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:14 . drwx---r-x 4 kondoh.html.xdomain.jp 1000 4096 Feb 9 11:10 .. -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 9 11:14 bar.txt -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 9 11:14 foo.txt
lsやlstのときは、実行するコマンド群の表示はしません。
複数のパス指定すると、繋がって表示されて、ちょっとややこしいです。
lstコマンドは名前だけの表示です。
複数のパス指定すると、繋がって表示されるので、1つだけのパスを指定するのが無難です。;-p)
$ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx lst hoge fuga kon $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx lst hoge/fuga bar.txt foo.txt $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx lst hoge/kon hello.txt $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx lst hoge/fuga hoge/kon bar.txt foo.txt hello.txt
もうちょっと対話的に動作させたく。
整理して修正してみると、全く別物になるレベルで書き換わってしまいました。
なるべくこれまでの使い勝手は変わらない感じにしてます。
$ cat v3.patch | patch -p1
$ ./ftp_ut.py Usage: ./ftp_ut.py [-h] [-dbg] host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. $ touch foo.txt $ mkdir foo $ echo bar > foo/bar.txt $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx mkdir foo login mkdir foo $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx foo.txt foo/bar.txt login put foo.txt cd foo lcd foo put bar.txt cd .. lcd .. $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx ls foo.txt foo 229 Entering Extended Passive Mode (|||60040|) 150 Opening ASCII mode data connection for file list -rw----r-- 1 kondoh.html.xdomain.jp 1000 0 Feb 10 23:38 foo.txt 226 Transfer complete 229 Entering Extended Passive Mode (|||60042|) 150 Opening ASCII mode data connection for file list drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 10 23:38 . drwxr-xr-x 31 kondoh.html.xdomain.jp 1000 4096 Feb 10 23:38 .. -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 10 23:38 bar.txt 226 Transfer complete $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx lst foo.txt foo foo.txt bar.txt $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx del foo.txt foo/bar.txt login del foo.txt cd foo del bar.txt cd .. $ ./ftp_ut.py ftp.hoge.fuga.jp kondoh xxxx rmdir foo login rmdir foo
ごっそり書き換えたので、バグが残ってるかも知れません。
-debug でデバッグ様の詳細表示モードです。
同じ事をしてみると
$ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx mkdir foo open ftp.hoge.fuga.jp user kondoh ---- # !!! -debug モードでは、ここが丸見えなのでご注意 !!! bin prompt verbose Interactive mode off. Verbose mode on. login mkdir foo 257 "/foo" - Directory successfully created mkdir foo $ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx foo.txt foo/bar.txt open ftp.hoge.fuga.jp user kondoh ---- # !!! -debug モードでは、ここが丸見えなのでご注意 !!! bin prompt verbose Interactive mode off. Verbose mode on. login put foo.txt local: foo.txt remote: foo.txt 229 Entering Extended Passive Mode (|||60004|) 150 Opening BINARY mode data connection for foo.txt 226 Transfer complete cd foo 250 CWD command successful lcd foo Local directory now: /Users/kondoh/kon_page/ftp_ut/foo put bar.txt local: bar.txt remote: bar.txt 229 Entering Extended Passive Mode (|||60087|) 150 Opening BINARY mode data connection for bar.txt 226 Transfer complete 4 bytes sent in 00:00 (0.25 KiB/s) cd .. 250 CWD command successful lcd .. Local directory now: /Users/kondoh/kon_page/ftp_ut put foo.txt cd foo lcd foo put bar.txt cd .. lcd .. $ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx ls foo.txt foo : 略 : $ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx lst foo.txt foo open ftp.hoge.fuga.jp user kondoh ---- # !!! -debug モードでは、ここが丸見えなのでご注意 !!! bin prompt verbose Interactive mode off. Verbose mode on. ls foo.txt 229 Entering Extended Passive Mode (|||60019|) 150 Opening ASCII mode data connection for file list -rw----r-- 1 kondoh.html.xdomain.jp 1000 0 Feb 11 00:15 foo.txt 226 Transfer complete ls foo 229 Entering Extended Passive Mode (|||60026|) 150 Opening ASCII mode data connection for file list drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 11 00:15 . drwxr-xr-x 31 kondoh.html.xdomain.jp 1000 4096 Feb 11 00:15 .. -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 11 00:15 bar.txt 226 Transfer complete foo.txt bar.txt $ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx del foo.txt foo/bar.txt open ftp.hoge.fuga.jp user kondoh ---- # !!! -debug モードでは、ここが丸見えなのでご注意 !!! bin prompt verbose Interactive mode off. Verbose mode on. login del foo.txt 250 DELE command successful cd foo 250 CWD command successful del bar.txt 250 DELE command successful cd .. 250 CWD command successful del foo.txt cd foo del bar.txt cd .. $ ./ftp_ut.py -debug ftp.hoge.fuga.jp kondoh xxxx rmdir foo open ftp.hoge.fuga.jp user kondoh ---- # !!! -debug モードでは、ここが丸見えなのでご注意 !!! bin prompt verbose Interactive mode off. Verbose mode on. login rmdir foo 250 RMD command successful rmdir foo
引数でサイトのユーザーアカウントやパスワードを指定するのが、 あまりにも煩雑なので、設定ファイルでも指定できるようにしてみました。
パスワードも設定ファイルに記述するのでご注意を。
$ cat v4.patch | patch -p1
YAMLファイルでファイル名はftp_ut.yaml固定です。
YAMLの辞書形式で記述します。
サイト名_a: host_a user_a passwd_a サイト名_b: host_b user_b passwd_b サイト名_c: host_c user_c passwd_c : サイト名_z: host_z user_z passwd_z default: サイト名_c
例えば
$ cat ftp_ut.yaml hoge: ftp.hoge.fuga.jp kondoh xxxx foo: foo.html.xdomain.jp foo yyyy default: hoge
YAMLの辞書形式なので、行の順番は任意です。
キーdefaultの箇所で、デフォルトのサイト名を指定しますが、この行は省略可能です。
このftp_ut.yamlのファイル名のファイルを、 まずftp_ut.pyのあるディレクトリを探して、ファイルあればロードします。
次に、カレントディレクトリにもこのファイル名のファイルがあればロードして、 重複してる項目は上書きします。
上書きは、辞書のupdate()メソッドを使ってます。
どこにもftp_ut.yamlファイルが見つからないときは、 従来通りコマンドラインでアカウントを指定する方法のままです。
ftp_ut.yamlファイルが見つかった場合は、 コマンドラインオプションで -s サイト名 で指定してサイトを選びます。
ftp_ut.yamlファイルが見つかり -s サイト名 の指定が無いときは、 設定ファイルのデフォルトの指定でサイトが選ばれます。
候補が1つしか無い場合は、デフォルトの指定が無くても、それがデフォルト扱いになります。
サイトの情報が見つから無ければ、それなりのメッセージを表示して終了です。
ftp_ut.pyのあるディレクトリは、__file__ で取得してます。
例えば、そこにftp_ut.yamlで各サイトの一覧を用意しておいて、 ftp_ut.pyを実行するときの各作業場所のftp_ut.yamlで、 デフォルトのサイト名だけを指定する事もできます。
ftp_ut.yamlが無い状態から
$ cd /tmp $ mkdir hoge $ cd hoge $ echo foo > foo.txt $ python -m ftp_ut Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-dbg] [-s site_name] host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. site_name in ftp_ut.yaml, can ommit host user passwd $ python -m ftp_ut ftp.hoge.fuga.jp kondoh xxxx foo.txt login put foo.txt
例えば ftp_ut.py のあるディレクトリは
$ python -m site | grep ftp_ut '/Users/kondoh/kon_page/ftp_ut', $ ls /Users/kondoh/kon_page/ftp_ut/ftp_ut.py /Users/kondoh/kon_page/ftp_ut/ftp_ut.py
なので
$ echo "hoge: ftp.hoge.fuga.jp kondoh xxxx" > /Users/kondoh/kon_page/ftp_ut/ftp_ut.yaml $ python -m ftp_ut ls foo.txt 229 Entering Extended Passive Mode (|||60053|) 150 Opening ASCII mode data connection for file list -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 11 11:58 foo.txt 226 Transfer complete
他のサイトも登録
$ echo "foo: foo.html.xdomain.jp foo yyyy" >> /Users/kondoh/kon_page/ftp_ut/ftp_ut.yaml $ cat /Users/kondoh/kon_page/ftp_ut/ftp_ut.yaml hoge: ftp.hoge.fuga.jp kondoh xxxx foo: foo.html.xdomain.jp foo yyyy $ python -m ftp_ut ls foo.txt err in .yaml, select by -s ption hoge foo Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-dbg] [-s site_name] host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. site_name in ftp_ut.yaml, can ommit host user passwd $ python -m ftp_ut -s hoge ls foo.txt 229 Entering Extended Passive Mode (|||60048|) 150 Opening ASCII mode data connection for file list -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 11 11:58 foo.txt 226 Transfer complete
そして、この/tmp/hogeからのときは、サイトhogeをデフォルトにするためには
$ pwd /tmp/hoge $ echo "default: hoge" > ftp_ut.yaml $ cat ftp_ut.yaml default: hoge $ python -m ftp_ut ls foo.txt 229 Entering Extended Passive Mode (|||60089|) 150 Opening ASCII mode data connection for file list -rw----r-- 1 kondoh.html.xdomain.jp 1000 4 Feb 11 11:58 foo.txt 226 Transfer complete
やはりバグがありました。
2つの設定ファイルを読み込むときの順番が逆でした。 修正しておきます。
あと、ファイルをアップロードするときなど、 サイトにログインした直後の場所からの相対の位置で作業するのが、 少々キツイです。
chrootじゃないですが、 サイトにログインしてすぐサイト側だけcdで指定場所に移動可能にしてみました。
$ cat v5.patch | patch -p1
$ python -m ftp_ut Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-dbg] [-s site_name] [-C dir] host user passwd path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. site_name in ftp_ut.yaml, can ommit host user passwd
-C dir を追加しました。
tarコマンドにならって -C です。
指定があるとサイトにログインした直後に cd dir を実行して移動します。
ローカル側は移動せずそのままです。
例えば
$ python -m ftp_ut -s site_foo -C foo/bar index.html
では、
従来の記述はそのまま使えます。
site_name: host user passwd
移動するディレクトリ指定を追加する場合は、
site_name: host user passwd foo/hoge
などと追加します。
元のcdしない場合と別のサイト名で用意してもかまいません。
site_name: host user passwd site_name_hoge: host user passwd foo/hoge
':' 右側の値の文字列にスペースが含まれてない場合は特別な指定と見なします。
例えば
site_name: host user passwd site_name_hoge: site_name/foo/hoge
他のエントリーのサイト名とディレクトリ指定を'/'で区切ってあるものとします。
例えば、作業ツリーの中で
foo/ foo/bar/hoge/
foo/ 直下と foo/bar/hoge/ 直下をよく使う場合
ftp_ut.pyのディレクトリにある方の設定ファイルftp_ut.yamlでは
site_name: host user passwd site_foo: site_name/foo #site_hoge: site_name/foo/bar/hoge site_hoge: site_foo/bar/hoge
などと登録しておいて
foo/ 直下の ftp_ut.yaml では
default: site_foo
foo/bar/hoge/ 直下の ftp_ut.yaml では
default: site_hoge
にしておくと、今いてるローカルの作業ディレクトリの場所によって、 ログイン後にサイト側も移動します。
気に入らない箇所を色々と書き換えてしまいました。
コマンドと同じ名前のファイルをアップロードできないので、 一応省略可能で put を明示的に指定できるようにしました。
lst の実行結果が、ls -F 的にファイルとディレクトリを区別した表示にしました。
$ cat v6.patch | patch -p1
$ python -m ftp_ut Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-debug] [-s site_name] [-C dir] host user passwd [put] path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. site_name in ftp_ut.yaml, can ommit host user passwd
ほぼ従来通り操作できると思います。
例えば、ftp_ut.yaml でデフォルトのサイトが設定されている環境で
$ mkdir -p tmp/hoge/fuga tmp/hoge/foo $ touch tmp/bar.txt tmp/hoge/hello.txt $ find tmp tmp tmp/bar.txt tmp/hoge tmp/hoge/foo tmp/hoge/fuga tmp/hoge/hello.txt python -m ftp_ut mkdir tmp tmp/hoge tmp/hoge/foo login mkdir tmp mkdir tmp mkdir tmp/hoge mkdir tmp mkdir tmp/hoge mkdir tmp/hoge/foo $ python -m ftp_ut tmp/bar.txt tmp/hoge/hello.txt login cd tmp lcd tmp put bar.txt cd .. lcd .. cd tmp/hoge lcd tmp/hoge put hello.txt cd ../.. lcd ../.. $ python -m ftp_ut ls tmp drwx---r-x 3 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:04 . drwxr-xr-x 32 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:02 .. -rw----r-- 1 kondoh.html.xdomain.jp 1000 0 Feb 14 00:04 bar.txt drwx---r-x 3 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:04 hoge $ python -m ftp_ut lst tmp bar.txt hoge/ $ python -m ftp_ut ls tmp/hoge drwx---r-x 3 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:04 . drwx---r-x 3 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:04 .. drwx---r-x 2 kondoh.html.xdomain.jp 1000 4096 Feb 14 00:02 foo -rw----r-- 1 kondoh.html.xdomain.jp 1000 0 Feb 14 00:04 hello.txt $ python -m ftp_ut lst tmp/hoge foo/ hello.txt $ python -m ftp_ut del tmp/hoge/hello.txt tmp/bar.txt login cd tmp/hoge del hello.txt cd ../.. cd tmp del bar.txt cd .. $ python -m ftp_ut rmdir tmp/hoge/foo tmp/hoge tmp/fuga tmp login rmdir tmp/hoge/foo rmdir tmp/hoge rmdir tmp/fuga rmdir tmp $ rm -rf tmp
違う環境で試してみると、色々と問題があったので修正してみました。
環境によっては、子プロセスで実行している ftp -n コマンドの標準入力に文字列を与えても、 標準出力は「だんまり」でした。
フラッシュかけてもだめ。
標準入力をクローズするまでは、返事を返してきません。
対話的にしたいので、こいうときは擬似端末。
pythonのptyモジュールを調べてみると、spawnで親側の標準入力、標準出力を変更するようなので、 別に「それ専用のコマンド」をkon_utに設けてみました。
$ cat v7.patch | patch -p1
kon_utにpyt_spawn.pyがある前提です。
kon_pageのpythonモジュールのインストール の手順で最新版にしておきます。
操作手順などは特に変わらないはずです。
ディレクトリを作るとき、ファイルやディレクトリの存在確認をしてから、 必要な分だけ作るようにしました。
ローカルにある深いパスのファイルをアップロードするときも、 ディレクトリが無ければputする前にmkdirするようにしました。
あと、サボってたftpサーバとの対話の同期を少しまともっぽくしました。
$ cat v8.patch | patch -p1
$ mkdir -p fuga/hoge/foo $ echo bar > fuga/hoge/foo/bar.txt $ find fuga fuga fuga/hoge fuga/hoge/foo fuga/hoge/foo/bar.txt $ python -m ftp_ut fuga/hoge/foo/bar.txt login mkdir fuga mkdir fuga/hoge mkdir fuga/hoge/foo cd fuga/hoge/foo lcd fuga/hoge/foo put bar.txt cd ../../.. lcd ../../..
ディレクトリの再帰的な削除を追加しました。
rm_rf で指定のパスを再帰的に削除します。 (rm -rfのつもりです)
危険なので慎重にご使用を。
$ cat v9.patch | patch -p1
$ mkdir -p fuga/hoge/foo $ echo bar > fuga/hoge/foo/bar.txt $ find fuga fuga fuga/hoge fuga/hoge/foo fuga/hoge/foo/bar.txt $ python -m ftp_ut fuga/hoge/foo/bar.txt login mkdir fuga mkdir fuga/hoge mkdir fuga/hoge/foo cd fuga/hoge/foo lcd fuga/hoge/foo put bar.txt cd ../../.. lcd ../../.. $ python -m ftp_ut lst fuga fuga/hoge fuga/hoge/foo ./ ../ hoge/ ./ ../ foo/ ./ ../ bar.txt $ python -m ftp_ut Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-debug] [-s site_name] [-C dir] host user passwd [put] path .. host user passwd del path .. host user passwd mkdir path .. host user passwd rmdir path .. host user passwd ls path .. host user passwd lst path .. host user passwd rm_rf path .. $ python -m ftp_ut rm_rf fuga login cd fuga/hoge/foo del bar.txt cd ../../.. rmdir fuga/hoge/foo rmdir fuga/hoge rmdir fuga $ python -m ftp_ut lst fuga $ rm -rf fuga
ディレクトリにロック用のディレクトリを作ったり削除したりする仕組みを追加してみました。
「ゆるゆる」のロック機構です。
秒単位のタイムスタンプに頼ってます。
ロックをかけたいディレクトリの直下に _lock/ というディレクトリを作って、 その中にローカルマシンの hostname username を元にまとめた文字列を作成。
例えば 'mac-a_kondoh' だとすると、 それに現在時刻の文字列を'.'でつないだ名前のディレクトリを作成します。
成功すれば、'get lock<改行> ...' と表示します。
target_dir/ _lock/ mac-a_kondoh.20200216142910/
ロックをかけようとしたときに、 誰かが作った有効なロックのディレクトリが残っていたら、 ロックに失敗し、'no lock<改行> ...' と表示します。
ただし、誰かがロックをかけたまま、異常終了してロック用のディレクトリが長らく残っていて、 いつまでもロックがかけれない、なーんて事がありがちですね。
なので、ロックをかけたり外したりするときに、 ゾンビが残ってないか調べて削除するようにしてます。
で、無事ロック用のディレクトリを作成した後、 誰かが同時にかけて競合してないかを、もう一度確認します。
$ cat v10.patch | patch -p1
$ python -m ftp_ut Usage: /Users/kondoh/kon_page/ftp_ut/ftp_ut.py [-h] [-debug] [-s site_name] [-C dir] host user passwd [put] path .. : host user passwd lock path .. host user passwd unlock path .. site_name in ftp_ut.yaml, can ommit host user passwd $ python -m ftp_ut mkdir foo login mkdir foo $ python -m ftp_ut lock foo get lock kon-no-MacBook-Air_local__kondoh_.20200216145548 $ python -m ftp_ut lst foo ./ ../ _lock/ $ python -m ftp_ut lst foo/_lock ./ ../ kon-no-MacBook-Air_local__kondoh_.20200216145548/ $ python -m ftp_ut unlock foo $ python -m ftp_ut lst foo ./ ../
今更ですが、ダウンロード方向の get も作ってみました。
指定のpathがディレクトリであれば、再帰的にダウンロードします。
エントリを調べつつ取得するので、のろいです。
ローカル側に勝手にディレクトリを作って上書きするのでご注意を。
$ cat v11.patch | patch -p1
$ mkdir -p fuga/hoge/foo $ echo bar > fuga/hoge/foo/bar.txt $ find fuga fuga fuga/hoge fuga/hoge/foo fuga/hoge/foo/bar.txt $ python -m ftp_ut fuga/hoge/foo/bar.txt login mkdir fuga mkdir fuga/hoge mkdir fuga/hoge/foo cd fuga/hoge/foo lcd fuga/hoge/foo put bar.txt cd ../../.. lcd ../../.. $ python -m ftp_ut lst fuga fuga/hoge fuga/hoge/foo ./ ../ hoge/ ./ ../ foo/ ./ ../ bar.txt $ mv fuga fuga- $ python -m ftp_ut get fuga login cd fuga/hoge//foo lcd fuga/hoge//foo get bar.txt cd ../../../.. lcd ../../../.. $ find fuga fuga fuga/hoge fuga/hoge/foo fuga/hoge/foo/bar.txt $ diff -ur fuga- fuga $
getの階層をたどる処理に無駄が多すぎてのろい問題はさておき、、、
find的なのを追加してみました。
指定path以下の階層のファイルを探してそのパス群を表示します。
Unix環境のfindコマンドのようにディレクトリのエントリは表示しません。
あと、get_kind() 関数にバグがあったので修正入れてます。
$ cat v12.patch | patch -p1
$ mkdir -p fuga/hoge/foo $ mkdir -p fuga/bar/guha $ echo bar > fuga/hoge/foo/bar.txt $ echo hello > fuga/bar/guha/hello.txt $ echo kon > fuga/kon.txt $ find fuga fuga fuga/bar fuga/bar/guha fuga/bar/guha/hello.txt fuga/hoge fuga/hoge/foo fuga/hoge/foo/bar.txt fuga/kon.txt $ python -m ftp_ut fuga/hoge/foo/bar.txt fuga/bar/guha/hello.txt fuga/kon.txt login mkdir fuga mkdir fuga/hoge mkdir fuga/hoge/foo cd fuga/hoge/foo lcd fuga/hoge/foo put bar.txt cd ../../.. lcd ../../.. mkdir fuga/bar mkdir fuga/bar/guha cd fuga/bar/guha lcd fuga/bar/guha put hello.txt cd ../../.. lcd ../../.. cd fuga lcd fuga put kon.txt cd .. lcd ..
ここまでは前置きです。
確認したかった肝心の箇所は次の通り。
$ python -m ftp_ut find fuga fuga/bar/guha/hello.txt fuga/hoge/foo/bar.txt fuga/kon.txt
ここからは後始末。
$ python -m ftp_ut rm_rf fuga login cd fuga/bar/guha del hello.txt cd ../../.. rmdir fuga/bar/guha rmdir fuga/bar cd fuga/hoge/foo del bar.txt cd ../../.. rmdir fuga/hoge/foo rmdir fuga/hoge cd fuga del kon.txt cd .. rmdir fuga $ python -m ftp_ut find fuga $ $ rm -rf fuga
getの階層をたどる処理に無駄が多すぎてのろい問題を対策してみます。
mgetを使ってみたりもしましたが、改善具合やいかに?
大きなサイズのファイルがあったり、 1つのディレクトリの中に大量のファイルがあと、 mgetのレスポンス待ちで何度も'timeout'の表示が出ますが、、、
気長に待てばファイルはちゃんと取れてると思います。;-p)
$ cat v13.patch | patch -p1
サイト用の設定ファイルを読み込む処理の箇所を、 site_ut.py として「のれん分け」してみました。
現状のftp_ut.py からは使ってませんが、 対応するURLも記述しておいて、取得できるようにしてみました。
例えばyamlファイルに次のような感じで、URLの記述を追加して試します。
site_name: host user passwd site_foo: site_name/foo site_hoge: site_foo/bar/hoge url: site_name: http://www.site_name.com site_hoge: http://www.site_name.com/hoge
$ cat v14.patch | patch -p1
上記の ftp_ut.yaml ファイルだったとして
$ cat ftp_ut.yaml site_name: host user passwd site_foo: site_name/foo site_hoge: site_foo/bar/hoge url: site_name: http://www.site_name.com site_hoge: http://www.site_name.com/hoge
$ ./site_ut.py site_name host: host passwd: passwd path: '' url: http://www.site_name.com user: user
$ ./site_ut.py site_foo host: host passwd: passwd path: foo url: http://www.site_name.com/foo user: user
$ ./site_ut.py site_hoge host: host passwd: passwd path: foo/bar/hoge url: http://www.site_name.com/hoge user: user
site_ut.py でサイト用の設定ファイルを読み込む際に、 URL以外にもどんどん追加しやすいように拡張してみました。
とりあえず 'url' 以外に 'lmt_size' という(謎の)項目を追加してます。;-p)
そして、site_ut.py に put(), get() 関数を追加してみました。
put() は内部的にftp_utを使って、サイトにファイルをアップロードします。
get() はwgetコマンドで、指定サイトのURLからファイルをダウンロードします。
$ cat v15.patch | patch -p1
$ cat ftp_ut.py site_name: host user passwd site_foo: site_name/foo site_hoge: site_foo/bar/hoge url: site_name: http://www.site_name.com site_hoge: http://www.site_name.com/hoge lmt_size: site_name: 3m
$ python -m site_ut site_name host: host user: user passwd: passwd path: '' url: http://www.site_name.com lmt_size: 3m $ python -m site_ut put hogehoge $ mv hogehoge hogehoge.org $ python -m site_ut get hogehoge
site_ut.py の get で、ディレクトリ・パスの生成が抜けてました。
修正しておきます。
$ cat v16.patch | patch -p1
site_ut.py get コマンドで、ディレクトリを含まないファイルだけのパスを指定した場合、 途中の取得先のディレクトリへの移動が、
$ cd
相当のコマンド実行になってしまい、変な動作になってました。
修正しておきます。
合わせて、取得元のURLの存在確認をしてから取得するようにしました。
$ cat v17.patch | patch -p1
putで指定pathがディレクトリの場合、 以下の階層にあるファイルとシンボリック・リンクを、 全てputするようにしてみました。
put側は簡単に実現できますが、 get側はwgetコマンドを使う方針なので、 簡単にはいかないですね。
$ cat v18.patch | patch -p1
ファイルやディレクトリが存在するか確認するだけの exists コマンドを追加しました。
get コマンド同様に path を指定します。
指定のファイルやディレクトリが存在すると、 found xxx と表示して、終了コード0で正常終了します。
存在しないと、 not found xxx と表示して、終了コード1で異常終了します。
内部では wget --spider コマンドを使ってます。
$ cat v19.patch | patch -p1
catコマンドを追加してみました。
ファイル限定で内容を標準出力に表示します。
(テキストファイルを想定してます)
内部では wget -q -O- 結果を表示してます。
$ cat v20.patch | patch -p1
site_ut.py の getコマンド箇所にtypoがありました。 修正しておきます。
にget_name_args()関数を追加したので、 site_ut.py から使うようにして整理しておきます。
site_ut.pyのコマンドライン引数にオプション -C dir を追加しました。
tarコマンドと同じく、動作前にローカル側のディレクトリ移動します。
ただし、ftp_ut.yaml のロードは起動した時のディレクトリからロードするのはそのままです。
ロード後に、-C dir 指定のディレクトリに移動して後続の処理を実行します。
$ cat v21.patch | patch -p1
長らくftp_ut.yamlファイル設定に頼る使い方しかしてなかったら、 直接host, user, passwdを指定する使い方が出来なくなっておりました。
見直してみると、なるほど、従来の指定の仕方では多少無理がある状態...
専用のオプション指定 -SITE "host user passwd" を追加します。
$ cat v22.patch | patch -p1
$ ftp_ut -SITE "host user psswd" path ...
などと指定します。
ローカル側のディレクトリ指定 -C dir でのputでは、 site_utの内部でディレクトリ移動してから、 ftp_utを呼び出していたため、 ftp_utで参照するカレントディレクトリのftp_ut.yamlが、 site_utと異なってしまう事態に陥っておりました。
ディレクトリ移動した後は、 移動前に取り込んだサイトの情報を、 ftp_utで直接指定するようにして、対策してみます。
$ cat v23.patch | patch -p1
site_ut.pyのputコマンドの実行時に、だんまりの期間があまりに長いので、 -verb オプションを追加してみました。
-verb を指定して実行すると、 内部で実行するftp_ut.pyで -debug オプション付きで実行します。
コマンド実行に使っているcmd_ut.pyのcall()では、 subprocess.check_output()を使っているので、 コマンド実行の時に表示される文字列は、終了の値に返り値としてまとめて返されるため、 肝心な時に表示はされず「だんまり」のままです。
これだけのために pythonのユーティリティ・プログラム 2020冬 を更新して cmd_ut.py にcall_show()を追加してみました。
さらに、ftp_ut.pyで-debugオプションを指定したときは、 login時のパスワードも表示されてしまっていたので、 伏字にする対応も入れてみました。
$ cat v24.patch | patch -p1
-debugオプション付きのときに、パスワード以外にも、 ホスト名やユーザも伏字にするようにしました。
簡易なファイルツリーのバージョン管理ツール(gitの真似事) 2020春 の絡みで、色々と不具合があぶりだされました。
lmt_size設定の関連で、大きなファイルを分割した場合や、 URL上のファイルの存在確認などににバグがありました。
修正しておきます。
$ cat v25.patch | patch -p1
fsyn push site_utからsite_ut.py経由で使うときに、 FTPサイトのディレクトリに大量のファイルが溜まってくると、 lsのレスポンスが返るまでに、頻繁にタイムアウトするようになって しまいました。
とりあえずタイムアウトを15秒から4倍の1分にして、しのいでおきます。
v26.patch
diff -ur v25/ftp_ut.py v26/ftp_ut.py
--- v25/ftp_ut.py 2020-05-06 19:08:35.000000000 +0900
+++ v26/ftp_ut.py 2021-04-02 21:15:41.000000000 +0900
@@ -13,7 +13,7 @@
to_str = base.to_str
-def new(host, user, passwd, tmout1=15, tmout2=1, debug=False):
+def new(host, user, passwd, tmout1=60, tmout2=1, debug=False):
ftp_cmd = 'python -m pty_spawn ftp -n'
proc = cmd_ut.proc_new_comm_tm2( ftp_cmd, tmout1, tmout2 )