ラベル Trac の投稿を表示しています。 すべての投稿を表示
ラベル Trac の投稿を表示しています。 すべての投稿を表示

火曜日, 7月 15, 2008

Trac-0.11ja出ましたね

待ってましたよ。 先週くらい?にリリースされてたのは知っていて、 会社では試験的にWindows上に構築してみたんですが、 いかんせんそんなに遊ぶ?暇はないので・・・ これから、自宅でFedora9+Subversion1.5.0+Apache2.2.xで環境を構築してみようと思います。 残念ながらFedora9のyumではsubversionは1.4.7なんで、 ソースから普通にmakeしました。 (パッケージ管理的に考えるとソースから作るのは僕は否定的ではあるんですが・・・まぁ、しゃーないですね。) また、SELinuxとかで訳がわからなくなっていくんだろうなぁ~ 今回はバックエンドDBにPostgresは使わない方向で行ってみます。 そもそも、Postgresqlにする必要性も無いんじゃないの?ってところがあるからです。 以前、ムキになってやってたんですが、 「そもそも、バックエンドのデータを直接操作するのって、ルール違反じゃね?」 っていう思いがずっと溜まっていたのがあるんですよね。 そりゃ、直接操作すれば楽なんですけど、 しっかりしたTracのインターフェースを介して操作する方がもっともなアプローチだと思うので sqliteを使うようにします。 さぁ、いつできるかな??

土曜日, 6月 28, 2008

Trac用メモ

Apache上でTracを動かすときのSELinuxのラベル設定 Tracのプラグインのキャッシュディレクトリのドメインは http_tmp_t 普通のtemp_tとは違うんですね。。。 一つ勉強になりました。

火曜日, 6月 24, 2008

いつの間にかTrac0.11のRCが取れたのがリリースされてる

ちょっと、mod_wsgiってのがどんなものなのか?ってのが気になって Tracをダウンロードしてこようと思ったら、 Trac 0.11RC2じゃなくなってる!! RCってのは「Release Candidate」ってことね。もうチョイで正式に。。。ってニュアンスで受け取ってるけど問題ないのかな??? で、入れて少し動かしてみる。。。 当然だけど全部英語だ。。。 しかし、Genshiを使ったテンプレートってどんなもんなんだろ? yumで入れようとするとClearSilverがくっついてくるので、 腹立たしくてeasy_install trac==0.11で入れてみたんですが、 まぁ、ぼちぼち触りながら感触を確かめてみるか。

火曜日, 6月 17, 2008

飼殺し

何か物騒なタイトルになっちゃったけど、 現在の僕の職場での状況がまさにそれに該当してます。。。 契約した案件にストップがかかってしまって余剰人員その1となってしまっています。。。 上の人もそのあたりは重々承知のはずなんだけどねぇ~ 簡単なお手伝いでも良いんで何か僕にお題を下さい。 まぁ、お金は出るんで問題ないと言えば問題ないんですけど。。。 やることが無くなってきて どうしたもんかと色々考えてます。 この時間を利用してもっとも僕にとってプラスになることを考えてみるが、 イマイチ「これだー!!」っていうのは思いつけない。。。 今日はとりあえずEclipseLinkのWikiが結構まとまってきていたので、 それを元に実験でもしてみるかぁ~と思っていたんですが、 もう、集中力なんか保てるわけもなく、眠いこと眠いこと。。。 「ぼぉ~」としながらcvs2svnのスクリプトを流してみたりしてました。 cvs2svnのスクリプトは昔も使ったことがあったので、楽勝だと思っていたんですが、 困ったことにコンバートするのに時間がかかりすぎて使用しているPCのCPUが100%になったまま。。。 とりあえず、プロセスの優先度を通常以下にして他のこと(まぁ、Web見るくらいですけど。。。)をこなしてた。 今日中に終わりそうな気がしなかったので、ほったらかしにして帰ってきてやった。 なんで、Revのsort処理に何時間もかかるんだ?? まぁ、結果は明日行ったらわかるだろう。。。

火曜日, 6月 10, 2008

CTUのFW設定が。。。

