2007年9月26日星期三

練習寫 TracMacro - [[TicketStatus]]

練習寫 TracMacro - [[TicketStatus]]

因為我們常要寫 wiki page 以便追蹤專案的進度、列出待辦事項等等,由於在 Trac 裡寫 #1 只會顯示 ticket number,往往我們必須要手動把 ticket summary 加在後面,當 ticket 有所變動時,wiki 與 ticket 兩邊就會不同步,維護起來非常麻煩。所以剛剛練習寫了一個 WikiMacro,取名為 TicketStatus.py,列出 ticket number、summary、status 與 owner,開會時一打開,所有事情一目了然。

WikiMacro 不難寫,不過因為我不太熟 python,所以 比較麻煩的地方在於怎樣抓取資料。可能是由於 dynamic language 的特性,很難直接從原始碼追蹤,了解手上可以用的參數,其型別與屬性分別可以輾轉得到哪些資料。不過這對熟悉 python programming 的人,應該不是問題。因為多半有現成的工具,如 ipython 等,幫助我們直接取得、分析、追蹤整個物件結構。

TicketStatus.py 的原始碼如下:

"""
Display status and summaries of specified ticket numbers. Useful for listing
TODOs.

Example:
{{{
[[TicketStatus(#1,#7,#31)]] ... list of tickets
[[TicketStatus(1,7,31)]] ... '#' char can be omitted
}}}
"""


import re
import string

def uniq(x):
y
= []
for i in x:
if not y.count(i):
y
.append(i)
return y

args_pat
= [r"#?(?P\d+)",]

def execute(hdf, args, env):
items
= []
args_re
= re.compile("^(?:" + string.join(args_pat, "|") + ")___FCKpd___0quot;)
for arg in [string.strip(s) for s in args.split(',')]:
match = args_re.match(arg)
if not match:
env.log.debug('TicketStatus: unknown arg: %s' % arg)
continue
elif match.group('tktnum'):
items.append(int(match.group('tktnum')))
items = uniq(items)

db = env.get_db_cnx()
cursor = db.cursor()
sql = "
SELECT id, summary, status, resolution, owner FROM ticket WHERE id IN (%s)" % (string.join(['%d' % c for c in items], ', '))
cursor.execute(sql)
html = ''
for (tkt_id, tkt_summary, tkt_status, tkt_resolution, tkt_owner) in cursor:
html += '1">'
try:
# for trac 0.9 or later
from trac.wiki.formatter import wiki_to_oneliner
html += wiki_to_oneliner(('#%d' % tkt_id), env, env.get_db_cnx())
except:
# for trac 0.8.x
from trac.WikiFormatter import wiki_to_oneliner
html = wiki_to_oneliner(('#%d' % tkt_id), hdf, env, env.get_db_cnx())
html += ''
status = tkt_status
if status == 'closed':
status = tkt_resolution
html += '1">%s1">%s%s' % (status, tkt_owner, tkt_summary)
html += ''
html = 'ticketstatus wiki" width="90%%">\n\n%s\n\n
' % html
return html

當一行太長時,我搞不清楚 python 縮排的條件是什麼,所以只好請大家將就點,往右捲來看。

用起來很簡單,把 ticket numbers 當參數傳進去即可,如:[[TicketStatus(#1,#2)]]。顯示效果如下:

使用說明如下:


理論上 trac 應該要有提供 API,讓我們可以靠 ticket number 就取得其他的屬性,不過因為前述的理由,所以最終我還是直接對 sqlite database 下 query。這其實是不太好的作法,不過黔驢技窮,那也沒辦法了。:-p

Updated (2007-08-23):

印出來的 html,應該要先把 &、<、>、"、' 等代換成對應的 html entities 才行。修改如下:

  1. 新增 htmlspecialchars 函式[1]

    def htmlspecialchars(s):
    s
    = re.sub(r'&', r'&', s)
    s
    = re.sub(r'<', r'<', s)
    s
    = re.sub(r'>', r'>', s)
    s
    = re.sub(r'"', r'"', s)
    s
    = re.sub(r'\'', r''', s)
    return s;
  2. 在印出的時候,呼叫 htmlspecialchars 做轉換:

    html += '%s%s%s' % (htmlspecialchars(status), htmlspecialchars(tkt_owner), htmlspecialchars(tkt_summary))

    這一行實在是長到不行,不過沒辦法,python 就是這麼規定的[2]


  1. 就直接學 PHP 的命名吧。:-p
  2. 這大概是我無法對 python 產生熱情的原因之一吧。我已經是個很嚴格要求自己程式縮排規則的人了,python 的限制一加下去,反而正正得負,程式變難看了。
This entry was written by jeffhung and posted on August 7, 2007 at 8:00 pm and filed under Python, SCM. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

没有评论: