2012-12-07 [長年日記]

Tracの構造を見てみる

昨日に引き続き、Tracプラグイン開発について掘り下げるよ。

コンポーネントアーキテクチャ

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メソッドでリクエストを処理してやればいい、ということ。


«前の日記(2012-12-06) 最新 次の日記(2012-12-08)»