VMServerの絡みでプライベートアドレスのBクラスレベルまでをあれこれ操作しないとうまくいかないってことがわかった。。。 めんどくせー とりあえず、自由に使えるサーバとして考えてDDNSも取ったんだけど。。。 内部ネットワークがうまく機能してくれないと、 何も始められないよ。。。 せっかくTrac0.11でも入れてGenshiだっけ? ClearSilverで散々な目にあってるだけにjQueryを使ってるテンプレートエンジンであるGenshiに期待してるんですけど。。。 あれで日本語用にちょこちょこっとテンプレートのインターフェースを操作しようと考えていたのに。。。 とりあえず、nfsが動いてくれないことにはどうしようもないよね。。。 あえて、nfsを使わずにrsyncで同期を取るというのも一つの手なのかもしれない。。。 もしもの場合にはそっち方向で考えてみるか。。。

土曜日, 6月 07, 2008

TracAPIを使ったSubversionコミットメール

昨日のやつをもう少し精査してみました。 trac-post-commit-hook.pyを少しいじって(いじる場所はちょっと前に書いてます。) とりあえず、作ったのは
  • trac.svn.notification.py
  • postcommit_notify_email.cs
の2つです。 .csはClearSilverのテンプレートだそうだ。 ソースはこんな感じ まずはtrac.svn.notification.py
# -*- coding: utf-8 -*-

# Copyright (C) 2003-2006 Edgewall Software
# Copyright (C) 2003-2005 Daniel Lundin 
# Copyright (C) 2005-2006 Emmanuel Blot 
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author:gara
#

from trac import __version__
from trac.config import *
from trac.core import *
from trac.notification import NotifyEmail
from trac.util.datefmt import format_datetime
from trac.util.text import CRLF, wrap
from trac.versioncontrol.api import NoSuchChangeset
from trac.versioncontrol.diff import unified_diff
from trac.mimeview.api import is_binary
import md5

_kindmap = {'dir':u"ディレクトリ", 'file':u"ファイル"}
_actionmap = {'add': u"追加", 'copy': u"コピー",
            'delete': u"削除", 'edit': u"更新",
            'move': u"移動"}

logfile = "postcommit_notification.log"
LOG = True

if LOG:
  f = open (logfile, "w")
  f.write("Begin Log\n")
  f.close()
  def log (s, *params):
      f = open (logfile, "a")
      f.write(s % params)
      f.write("\n")
      f.close()
else:
  def log (s, *params):
      pass

class PostCommitNotificationSystem(Component):

  always_notify_owner = BoolOption('notification', 'always_notify_owner',
                                   'false',
      u"""チケットの担当者に常に通知メールを送信するかを設定します (''0.9 以降'') 。""")

  always_notify_reporter = BoolOption('notification', 'always_notify_reporter',
                                      'false',
      u"""''報告者'' フィールドにあるアドレスに常に通知メールを
      送信するかを設定します。""")

  always_notify_updater = BoolOption('notification', 'always_notify_updater',
                                     'true',
      u"""チケットの属性の変更者に常に通知メールを
      送信するかを設定します。""")


