optparse-applicativeはいい感じでした,Data.ByteString.readFileは/dev/stdinを読み込めない,GitPythonを使いました,python好きになれない

だるすぎる

だるすぎてやるべきことがあるのに,ずっと世界樹の迷宮IV 伝承の巨神をやっていました.最近これを再開して,ちょっと前にクリアしました.

  • ソードマン/ルーンマスター
  • ナイトシーカー/ミスティック
  • メディック/ダンサー
  • スナイパー/ミスティック
  • ルーンマスター/メディック

の構成でやっています.

それで第六迷宮に潜っていたのですが,三頭飛南瓜が強すぎて1回勝ったけどもうひとつのグループに全滅させられ続けて作業をやりたくなってきました.

作業やってました.

optparse-applicativeはいい感じでした

optparse-applicative :: Stackage Serverを使ってhaskellコマンドラインツールを書いています,やっぱりいい感じでした.

しかしこのParserApplicativeですがMonadではないので,もちろんモナド変換子ではなく,基底でIOを実行できません.その不自由さがある分宣言的に記述することが可能なのですが.

私が書いてるコマンドラインツールは状態を設定ファイルで持つので,その設定ファイルが存在するかでコマンドラインオプションの必要性が変わってくるので自前で書かないと処理できません.

問題は先にファイルを読み込むか,後に読み込むかですが,コマンドラインオプションの指定があれば上書きしたいので,後に読み込むことにして,オプションが存在しなかった場合は読み込んでファイルも無かったらエラーを出すことにしました.

optparse-applicativeのMaybeの取り扱いはoptionalで

指定してもしなくても良いコマンドラインオプションをMaybeで取り扱いたい.

valueというデフォルト値指定関数がありますが,今回は指定しない場合は他の引数に影響されて決定するようになっているので,MonadではなくApplicativeParserでは決定できません.

option autoで良いのかな,と思って指定したけどこれは単にReadでパースするように指定するだけなので,必須コマンドラインオプションとして扱われてしまいますね.

悩んで「optparse-applicative maybe」でググったら,以下のページを見つけました.

なるほど,Alternativeのインスタンスだからoptionalを使えば良かったのですね.公式クイックガイドには書いてなかったので見落としてました.

Data.ByteString.readFileは/dev/stdinを読み込めない

optparse-applicativeのリファレンスにはAlternativeの例としてStdInputが載っています.しかし私は標準入力向けのコマンドラインオプションを用意するのが面倒だったのでコマンドラインで/dev/stdinを指定すればいいじゃんと思ってたら/dev/stdin: hFileSize: inappropriate type (not a regular file)が起きました.

あれー,haskellのreadFileって/dev/stdin読み込めたはずじゃなかったか…?と思ったら,Data.ByteString.readFileは読み込めないそうですね,なるほどなあ.

System.IO.readFileで読み込んでByteStringpackしてやれば動きました.これだと多分効率はよろしくないのでしょうけど,そこまで気にする用途でもないのでこれで良いかな.

pythonを書いています

何年ぶりかわからないけれどpythonを書いています.シェルスクリプトは色々と苦しい,perl5を今選択するのはない,rubyは飽きてきた,というわけでpythonです.

いや本当はhaskellの方が良いのですが,ファイルを直接実行するスクリプト用途なので毎回runhaskellを実行するのはなあと思って今回は選んでません.

シェルスクリプト代わりに使っているのでsubprocessぐらいしか使ってませんが,数年前に色々やった時と違ってsubprocess.runというインターフェイスに統一されてかなりわかりやすくなってますね,良い.

戻り出力が文字列だと思ってたら実際はバイト列でした.universal_newlines=Trueを指定しないと文字列ではなくバイト列になるみたいですね.今回はバイト列で良かったのでバイト列として扱いました.

subprocess.runをネストして呼び出していたら上手く行かなかった

subprocess.runの引数にsubprocess.runの結果を渡そうと,ネストして書いていたらなんかダメでした.

一度変数でキャプチャして渡してやると上手くいきました.

ネストして二重の呼び出し状態にすると上手く行かないのかもしれません.マニュアルを見てもそういったことは書いてなかったのでよくわからない.

