ほげにっき

hogedigoの日記

ScrumもどきPlugin開発記

を書くことにした。せっかくなので。

pythonTrac plugin開発も未熟なので、もし識者が読んでツッコミ入れてくれたら・・・という淡い期待も。


参考にしたのは以下のチュートリアル。Trac0.11用なので注意。
EggCookingTutorialTrac0.11 – Trac Hacks - Plugins Macros etc.

構成

いっちょやってみっか!

とりあえずTracに必要なcustom ticketを挿入する機能を作ってみよう。
そしたらこのplugin開発自体をTracで管理して、かつテストまで出来るしね。

追加するticketは

estimate 見積もり
remain 残作業量

の二つ。


trac.iniに直接記述するとしたら、以下になるイメージ。

[ticket-custom]
estimate = text
estimate.label = Estimated hours
estimate.order = 10
estimate.value = 0
remain = text
remain.label = Remain
remain.order = 11
remain.value = 0

参考にしたのはTiming And Estimating pluginのソース。

ディレクトリ構成

src
│  setup.py
│
└─scrumhalf
        initenv.py
        __init__.py

実装

まずプラグインコンポーネント本体

initenv.py
import re
import time
from trac.core import *
from trac.env import IEnvironmentSetupParticipant
from trac.perm import IPermissionRequestor, PermissionSystem

class SetupEnv(Component):
    implements(IEnvironmentSetupParticipant)
    
    def __init__(self):
        pass

    def environment_created(self):
        if self.environment_needs_upgrade(None):
            self.upgrade_environment(None)
            
    def ticket_fields_need_upgrade(self):
        ticket_custom = "ticket-custom"
        return not ( self.config.get( ticket_custom, "estimate" ) and \
                     self.config.get( ticket_custom, "remain" ) and \
                     self.config.get( ticket_custom, "estimate.order") and \
                     self.config.get( ticket_custom, "remain.order"))
    
    def do_ticket_field_upgrade(self):
        ticket_custom = "ticket-custom"
        
        self.config.set(ticket_custom,"estimate", "text")
        if not self.config.get( ticket_custom, "estimate.order") :
            self.config.set(ticket_custom,"estimate.order", "10")
        self.config.set(ticket_custom,"estimate.value", "0")
        self.config.set(ticket_custom,"estimate.label", "Estimated hours")             

        self.config.set(ticket_custom,"remain", "text")
        if not self.config.get( ticket_custom, "remain.order") :
            self.config.set(ticket_custom,"remain.order", "11")
        self.config.set(ticket_custom,"remain.value", "0")
        self.config.set(ticket_custom,"remain.label", "Remain")             

        self.config.save();

    def environment_needs_upgrade(self, db):
        return self.ticket_fields_need_upgrade()
            
    def upgrade_environment(self, db):
        if self.ticket_fields_need_upgrade():
            self.do_ticket_field_upgrade()
        print "Done Upgrading"

自分もまだ理解していないが、いちお解説^^;


まずTrac pluginはtrac.core.Componentを継承するもの・・・らしい。

class SetupEnv(Component):

この辺のアーキテクチャについてはComponentArchitecture参照。


次に以下の文、

    implements(IEnvironmentSetupParticipant)

implementsメソッドで、インターフェース(拡張ポイント)を実装する。javaのイベントアーキテクチャ(なんたらListenerやらHandler)と似てる。

必要な拡張ポイントは複数implements出来る。その他標準拡張ポイントはTracDev/PluginDevelopment – The Trac Project参照。


IEnvironmentSetupParticipantインターフェースは、「Trac環境の初期化及びアップグレードを行う為の拡張ポイント」(IEnvironmentSetupParticipantコメントより意訳)だそうだ。Timing and Estimating pluginではDBテーブル作成などもしていたが、ここではとりあえずcustom ticketのみ追加しておく。


IEnvironmentSetupParticipantに定義されているメソッド(イベントハンドラ)は以下の3つ。

environment_created 新しいTrac環境が作成された時に呼び出される
environment_needs_upgrade Trac環境の更新が必要かどうかを返す
upgrade_environment 環境の更新を行う

Trac環境(原文:Trac environment)ってのはtrac-admin initenvで作成したプロジェクトのことかな。
うーん・・・。イマイチまだ把握出来ていないが・・・ここはとりあえずTiming And Estimating Pluginを参考に、各メソッドを実装する。

__init__.py
# TracScrumHalf module
from initenv import *

このファイルは、パッケージの初期化コードを記述する特殊ファイル。python仕様なので割愛。ここでComponentを定義してあるモジュールをimportする。importするだけで何故かTracから認識される。非常に簡単だが何やってるのかは謎。。とりあえずいつか調べる。

setup.py
#!/usr/bin/env python

from setuptools import find_packages, setup

# name can be any name.  This name will be used to create .egg file.
# name that is used in packages is the one that is used in the trac.ini file.
# use package name as entry_points
setup(
    name='TracScrumHalf', version='0.10',
    packages=find_packages(exclude=['*.tests*']),
    entry_points = """
        [trac.plugins]
        scrumhalf = scrumhalf
    """,
    package_data={'scrumhalf': ['templates/*.html', 
                                 'htdocs/css/*.css', 
                                 'htdocs/images/*']},
)

setuptoolsの為のファイル。

インストール

setup.pyのあるディレクトリで、

python setup.py develop

を実行。developを指定すると開発用インストール。python/site-packages以下にリンクが張られて、以降setup.pyを再実行する必要がなくなる・・・らしい。

Trac再起動

今回はTracdを使っているので、それを再起動する。自分はkill -9でshutdownしているけど、他に良い方法あるのかな??

Pluginを有効にする。

TracにAdmin権限を持つユーザでログインし、WebAdminより有効にする。

「Apply Changes」ボタンを押すと、500エラーになってしまうが、慌てず騒がず

trac-admin <Tracプロジェクト・ディレクトリパス> upgrade

を実行。プラグインなどがTrac環境を変更した場合は、これが必要になるらしい。

以上!

これでカスタムチケットが追加された。カンタンカンタン。


Tracpythonについてはまだまだ分からんことだらけだけど、他のpluginの見様見真似で結構作れそう。


次はカスタムレポートを作成してみる予定。