class PostCommitNotifyEmail(NotifyEmail):
  """Subversionのコミット情報をメール送信"""

  template_name = "postcommit_notify_email.cs"
  from_email = 'trac+ticket@localhost'
  COLS = 75

  def __init__(self, env):
      self.env = env
      self.repos = self.env.get_repository()
      self.repos.sync()
      NotifyEmail.__init__(self, env)
      self.prev_cc = []

  def notify(self, rev):
      self.rev = rev
      try:
          chgset = self.repos.get_changeset(rev)
      except NoSuchChangeset:
          return # キャッシュされているチェンジセットの値からはみ出ている
      self.chgset = chgset
      self.message = wrap(self.chgset.message,
                                       self.COLS, initial_indent=' ',
                                       subsequent_indent=' ', linesep=CRLF)
      self.reporter = ''
      self.owner = ''
      subject = self.format_subj()
      link = self.env.abs_href.changeset(self.rev)
      self.link = link
      self.hdf.set_unescaped('email.subject', subject)
      self.hdf.set_unescaped('email.commit.author', self.chgset.author)
      self.hdf.set_unescaped('email.commit.date', format_datetime(self.chgset.date))
      self.hdf.set_unescaped('email.commit.diff', self.unified_diff())
      self.hdf.set_unescaped('email.commit.message', self.message)
      self.hdf.set_unescaped('email.commit.link', self.link)
    
      NotifyEmail.notify(self, self.rev, subject)

  def get_recipients(self, rev):
      notify_reporter = self.config.getbool('notification',
                                            'always_notify_reporter')
      notify_owner = self.config.getbool('notification',
                                         'always_notify_owner')
      notify_updater = self.config.getbool('notification',
                                           'always_notify_updater')

      ccrecipients = self.prev_cc
      torecipients = []

      return (torecipients, ccrecipients)

  def format_subj(self):
      prefix = self.config.get('notification', 'smtp_subject_prefix')
      if prefix == '__default__':
          prefix = '[%s]' % self.config.get('project', 'name')
      if prefix:
          return '%s rev:%s' % (prefix, self.rev)
      else:
          return 'rev:%s' % (self.rev)

  def get_message_id(self, rcpt, modtime=0):
      """Generate a predictable, but sufficiently unique message ID."""
      s = '%s.%08d.%d.%s' % (self.config.get('project', 'url'),
                             int(self.rev), self.chgset.date,
                             rcpt.encode('ascii', 'ignore'))
      dig = md5.new(s).hexdigest()
      host = self.from_email[self.from_email.find('@') + 1:]
      msgid = '<%03d.%s@%s>' % (len(s), dig, host)
      return msgid

  def send(self, torcpts, ccrcpts):
      dest = self.reporter or 'anonymous'
      hdrs = {}
      hdrs['X-svn-changeset-ID'] = str(self.rev)
      msgid = self.get_message_id(dest)
      hdrs['In-Reply-To'] = msgid
      hdrs['References'] = msgid
      NotifyEmail.send(self, torcpts, ccrcpts, hdrs)

  def unified_diff(self):
      txt = CRLF
      try:
          chgset = self.repos.get_changeset(self.rev)
      except NoSuchChangeset:
           return # out of scope changesets are not cached
      for set in chgset.get_changes():
          lst = list(set)
          path = list(set)[0]
          kind = list(set)[1]
          change = list(set)[2]
          base_path = list(set)[3]
          base_rev = list(set)[4]
          if kind != u"file":
              continue
          if change == u"add":
              continue
          elif change == u"delete":
              continue
          elif change == u"move":
              continue
          elif change == u"copy":
              continue
          new_node = self.repos.get_node(path, chgset.rev)
          old_node = self.repos.get_node(base_path, base_rev)
          txt += CRLF
          txt += u"diff: " + path + CRLF
          line = "%s %s %s" % (_actionmap.get(change), _kindmap.get(kind), path)
          txt += wrap(line, self.COLS, linesep=CRLF) + CRLF
          txt += wrap(u"Unified Diff--------------------------------------------------------------", self.COLS, linesep=CRLF) + CRLF
          new_content = new_node.get_content().read()
          old_content = old_node.get_content().read()
          if is_binary(new_content) or is_binary(old_content):
              txt += u"(バイナリファイルが異なっています)" + CRLF
              continue

          txt += wrap(u"--- %s (リビジョン %s)" % (base_path, base_rev), self.COLS, linesep=CRLF) + CRLF
          txt += wrap(u"+++ %s (リビジョン %s)" % (path, chgset.rev), self.COLS, linesep=CRLF) + CRLF
          context = 3
          options = ['-U%d' % -1]
          options.append('-B')
          options.append('-i')
          options.append('-b')
          for option in options:
              if option.startswith('-U'):
                  context = int(option[2:])
                  break
          for line in unified_diff(old_content.splitlines(),
                                new_content.splitlines(), context,
                                    ignore_blank_lines='-B' in options,
                                    ignore_case='-i' in options,
                                    ignore_space_changes='-b' in options):
              txt += wrap(line, self.COLS, linesep=CRLF) + CRLF

      return txt
そんでもってpostcommit_notify_email.cs
更新 (更新者: <?cs var:email.commit.author ?>):
更新日時: <?cs var:email.commit.date ?>

コメント:
<?cs var:email.commit.message ?>
<?cs var:email.commit.diff ?>
--
Commit URL: <<?cs var:email.commit.link ?>>
<?cs var:project.name ?> <<?cs var:project.url ?>>
<?cs var:project.descr ?>
こんなんでも、誰かの参考になれば。。。 いいなw

ありゃ?日付が変わってる。。。

