optparse-applicativeはいい感じでした, Data.ByteString.readFileは/dev/stdinを読み込めない, GitPythonを使いました, python好きになれない
だるすぎる
だるすぎてやるべきことがあるのに, ずっと世界樹の迷宮IV 伝承の巨神をやっていました. 最近これを再開して, ちょっと前にクリアしました.
- ソードマン/ルーンマスター
- ナイトシーカー/ミスティック
- メディック/ダンサー
- スナイパー/ミスティック
- ルーンマスター/メディック
の構成でやっています.
それで第六迷宮に潜っていたのですが, 三頭飛南瓜が強すぎて1回勝ったけどもうひとつのグループに全滅させられ続けて作業をやりたくなってきました.
作業やってました.
optparse-applicativeはいい感じでした
optparse-applicative :: Stackage Serverを使ってhaskellコマンドラインツールを書いています, やっぱりいい感じでした.
しかしこのParser
はApplicative
ですがMonad
ではないので,
もちろんモナド変換子ではなく,
基底でIO
を実行できません.
その不自由さがある分宣言的に記述することが可能なのですが.
私が書いてるコマンドラインツールは状態を設定ファイルで持つので, その設定ファイルが存在するかでコマンドラインオプションの必要性が変わってくるので自前で書かないと処理できません.
問題は先にファイルを読み込むか, 後に読み込むかですが, コマンドラインオプションの指定があれば上書きしたいので, 後に読み込むことにして, オプションが存在しなかった場合は読み込んでファイルも無かったらエラーを出すことにしました.
optparse-applicativeのMaybeの取り扱いはoptionalで
指定してもしなくても良いコマンドラインオプションをMaybe
で取り扱いたい.
value
というデフォルト値指定関数がありますが,
今回は指定しない場合は他の引数に影響されて決定するようになっているので,
Monad
ではなくApplicative
なParser
では決定できません.
option auto
で良いのかな,
と思って指定したけどこれは単にRead
でパースするように指定するだけなので,
必須コマンドラインオプションとして扱われてしまいますね.
悩んで「optparse-applicative maybe」でググったら, 以下のページを見つけました.
- haskell - How to parse Maybe with optparse-applicative - Stack Overflow
- HaskellのOptparse-Applicativeの底力を知る - mathhunの日記
なるほど,
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
で読み込んでByteString
にpack
してやれば動きました.
これだと多分効率はよろしくないのでしょうけど,
そこまで気にする用途でもないのでこれで良いかな.
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.conf
でPYTHON_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.