proglog

主にプログラミングに関する断片的メモ

[devel][python] buildoutを使い始めるためのメモ

いくつかgaeのアプリケーションをpython2.5で作ってきた。
2.7も試したけど、個人的な用途ではあんまり旨味がなかったので、スルーしてきた。
でも、2.7でしか使えないライブラリなんかも追加されてきて、ちょっと触手を伸ばしてみようかと。

vertualenvで切り替えるのもいいけど、せっかくなので、同じような文脈でよく目にしたbuildoutを試してみることに。

参考にしたのは以下の二つのサイト


以下そのメモ。
疑問点、わからないところなども含む。

イントロ

buildoutはだいたい、cのmakeやjavaのantに当たるPythonのツール。
どっちかって言うとantに近いような。


Makefieleやbuild.xmlに相当するものは、buildout.cfgというコンフィグファイルで、これにやりたいことを書く。


ユースケースとしては、

などなど

ありがたいことに、そういったケースについて、buildout.cfgを公開してくれてるサイトがある。
だから、それをもらってきて使えば、詳細を知ることなく、その恩恵にあずかれる。
例えば、Google App Engine (GAE/py) の開発環境をつくる - 清水川Webなど。

ここで、mynewgaeappをプロジェクトルートとする。
上記のようなサイトのbuildout.cfgをコピペして、その上のディレクトリに保存してあるとする。

mkdir mynewgaeapp
cp buildout.cfg mynewgaeapp
cd mynewgaeapp
buildout

これだけで、サブディレクトリを作って、必要なライブラリをダウンロードして、開発環境を作ってくれる。

インストール

makeやantoと大きく違うのは、buildoutは、基本的には、プロジェクトごとにインストールして使う物らしい。
では、そのbuildout自体を、どうやってインストールするか。
これには三つの方法があるらしい。

  • bootstrap.py
  • zc.buildout.eggをシステムのpython(以下、system python)にインストールして、そのbuildoutを使う。
  • 最初だけ他のプロジェクトのbuildoutを使う

いろいろ見たページで一番多いのはbootstrap.pyを使うものだった。
これは、その名の通り、bootstrapを行う。つまり、buildout自体、その最新版をダウンロードしてきて、使える状態にしてくれる。
三番目のは、使い始めの段階ではパス。
で、厳密には一番目がいいんだろうと思う。けど、面倒なので僕は2番目の方法で。

pip install zc.buildout

これで、system pythonScriptsディレクトリにbuildoutコマンドがインストールされる。
そこにパスが通っていれば、冒頭の通りに使える。

実行方法

インストール後は、基本的には、プロジェクトにある"bin/buildout"を実行。
partsを個別に実行する時は、"/bin/buildout install parts名"らしい。
なんでinstallなのかはよく分からない。
ルート直下の"install.cfg"に実行ログが書かれる。

自分で一から始めるには

mkdir newproj
cd newproj
buildout init

これで、必要なディレクトリが作られ、プロジェクトルート直下のbinディレクトリにbuildoutがインストールされ、プロジェクトルートに、buildout.cfgの雛形が作られる。

プロジェクトのソースファイルの置き場所は、基本的にはプロジェクトルート。
ディレクトリ構造はネストするより浅く広くがこのツールのポリシーらしい。

そうは言っても、ルート直下に"src"ディレクトリを掘ってその下に置く例もある。

その他の構造はDirectory Structure of a Buildout ― Buildout v1.2.1 documentation

buildout.cfgの書き方

個人的に一番多いユースケースは、サンドボックスでライブラリを試すこと。
だから、このケースに沿ってメモ。

概要

makeのルール、あるいはターゲットとコマンド行、antのターゲットとタスクに相当する物は、それぞれ、partsrecipe

recipeは、例えば何かのフレームワークのダウンロード、インストールを行って開発環境を設定する、などという一つのまとまったことを丸ごと行ってくれるものが多い。
partsは実質、このrecipeのオプション設定を行うもので、各partsにrecipe一つという形式。
antなどのように、一つのターゲットに、タスクを複数、ということはない。

そしてrecipeはたいていpypiにあるけど、名前さえ指定すれば、buildoutがダウンロードしてきてくれる。
至れり尽くせり。

文法

書き方は、PythonConfigParserのフォーマットプラスα。
つまり、基本は

[ヘッダ](ヘッダ)
name=value(オプション)

で構成されるセクション、という構造で書いていく。

αの部分は、

  • makeなんかにもある変数の置き換えマクロ
  • 大文字小文字の区別。
  • コンフィグファイルの継承に伴ったオプションの付け替え

この最後のやつはここでは省く。
基本モジュールを作っておいて、あとでそれをインクルードして変数設定して使うとかそんな感じかと。

基本型

buildoutセクションのpatrsオプションにpartsの名前を並べる。宣言か。
parts名は任意。
そしてそれに応じたpartsセクションを作って、partsの中身を定義する、という形。