以前、TracでSubversion側からチケット更新を行った場合にメールを飛ばそうとしていたんですが、 細かく整理するとやりたいことは以下のようなことになります。
  1. Trac上でチケットの編集 ⇒こりゃ既存の機能っすね
  2. Subversion上でコミット ⇒これだけで考えれば、そんなに難しくないと思う
  3. Subversion上でコミットしてコミットメッセージ内にチケットを操作するコマンドを埋め込む
この3に関しては、何も考えずに1と2を用意すると チケットの更新メール + Subversionのコミットメール の2通が飛んでくる。。。 内容は同じなのにそりゃ邪魔だろということで、 3のパターンのときにはTracサイドのチケット更新メールにSubversionのコミット情報を埋め込む方向でモジュールを作り始めた。 せっかくなので、2についてもtracパッケージで用意されているパッケージ群を使って送れるとおもしろいかなぁ~と思って、早速作ってみた!
# -*- coding: utf-8 -*-

# Copyright (C) 2003-2006 Edgewall Software
# Copyright (C) 2003-2005 Daniel Lundin 
# Copyright (C) 2005-2006 Emmanuel Blot 
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author:がら
#

from trac import __version__
from trac.config import *
from trac.core import *
from trac.notification import NotifyEmail
from trac.util.datefmt import format_date
from trac.util.text import CRLF, wrap
from trac.versioncontrol.api import NoSuchChangeset
from trac.versioncontrol.diff import unified_diff
import md5



_kindmap = {'dir':u"ディレクトリ", 'file':u"ファイル"}
_actionmap = {'add': u"追加", 'copy': u"コピー",
           'delete': u"削除", 'edit': u"更新",
           'move': u"移動"}

logfile = "postcommit_notification.log"
LOG = True

if LOG:
 f = open (logfile, "w")
 f.write("Begin Log\n")
 f.close()
 def log (s, *params):
     f = open (logfile, "a")
     f.write(s % params)
     f.write("\n")
     f.close()
else:
 def log (s, *params):
     pass

class PostCommitNotificationSystem(Component):

 always_notify_owner = BoolOption('notification', 'always_notify_owner',
                                  'false',
     u"""チケットの担当者に常に通知メールを送信するかを設定します (''0.9 以降'') 。""")

 always_notify_reporter = BoolOption('notification', 'always_notify_reporter',
                                     'false',
     u"""''報告者'' フィールドにあるアドレスに常に通知メールを
     送信するかを設定します。""")

 always_notify_updater = BoolOption('notification', 'always_notify_updater',
                                    'true',
     u"""チケットの属性の変更者に常に通知メールを
     送信するかを設定します。""")