GitPythonを使うことにしました

ちょっとした作業だと思ってsubprocessでgitをコマンドラインインターフェイスから呼び出してpythonでやっていましたが,なんかちょっと複雑になってきたのでgitpython-developers/GitPython: GitPython is a python library used to interact with Git repositories.とか使った方が良いのかなあと思えてきました.

依存ライブラリが増えるのは避けたかったので標準ライブラリでやっていましたが,結構複雑になってきた.

もちろんごり押しで検出とかやっていくことも出来るでしょうけど,生文字列を弄ってどうこうするのは不安が多すぎる.

結局GitPythonもgitをコマンドラインで呼び出していることには変わらないんですけど,抽象化を自前でやるのはだるすぎる.

しかしpipがよくわからない,手前だけやるならportageでインストールして終われるけれど,実際に向こう側のubuntuで動くかどうかそれだと不明なので悩む.

手元のgentooだとmake.confPYTHON_TARGETS="python2_7 python3_4 python3_6"しないとpipによるインストールが適用されなくて少し悩みました.

stack使っていいhaskellのプログラムとかは自動でインストールまで行ってくれるから気軽に外部のライブラリ使えるけど,インストールがファイルをコピーするという手動な方法だと自動化されてないから使うの少し躊躇ってしまいますね…

しかし,GitPythonはそれでも良いと言えますね,テキストをわざわざパースしなくてもchange_typeなどへのインターフェイスが確保されてます.

4b825dc642cb6eb9a060e54bf8d69288fbee4904を使ったfirst commitへのdiffハックが動かなくて困りました.first commitではHEAD^が存在しないため,これとのdiffが取れないという問題です.version control - How to get Git diff of the first commit? - Stack Overflow

commit.diff("4b825dc642cb6eb9a060e54bf8d69288fbee4904")[0]なら動くんですけど,これはHEAD -> empty向けのdiff生成になってしまうので,逆になってしまうんですよね.

repo.commit("4b825dc642cb6eb9a060e54bf8d69288fbee4904")Commitオブジェクトを作り出そうとしても,これはValueError: Cannot convert object <git.Tree "4b825dc642cb6eb9a060e54bf8d69288fbee4904"> to type commitになってしまいます.

どうもこれの解決策は存在しないみたいなので,first commitの場合は全てnew fileになるので全文を投稿するという方法で迂回することが出来るでしょう.diffではないからdiffは対応しなくて良い…ということで.

diffの動作がcreate_patch = Trueを付けるかで全く変わってしまって困惑しました.create_patch = Trueがないとdiffが生成されないっぽいので付けなければならないのですが,付けるとchange_typeが消滅してしまいます.仕様っぽい.

まあ所詮subprocessでgitを呼び出しているだけなので,パラメータで出力が変わってしまうのは仕方がないのか.new_fileメソッドを使うことで対処.

python好きになれない

やはりpythonも好きになれないと感じてしまった…

バイト列と文字列の区別が代表するように,型を意識してプログラミングしないといけないのに,実行時前型チェックがないので苦痛感がありますね…それは標準ライブラリの問題かもしれません.

これはGitPythonの問題なのかもしれませんがオブジェクトの状態によってメソッドが生えてたり生えてなかったり空を返してきてきつい.30行ほどのプログラムでもかなりきついのに大規模な開発はきつい…

構文自体は嫌いじゃないのになーと思ったけど構文も条件演算子が謎の構文だったり引数の形式がごちゃごちゃだったりでアレだ.

まだrubyの方が型をほとんど気にしないで済むからマシかもしれない.もちろん動的型付け言語では何が良いかというとperl6のように漸進的型付けをちゃんとやるか,多くのlispのように連想マップで全て誤魔化すかですね.ただperl6は処理系がまだ未完成で速度がひどくlispは方言が散らばって何を使ってもライブラリが足りなくなってしまう.

何を言いたいかわからなくなってきた.haskell以外全方位言語disをするためにブログを書いているわけではない.あんまり文句言うとあれなのでフォローするとシェルスクリプトの上位互換としてはやっぱり優秀ですよね,python.