partsには、それぞれ一つのrecipeを置き、そのrecipeのオプションを設定していく。
逆に、recipeとそのオプションを設定するのがpartsセクションだと考えたほうがいいのかも。

[buildout]
parts= foo bar

[foo]
recipe=baz.quxw
quxwopt1=value1
quxwopt2=value2

[bar]
recipe=baz.quux
quuxopt=${hoge:fuga}

[hoge]
fuga=piyo

buildoutセクションで、"foo"と"bar"という二つのpartsの使用を宣言。
パーツ"foo"セクションのrecipeオプションでrecipe"baz.quxw"の使用を設定。
その"baz.quxw"が要求するquxwopt1とquxwopt2に値を設定、という形。

ここでhogeセクションはpartsセクションじゃない。recipeがないので。
なにかrecipiがオプション設定にそういう書き方を要求するとか、置き換えマクロで使うような変数を書いたりする時に、こういうセクションが使われる。

パーツbarのセクションのquuxoptが変数置き換えの例。
${セクション名:オプション名}の形で参照できる。
ここでは、hugeセクションのfugaオプションの値を参照している。

buildout.cgの例

実際に動く形で。
適切かどうかは分からない。

ライブラリsimplejsonをサンドボックスで試すケース。
僕は、普段python25を使っているので、python2.7のサンドボックスを作ってみる。

[buildout]
parts = tryjson
python=python27
unzip=true
include-site-packages=false

[tryjson]
recipe=z3c.recipe.scripts
eggs=simplejson
interpreter=myp


[python27]
executable=C:\lang\Python27\python.exe

という感じになる。

ここでは、z3c.recipe.scriptというレシピを使っている。
これは、こういう用途に使うものらしい。
そして、その設定をするためのpartsセクションをtryjsonという名前で作っている。

buildoutセクションのオプションのリストはzc.buildout Predefined buildout options
その下のほうにも、散発的にオプションが出てくる。

ここでは、buildoutセクションのpythonオプションでターゲットとなる処理系をしている。

include-site-packagesオプションで、site-packageを切り離し、あとは、site-customizeをオフにする設定を加えるだけ。ほぼ完全にvertualenv代替という感じか。

partsであるtryjsonセクションの"interpreter"オプションは、recipeである"z3c.recipe.scripts"のもので、要は"sys.path"を適切に設定したpythonの起動スクリプトをこの名前で作ってくれる、というものっぽい。
だから、このプロジェクトで使うpythonは、"bin/myp"で起動することになる。
じゃあ、shebangとかもそう書けってことか。
じゃあ、emacspython-modeとかから利用するのはどうするんだろう。
一時的にsetq?

実際の利用方法

recipeを探す

recipeのリストを見て、自分の要求に合う物を選び、組み合わせてbuildout.cfgを書く。
recipeの所在は、

とかなんだろうか。

PyPI以外のところにあるrecipeを使う時は、buildoutセクションのオプションに、それを設定する項目がある。

parts間の依存関係

例えば、antのタスクの実行のためのフラグプロパティみたいなものはないみたい。
recipeはそれ自体で一通りのことをするので、たいていはparts間の依存性は気にしなくてもいい感じ。

だけど、例えば、他のpartsセクションで設定したoption値とかを参照する時は、依存性が生じる。
無理矢理作った例

[buildout]
parts = p1 p2 p3

[p1]
dummy = 1


[p2]
recipe = collective.recipe.template
input = inline:
   #!/bin/bash
   echo ${p3:foo}

output = out.sh


[p3]
recipe = mr.scripty
foo = return "from p3"


[parameter]
foo = 10
bar = 20

partsセクションのp3で設定したオプションfooの値をpartsセクションのp2で参照している。

p2で使ってるrecipeは、テンプレートからファイルを作ってくれるもの。
こういうのはいくつかあるみたいだけど、ここではbuildout.cfg自体にテンプレートを書けるものを使った。

p3で使ってるrecipeは、オプションの値の設定にpythonスクリプトを書けるようにするもの。
実はセクションをクラスにして、そのオプション名のインスタンスメソッドを作ってるらしい。
だから、returnで値を設定、ということになる。

で、p3で設定したオプションfooの値を、p2のテンプレート中で使ってる。
p2のインストールだけをした場合、どうなるか。

ともあれ、これを実行する

>buildout install p2
Getting distribution for 'mr.scripty'.
Got mr.scripty 1.0b3.
Getting distribution for 'collective.recipe.template'.
Got collective.recipe.template 1.9.
Installing p2.

>cat out.sh
#!/bin/bash
echo from p3

p2のインストールを指定しただけだけど、きちんとp3が実行されて、それを反映したファイルができてる。
オプションの値の参照関係なんかは、きちんと拾ってくれるみたい。

ローカルなrecipeの使い方 :search:

マニュアルでやってること

pythonの対話モードでwrite()でbuildout.cfg書いたり、cat()でその中身を確認したりしてる。
なんだろうと思ったら、zc.buildout.testingをimportすると使えるみたい。

使える関数一覧はzc.buildout 1.5.2 : Python Package Index