class PostCommitNotifyEmail(NotifyEmail):
 """Subversionのコミット情報をメール送信"""

 template_name = "postcommit_notify_email.cs"
 from_email = 'trac+ticket@localhost'
 COLS = 75

 def __init__(self, env):
     self.env = env
     self.repos = self.env.get_repository()
     self.repos.sync()
     NotifyEmail.__init__(self, env)
     self.prev_cc = []

 def notify(self, rev):
     self.rev = rev
     try:
         chgset = self.repos.get_changeset(rev)
     except NoSuchChangeset:
         return # キャッシュされているチェンジセットの値からはみ出ている
     self.chgset = chgset
     self.message = wrap(self.chgset.message,
                                      self.COLS, initial_indent=' ',
                                      subsequent_indent=' ', linesep=CRLF)
     self.reporter = ''
     self.owner = ''
     self.hdf.set_unescaped('email.commit_body_hdr', self.format_hdr())
     subject = self.format_subj()
     link = self.env.abs_href.changeset(self.rev)
     self.hdf.set_unescaped('email.subject', subject)
     self.hdf.set_unescaped('email.commit.author', self.chgset.author)
     self.hdf.set_unescaped('email.commit.date', format_date(self.chgset.date))
     self.hdf.set_unescaped('email.commit.change_paths', self.change_paths())
     self.hdf.set_unescaped('email.commit.diff', self.unified_diff())
     self.hdf.set_unescaped('email.commit.message', self.message)
  
     self.link = link
     NotifyEmail.notify(self, self.rev, subject)

 def format_hdr(self):
     txt = ""
     for set in self.chgset.get_changes():
         lst = list(set)
         path = list(set)[0]
         kind = list(set)[1]
         change = list(set)[2]
         base_path = list(set)[3]
         base_rev = list(set)[4]
         txt += "[%s]: %s" % (self.rev, wrap(path,
                              self.COLS, linesep=CRLF))
     return txt

 def get_recipients(self, rev):
     notify_reporter = self.config.getbool('notification',
                                           'always_notify_reporter')
     notify_owner = self.config.getbool('notification',
                                        'always_notify_owner')
     notify_updater = self.config.getbool('notification',
                                          'always_notify_updater')

     ccrecipients = self.prev_cc
     torecipients = []

     return (torecipients, ccrecipients)

 def format_subj(self):
     prefix = self.config.get('notification', 'smtp_subject_prefix')
     if prefix == '__default__':
         prefix = '[%s]' % self.config.get('project', 'name')
     if prefix:
         return '%s [%s]' % (prefix, self.rev)
     else:
         return '[%s]' % (self.rev)

 def get_message_id(self, rcpt, modtime=0):
     """Generate a predictable, but sufficiently unique message ID."""
     s = '%s.%08d.%d.%s' % (self.config.get('project', 'url'),
                            int(self.rev), self.chgset.date,
                            rcpt.encode('ascii', 'ignore'))
     dig = md5.new(s).hexdigest()
     host = self.from_email[self.from_email.find('@') + 1:]
     msgid = '<%03d.%s@%s>' % (len(s), dig, host)
     return msgid

 def send(self, torcpts, ccrcpts):
     dest = self.reporter or 'anonymous'
     hdrs = {}
     hdrs['X-svn-changeset-ID'] = str(self.rev)
     hdrs['X-svn-changeset-URL'] = self.link
     msgid = self.get_message_id(dest)
     hdrs['In-Reply-To'] = msgid
     hdrs['References'] = msgid
     NotifyEmail.send(self, torcpts, ccrcpts, hdrs)

 def unified_diff(self):
     txt = ""
     try:
         chgset = self.repos.get_changeset(self.rev)
     except NoSuchChangeset:
          return # out of scope changesets are not cached
     for set in chgset.get_changes():
         lst = list(set)
         path = list(set)[0]
         kind = list(set)[1]
         change = list(set)[2]
         base_path = list(set)[3]
         base_rev = list(set)[4]
         if kind != u"file":
             continue
         if change == u"add":
             continue
         elif change == u"delete":
             continue
         elif change == u"move":
             continue
         elif change == u"copy":
             continue
         new_node = self.repos.get_node(path, chgset.rev)
         old_node = self.repos.get_node(base_path, base_rev)
         new_content = new_node.get_content().read()
         old_content = old_node.get_content().read()
         txt = wrap("", self.COLS, linesep=CRLF)
         txt += u"diff: %s" % wrap(path, self.COLS, linesep=CRLF)
         txt += wrap(u"------------------------", self.COLS, linesep=CRLF)
         txt += wrap(u"--- %s (リビジョン %s)" % (base_path, base_rev), self.COLS, linesep=CRLF)
         txt += wrap(u"+++ %s (リビジョン %s)" % (path, chgset.rev), self.COLS, linesep=CRLF)
         context = 3
         options = ['-U%d' % -1]
         options.append('-B')
         options.append('-i')
         options.append('-b')
         for option in options:
             if option.startswith('-U'):
                 context = int(option[2:])
                 break
         for line in unified_diff(old_content.splitlines(),
                               new_content.splitlines(), context,
                                   ignore_blank_lines='-B' in options,
                                   ignore_case='-i' in options,
                                   ignore_space_changes='-b' in options):
             txt += wrap(line, self.COLS, linesep=CRLF)

     return txt

 def change_paths(self):
     txt = ""
     try:
         chgset = self.repos.get_changeset(self.rev)
     except NoSuchChangeset:
          return # out of scope changesets are not cached
     for set in chgset.get_changes():
         lst = list(set)
         path = list(set)[0]
         kind = list(set)[1]
         change = list(set)[2]
         base_path = list(set)[3]
         base_rev = list(set)[4]
         line = "%s %s %s" % (_actionmap.get(change), _kindmap.get(kind), path)
         txt += wrap(line, self.COLS, linesep=CRLF)
      
     return txt
