読者です 読者をやめる 読者になる 読者になる

0.11でTracMacroを書く

Trac

Shibuya.trac新年会で結構みんなの待望だったRSSマクロが公開されていました。このRSSマクロ、最新版のTrac 0.11では動かないみたい。なぜならTracは0.11からClearSilverではなくgenshiというテンプレートエンジンへ載せかえられているから。*1 *2

今日はRSSマクロを0.11へ移植してみた。その際学んだことをつらつら書いていきます。今回はLinux上ではなく、TracLightning2.1-beta4を使ってみました。Windows上です。

え?Tracはマクロとかを修正したときにサーバーの再起動が必要なの?

のっけからビックリしたんですが、Tracはサーバーのソースを修正すると自動的に更新するわけではないようです。否「自動的に更新」じゃなくて、望「毎回スクリプトを実行する」か。サーバとして起動するときにスクリプトをコンパイルして読み込んでおくような動きをしています。mod_pythonのディレクティブの設定でPythonAutoLoadなんてものがあるんで、それをONにしても反応が変わらず。
mod_pythonを使ってるからか?と思ってtracdで起動して、マクロを書き換えても読み込んでくれません。Tracのアプリケーションの特性なんでしょうか?良く分かりません。そこでCGIにしてTracを実行してみました。毎回プロセスを作る、と言われているCGI。要するに毎回新しく"python"コマンドで実行してるんだよな、と理解してるんですが、そういうことでしょうか。実行するたびにTracのスクリプトが読み込まれ、実行されるわけですから、そりゃ遅い。体感で20秒くらいかかります。マクロを書き換えて実行して…って、サーバー再起動するのとおんなじくらい時間かかるやん><
じゃ、気を取り直してFastCGIで動かしてみっか!とやってみたところ、Windows上だと実装していない処理があるから動かないよ、ってTracのドキュメントにかかれてました。*3

じゃ、マクロをコマンドラインから動かせないの?

0.10までのマクロは、スクリプトファイルの直下に直接メソッドを定義していました。これのいいところはそのメソッドをpythonインタプリタから直接実行できたわけです。こんな感じ。

if __name__ == '__main__':
  print execute( None, sys.argv[1], None )

0.11からのマクロはお行儀良く、クラスを作って、IWikiMacroProviderインターフェースを実装せよ、との事。しかもこのクラス、Componentクラスの子クラスでなければならない模様。これからはマクロもpluginsディレクトリにツッコめとなっているので嫌な予感がしてたけど、ほんとにそうなんですね。で、こんな風にしてみたら動いたよ。

from trac.test import EnvironmentStub

if __name__ == '__main__':
  env = EnvironmentStub()
  rss = RSS(env)
  print execute( None, sys.argv[1], None )

EnvironmentStubはテスト用のスタブ。ComponentクラスはコンストラクタでComponentManagerクラスのインスタンスを要求してやがる。だけどtrac.coreで定義されているComponentManagerクラスは、隠蔽されてます。*4なのでどうしたものか、と悩んだ末、EnvironmentStubでいけたので、これを使えばユニットテストも書けますね。
とりあえず今日はこんなところで。って言っても結構悩んだんだよ。

*1:ClearSiverはCで書かれており、OSネイティブなテンプレートエンジンです。そのため、移植性が多少下がってしまいます。できることならpythonで書かれたテンプレートエンジンが望まれていたわけです。そこで登場したのがgenshi。これはPythonで書かれたテンプレートエンジンで、Tracと同じedgewallで開発されているようです。

*2:ほんとか?ClearSilverが入ってたらwiki-macrosディレクトリに入れたら動く気がする。

*3:wiki/TracFastCGIってページです。

*4:__all__=['Component',...で羅列しているのは公開しているクラス、メソッド