sourceforge.net で Trac が動く
動くもんだなーと。ClearSilver (うっかり Silverlight と書きそうになった) だけ CentOS 4.4 でビルドしたのを持ち込み。カラオケいく前にコンビニでつまみを買った、昔のあの罪悪感に似ている。
ハマりポイントは
- sf.net の web サーバに入っている Python モジュールの MySQLdb が connection encoding の判定に mysql_character_set_name() を使っていること。
- sf.net のシェルサーバの libmysqlclient (proto ver=10) が mysql CLI フロントエンド (proto ver=14) の libmysqlclient と異なっており、かつ前者が multibyte charset 対応にビルドされていないこと。
- Python の default character encoding は sys.setdefaultencoding() で設定できるが、これは site モジュールにより起動時に無効にされること。
- mod_rewrite のルールと認証 (basic 認証のみ対応)
1. について、当該関数はサーバ側に問い合わせることをせず、クライアント側のコンテキストの文字コードを返すようにしている。なので SET NAMES などのクエリを発行してもこいつは更新されず、connection encoding がいつまでも latin1 とみなされ、クエリ生成時の変換に失敗する。どうせ UTF-8 しかやりとりされないので、MySQLdb.Connection の conversions リストに types.UnicodeType 対応の UTF-8 決め打ちコンバータを登録する。
2. については、不正なマルチバイト文字列が DB 接続に紛れ込む余地はないので (一旦 decode -> encode するので) みなし latin1 でエスケープしても便宜上問題ない。
3. は import sys したのちに reload(sys) すれば生き返るのでもれなく utf-8 と設定すれば OK。
const char * STDCALL mysql_character_set_name(MYSQL *mysql) { return mysql->charset->csname; }
追記
いくらか興味を持っていただいているようなので。まず、バージョン0.10.4を使いましたが、バックエンドの種類ではまったことはなかったです。MyISAM で問題なく動いています。
文字セットの問題ですが、上には詳細に記述しなかったものの、パッチを当てました。
下記のパッチは 1., と 3. についての修正を含んでいます。
--- trac-0.10.4.orig/trac/db/mysql_backend.py 2007-04-20 22:41:46.000000000 +0900 +++ trac-0.10.4/trac/db/mysql_backend.py 2007-06-29 15:27:36.000000000 +0900 @@ -125,6 +125,8 @@ raise TracError, 'MySQL servers older than 4.1 are not supported!' cnx.query('SET NAMES %s' % charset) cnx.store_result() + cnx.query('SET CHARACTER SET %s' % charset) + cnx.store_result() cnx.charset = charset def __init__(self, path, user=None, password=None, host=None, @@ -145,10 +147,18 @@ if (self._mysqldb_gt_or_eq((1, 2, 1))): cnx = MySQLdb.connect(db=path, user=user, passwd=password, host=host, port=port, charset='utf8') + elif (self._mysqldb_gt_or_eq((1, 1, 0))): + cnx = MySQLdb.connect(db=path, user=user, passwd=password, + host=host, port=port, use_unicode = True, + conv = conv) + self._set_character_set(cnx, 'utf8') else: cnx = MySQLdb.connect(db=path, user=user, passwd=password, - host=host, port=port, use_unicode=True) + host=host, port=port, unicode = 'utf8') self._set_character_set(cnx, 'utf8') + import types + cnx.converter[types.UnicodeType] = lambda u, d: cnx.literal( + u.encode('utf8')) ConnectionWrapper.__init__(self, cnx) self._is_closed = False --- trac-0.10.4.orig/cgi-bin/trac.cgi 2007-10-24 00:42:52.000000000 +0900 +++ trac-0.10.4/cgi-bin/trac.cgi 2007-06-29 16:40:59.000000000 +0900 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (C) 2003-2004 Edgewall Software @@ -16,6 +16,9 @@ # Author: Jonas Borgström <jonas@edgewall.com> try: + import sys + reload(sys) + sys.setdefaultencoding('utf-8') from trac.web import cgi_frontend cgi_frontend.run() except SystemExit:
また、trac.cgi として下記のようなラッパを使っています。
#!/bin/sh GROUP_HOME=`readlink -f \`dirname "$0"\`/..` TRAC_PREFIX="$GROUP_HOME/opt/trac" CLEARSILVER_PREFIX="$GROUP_HOME/opt/clearsilver" DOCUTILS_PREFIX="$GROUP_HOME/opt/docutils" SETUPTOOLS_PREFIX="$GROUP_HOME/opt/setuptools" PYTHONPATH=`echo \$TRAC_PREFIX/lib/python*/site-packages` PYTHONPATH=$PYTHONPATH:`echo \$CLEARSILVER_PREFIX/lib/python*/site-packages` PYTHONPATH=$PYTHONPATH:`echo \$DOCUTILS_PREFIX/lib/python*/site-packages` PYTHONPATH=$PYTHONPATH:`echo \$SETUPTOOLS_PREFIX/lib/python*/site-packages` TRAC_ENV="$GROUP_HOME/var/opt/trac" export PYTHONPATH export TRAC_ENV exec $TRAC_PREFIX/share/trac/cgi-bin/trac.cgi
ちなみにディレクトリ構成は
$GROUP_HOME | +- var | | | +- opt | | | +- trac | | | +- attachments | | | +- conf | | | +- htdocs ($GROUP_HOME/htdocs/chrome/site への symlink) | | | +- log | | | +- plugins | | | +- templates | | | +- wiki-macros | +- opt | +- clearsilver-0.10.4 | +- clearsilver (./clearsilver-0.10.4 への symlink) | +- docutils-0.4 | +- docutil (./docutil-0.4 への symlink) | +- setuptools-0.6c7 | +- setuptools (./setuptools-0.6c7 への symlink) | +- trac-0.10.4 | +- trac (./trac-0.10.4 への symlink)
上記のようになっています。