うーん、正直まだ未完成。。。 叩き台ができたってところかな? 基本的にTracの設定に準拠して動かそうと思っているのでこんな感じかな?と思っています。 しかし、Pythonってなかなかデバックしにくい。。。 そう思うのは僕だけかな?

木曜日, 6月 05, 2008

とりあえず、SELinuxをオフにしなくてもTracが動くようになりました

やっとできた。。。 初めから真面目に $ man audit2allow で調べとけばよかった。。。 manで見た中で例があげらっれており、以下のような文面だった。
EXAMPLE
      NOTE: These examples are for systems using the audit package. If you do
      not use the audit package, the AVC messages will be in /var/log/messages.
      Please substitute /var/log/messages for /var/log/audit/audit.log in the
      examples.

      Using audit2allow to generate monolithic (non-module) policy
     $ cd /etc/selinux/$SELINUXTYPE/src/policy
     $ cat /var/log/audit/audit.log | audit2allow >> domains/misc/local.te
     $ cat domains/misc/local.te
     allow cupsd_config_t unconfined_t:fifo_file { getattr ioctl };
     
     $ make load

     Using audit2allow to generate module policy

     $ cat /var/log/audit/audit.log | audit2allow -m local > local.te
     $ cat local.te
     module local 1.0;

     require {
             role system_r;

             class fifo_file {  getattr ioctl };

             type cupsd_config_t;
             type unconfined_t;
      };

     allow cupsd_config_t unconfined_t:fifo_file { getattr ioctl };
     

     Building module policy manually

     # Compile the module
     $ checkmodule -M -m -o local.mod local.te
     # Create the package
     $ semodule_package -o local.pp -m local.mod
     # Load the module into the kernel
     $ semodule -i local.pp

     Using audit2allow to generate and build module policy
     $ cat /var/log/audit/audit.log | audit2allow -M local
     Generating type enforcment file: local.te
     Compiling policy: checkmodule -M -m -o local.mod local.te
     Building package: semodule_package -o local.pp -m local.mod

     ******************** IMPORTANT ***********************

     In order to load this newly created policy package into the kernel,
     you are required to execute

     semodule -i local.pp
そこで、最終的にこんな具合にやってみた。
$ mkdir /etc/selinux/targeted/src $ mkdir /etc/selinux/targeted/src/policy $ cd /etc/selinux/targeted/src/policy $ audit2allow -d -m local > local.te $ checkmodule -M -m -o local.mod local.te $ semodule_package -o local.pp -m local.mod $ semodule -i local.pp
こんな感じでPermmision系のエラーが出る度に さっきのコマンドをくりかえし、 $ semodule -R で再読み込みをさせていく形で とりあえず、Tracが動くように。。。 こんなやり方でええのかなぁ~

日曜日, 6月 01, 2008

selinuxとTrac

Apacheで動かしているんですが、 selinuxのラベル設定が思いのほかうまくいかず。困っていたんです。。。 しかし、こんなに簡単に済むとは思ってもいませんでした。
chcon -R --reference=/var/www/html /var/trac/
これで、いいんだろうか。。。?

水曜日, 5月 28, 2008

[Trac]Timing and Estimation Pluginのpost-commit-hookではメールが飛ばない!?そして解決

Timing and Estimation Pluginのpost-commit-hookを 普通に信じて使おうとしていたんですが、

Tracのpost-commitでメールが飛ばないよ~

って状況になっていたんですが、 やっとこさ解決した。 (というか、スクリプトをバリバリ改造してみた。) オリジナルではそのまま送信しようとすると env.abs_hrefなんて属性は無いぞ!!って怒られてたんですが、 従来のtrac-0.10.3.1-ja-2.zipに付いていたtrac-post-commit-hookでenv.abs_hrefを設定している部分を発見した。 そこで、さっそくそのあたりのコードを移植してみた。 こんな感じ
--- trac-post-commit.py.org Wed May 28 13:05:22 2008
+++ trac-post-commit.py Wed May 28 13:14:35 2008
@@ -103,6 +103,7 @@
from trac.ticket.web_ui import TicketModule
# TODO: move grouped_changelog_entries to model.py
from trac.versioncontrol.api import NoSuchChangeset
+from trac.web.href import Href

logfile = "/var/trac/commithook.log"
LOG = False
@@ -193,6 +194,10 @@
       self.rev = rev
       self.msg = "(In [%s]) %s" % (rev, chgset.message)
       self.now = int(time.time())
