Tracの中心部分は、プラグイン可能なコンポーネント構造となっている。
チケット、Wiki、リポジトリといったほとんどの機能がコンポーネントとして提供されていて、設定如何で脱着できるようになっている。
Tracのプラグインを作るときは、使いたい拡張ポイントのインタフェースを実装し、実行パスに置いてTracコアに見つけてもらう、という流れになる。
前回のabout.py のブレークポイントで止めたときのコールスタックを見てみる:
Thread-8 - pid6556_seq9 process_request [about.py:60] dispatch [main.py:214] _dispatch_request [main.py:497] dispatch_request [main.py:465] __call__ [standalone.py:91] __call__ [standalone.py:59] run [wsgi.py:91] handle_one_request [wsgi.py:191] handle [BaseHTTPServer.py:340] __init__ [SocketServer.py:638] finish_request [SocketServer.py:323] process_request_thread [SocketServer.py:582] run [threading.py:504] __bootstrap_inner [threading.py:551] __bootstrap [threading.py:524]下が親、上が部品。一番下の __bootstrap [threading.py:524] から run [wsgi.py:91] までは、Webサーバとしての構造なので読み飛ばす。で、Webからの玄関であるWSGI経由でWebアプリのmain.pyが実行され、そのdispatchメソッドが Aboutモジュールの process_request [about.py:60] を呼びだしている。
main.py が Aboutモジュールを見つけて呼び出すまでの流れは、こんな感じ:
093: handlers = ExtensionPoint(IRequestHandler) : 169: for handler in self.handlers: 170: if handler.match_request(req): 171: chosen_handler = handler : 214: resp = chosen_handler.process_request(req)IRequestHandlerインタフェースを実装したモジュールたちの match_request を順に呼び出して、適合すると表明したモジュールの process_request を実行する、というシンプルな仕組み。
つまり、自分でプラグインを実装するときも、IRequestHandler インタフェースを実装したクラスで、match_requestメソッド で自分が処理できるリクエストかどうか判定し、process_requestメソッドでリクエストを処理してやればいい、ということ。
次回は、上記の要領で、IRequestHandler を実装して HelloWorldプラグインを作ってみる。