+        if url is None:
+            url = self.env.config.get('project', 'url')
+        self.env.href = Href(url)
+        self.env.abs_href = Href(url)

       cmd_groups = command_re.findall(self.msg)
       log ("cmd_groups:%s", cmd_groups)
最近になってユニファイド形式のdiff情報が便利だということにやっと気が付きました。。。 これで、Subversionサイドでコミットした際にコマンドがメッセージに記述されていたら、 チケットにコミットログを書き込みして、チケットの変更上をメールで送信することまでできるようになります。 しかし、これだけだとあくまでチケットが更新されたというメールしか飛びません。 (要はメッセージ内にこのスクリプトに反応するコマンドが書き込まれていないとメールなんて飛んでこない) そこで、メールを送信するスクリプトを作ってみた。 ※特殊文字が含まれると落ちちゃいます。。。 だめじゃん。。。 ※ちなみにWindows環境下で作っているんで、pathとかは適当に見直したほうがいいと思います。
#!D:/Tools/Trac/Python24/python.exe
# -*- coding: utf-8 -*-
# needs: nkf, head

import re
import sys
import popen2
import smtplib

smtpserver = 'xxx.xxx.xxx.xxx'
fromaddr = '○○○○○○'
maxdiffsize = 80000  # in bytes
repo_url = 'http://utsuutsu/projects/repo/changeset/'
_svnlook = 'D:/Subversion/bin/svnlook.exe'

logfile = "D:/Trac/projects/trac/log/mailsender.log"
LOG = True

if LOG:
  f = open (logfile,"w")
  f.write("Begin Log\n")
  f.close()
  def log (s, *params):
      f = open (logfile,"a")
      f.write(s % params)
      f.write("\n")
      f.close()
else:
  def log (s, *params):
      pass

def fromSJIStoISO2022JP(s):
  u = unicode(s,'japanese.shift_jis','replace')
  return u.encode('japanese.iso-2022-jp')

def fromUTF8toISO2022JP(s):
  u = unicode(s,'utf_8','replace')
  return u.encode('japanese.iso-2022-jp')

class CommitMailSender:

  def __init__(self, repo, rev):
      self.repo = repo
      self.rev = rev

      conffile = popen2.popen2(_svnlook + ' cat %s -r %s' % (self.repo, self.rev))[0].read().splitlines()
      changed = popen2.popen2(_svnlook + ' changed %s -r %s' % (self.repo, self.rev))[0].read().strip()

      log('%s' % (repo))
      log('%s' % (rev))
      log('%s' % (conffile))
      log('%s' % (changed))

      # changed     ->   pathlist
      # ------------------------
      # U    file1\n
      # U    file2\n    ['file1','file2']
      #
      pathlist = [l.split()[1] for l in changed.splitlines()]
      if log:
          for l in pathlist:
              log('path=%s' % (l))

      to = []
      to += ['xxx@utsuutsu']

      # decide who to send
      for line in conffile:
          lines = line.strip().split()
          if len(lines) < rule =" lines[0]" addrs =" lines[1:]" rule="%s" rule ="=" addrs ="=" path="%s" rule="%s" _author =" popen2.popen2(_svnlook" _author =" fromSJIStoISO2022JP(_author)" _date =" popen2.popen2(_svnlook" _date =" fromSJIStoISO2022JP(_date)" _log =" popen2.popen2(_svnlook" _log =" fromSJIStoISO2022JP(_log)" _changed =" popen2.popen2(_svnlook" _changed =" fromSJIStoISO2022JP(_changed)" _diff =" popen2.popen2(_svnlook" _diff =" fromSJIStoISO2022JP(_diff)" project_name =" fromUTF8toISO2022JP('プロジェクト名')" author_title =" fromUTF8toISO2022JP('更新者')" date_title =" fromUTF8toISO2022JP('日時')" log_title ="fromUTF8toISO2022JP('ログ')" changed_title =" fromUTF8toISO2022JP('変更箇所')" msg =" (">
reply-to: xxx@utsuutsu
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit
Subject: [%s] Revision:%s commit

[%s] Revision:%s commit to %s
%s:%s
%s:%s

%s:
%s

%s:
%s

diff:  (up to %d bytes)
------------------------
%s
""" % (project_name, rev, project_name, rev, repo_url+rev, author_title, _author, date_title, _date, log_title, _log, changed_title, _changed, maxdiffsize, _diff)
      )


      # send!!
      mail = smtplib.SMTP(smtpserver)
      mail.sendmail(fromaddr, to, msg)
      mail.quit()

      log(str(to))
これをさっきのtrac-post-commit.pyでコマンドが無い場合のみ呼び出すようにします。
--- trac-post-commit.py.org Wed May 28 13:27:19 2008
+++ trac-post-commit.py Wed May 28 13:28:32 2008
@@ -104,6 +104,7 @@
# TODO: move grouped_changelog_entries to model.py
from trac.versioncontrol.api import NoSuchChangeset
from trac.web.href import Href
+from CommitMailSender import CommitMailSender

logfile = "/var/trac/commithook.log"
LOG = False
@@ -200,6 +201,9 @@
       self.env.abs_href = Href(url)

       cmd_groups = command_re.findall(self.msg)
+        # 追加
+        if len(cmd_groups) == 0:
+            CommitMailSender(url, rev)
       log ("cmd_groups:%s", cmd_groups)
       tickets = {}
       for cmd, tkts, xxx1, xxx2 in cmd_groups:
しかし、思いつきで作った割りにはしっかり動いているじゃないかw

火曜日, 5月 27, 2008

selinuxとNFS

ただいま、NFSでVM上でゲストのディスクを全てホスト側から提供する形で Tracの環境を作っています。 とりあえず、作るには作ったんですが、 selinuxが邪魔して動いてくれないんです。。。 どうも、調べてみるとmountコマンドにオプションでcontext=ラベルでマウント時に ラベルが変更できるとか。。。 情報元はFedoraCore3のドキュメントなんですけどね。。。 他にも同じようなことが載ってるサイトがあったんですが、 Patchの文字が。。。 いやだー!! もしかしたらオプションの種類かmountのユーティリティとかが無いかもう少し調べてみることにしよう。

金曜日, 5月 23, 2008

Tracのpost-commitでメールが飛ばないよ~

仕事場で使っているTracにpost-commitのフックスクリプトを導入してみた。 最初は「おぉーチケットにきちんとコミットメッセージが載ってる~♪」って調子だったが、 ふと気がついた、うちの環境ではチケットの更新時にメールを飛ばしているのだが、 何でかpost-commitで更新したチケットはメールが飛ばない。。。 ということで、調べてみることにしてみたんですが、 また、Pythonだよ。。。 どうやら、チケットの情報を更新(insert)してcommitした後に メールを飛ばすようになっていることには気がついたんですが、 そこで、Enviromentオブジェクトにabs_hrefという属性が無いよ~とエラーがでてる。。。 とりあえず、無理やりenv.abs_hrefに値を格納して 「これでどうだ!!」とやってみたんですが、 さらなるエラーが。。。 unicodeオブジェクトにticketという属性が無いですよ~というエラーが。。。 というかunicodeってどういうことですか?? 全く分んないよ。。。 もう少しPythonを勉強しないことには何ともできないなぁ~と思った。 結局、未解決。。。

金曜日, 5月 16, 2008

こうして一週間が過ぎていく

結局、来週の予定は決まらずじまいで終わってしまった。。。 やったことといえば、やるのか?やらないのか?よくわからん基本設計をちょこっとだけ。 ただ、昨日Doxygenでハマっていた部分は解消した!! (あんまり仕事とは関係ないんですが。。。) iconvのソースを昨日のminwgではなくcygwinでビルドしてみました。 iconv.exeがでけたー!! しかし、これホントにいるのかなぁ~?? iconvのソースやドキュメントを読んでいたら、 どこにもShift_JISなんて記述がない。。。 でもって、ふと気がついたMS932もといCP932なら。。。 あ、ありましたよ!! それで、doxygenの設定ファイルを書き換えると、 無事にShift_JISソース→UTF-8のドキュメント生成に成功しました!! どこを探しても情報が見つからなかったので、かなり思いつきでやってみたんですが、これで良かったのかな?

failed to read qemu headerのときのメモ

かなり久々。。。 忘れないようにここに書きこんでおく。 ちょっとした手違いで libvirtでイメージを起動しようとすると failed to read qemu header なんておっしゃられて起動しない。。。 vmwareserverを使って...