Trac / レポジトリ生成用 CGI を Mercurial 対応に
以前(⇒ レポジトリ・trac 生成 CGI を作る - daily dayflower)作ったレポジトリ等生成ウェブインタフェースを,Mercurial にも対応するように書き換えました。といっても Trac 0.11b2 用にしてしまったので,0.10 では動きません。一応注釈はいれておいたんで,がんばれば 0.10 用にもできますけど((ほんとは try:
〜except ImportError:
で囲めばいいんですけどね))。
最初は trac.env.Environment
を直接操作してたんですが,デフォルト Wiki ページの生成部分がちょっとひどいことになりそうだったので,以前と同じように標準出力をトラップする形にしてます。このへん(admin 用インタフェース)ももうちょっと整備してほしいところですね。
2008/03/05 追記: デフォルトの Milestone 等がうっとおしいので削除しておくようにしました。
LoadModule wsgi_module modules/mod_wsgi.so WSGIScriptAlias /trac/create /var/www/app/trac_builder.wsgi <Directory /www/main/app> WSGIApplicationGroup %{GLOBAL} SetEnv TracEnvParentDir "/var/www/trac" SetEnv TracReposParentDir "/var/www/repos" Order deny,allow Allow from all </Directory>
みたいな使い方。以前と異なりシングルファイル化したので,mod_python とかの場合は,適宜パッケージとしてインストールしてください。個人的に mod_wsgi に移行してしまったので mod_python ではテストしてません。
# -*- coding: utf-8 -*- import os, sys class TracProject: def create_svn_repo(self, dest): import svn.repos svn.repos.create(dest, '', '', None, None) def create_hg_repo(self, dest): import mercurial.hg as hg import mercurial.ui hg.repository(mercurial.ui.ui(interactive=False, report_untrusted=False), dest, create=1) def create_repository(self, dest, type): if type == 'hg': self.create_hg_repo(dest) else: self.create_svn_repo(dest) def create_trac(self, project_name, project_dir, repository_dir, repository_type): class StreamSweeper: def __init__(self): self.stock = '' def write(self, s): self.stock += s def escape_quot(s): return s.replace('"', '\\"') log_stdout = '' r = 2 sys.stdout, last_stdout = StreamSweeper(), sys.stdout sys.stderr, last_stderr = StreamSweeper(), sys.stderr try: # for Trac 0.10, "from trac.script.admin" from trac.admin.console import TracAdmin import trac.env from trac.ticket.model import * admin = TracAdmin() admin.env_set(project_dir) r = admin.do_initenv('"%s" %s %s "%s"' % ( escape_quot(project_name), 'sqlite:db/trac.db', repository_type, escape_quot(repository_dir), ) ) # need extra 'template' parameter for Trac 0.10 # that can be retrieve from trac.config.default_dir() log_stdout = sys.stdout.stock if not r > 0: env = trac.env.Environment(project_dir) if repository_type == 'hg': env.config.set('components', 'tracext.hg.*', 'enabled') env.config.save() for i in range(1, 2+1): component = Component(env, 'component%d' % (i)) component.delete() for i in range(1, 4+1): milestone = Milestone(env, 'milestone%d' % (i)) milestone.delete() for i in ['1.0', '2.0']: version = Version(env, i) version.delete() #import trac.perm #permsys = trac.perm.PermissionSystem(env) #permsys.grant_permission('anonymous', 'TRAC_ADMIN') finally: sys.stdout, sys.stderr = last_stdout, last_stderr return ( r, log_stdout ) def create(self, project_name, project_dir, repository_dir, repository_type): try: self.create_repository(repository_dir, repository_type) except Exception, e: return ( 1, str(e) ) return self.create_trac(project_name, project_dir, repository_dir, repository_type) import cgi import trac.web.api class TracBuilder: def __init__(self, req): self.req = req self._html_wrapper = """ <html> <head> <title>TracBuilder - %s</title> <style type="text/css"> th { text-align: left; } </style> </head> <body> %s </body> </html> """ self._html_failure = """ <h1>Create Trac Project</h1> <p>Error occured:</p> <pre>%s</pre> """ self._html_success = """ <h1>Create Trac Project</h1> <p>Successfully created:</p> <pre>%s</pre> """ self._html_form = """ <h1>Create Trac Project</h1> <form method="post"> <table> <tbody> <tr> <th>Repository Name</th> <td><input type="text" name="repo" /></td> </tr> <tr> <th>Project Name</th> <td><input type="text" name="project" value="My Project" /></td> </tr> <tr> <th>Repository Type</th> <td> %s </td> </tr> <tr> <th></th> <td><input type="submit" /></td> </tr> </tbody> </table> </form> """ # transform _html_form for repository types repo_types = [ ( 'svn', 'Subversion (svn)' ) ] try: import mercurial.hg repo_types.append( ( 'hg', 'Mercurial (hg)' ) ) except ImportError: pass opts = '' for r in repo_types: checked = '' if r[0] == 'svn': checked = 'checked=" checked"' opts += """ <input type="radio" name="type" id="type-%s" value="%s"%s /> <label for="type-%s">%s</label> <br /> """ % ( r[0], r[0], checked, r[0], r[1] ) self._html_form = self._html_form % ( opts ) def show_failure(self, message = ''): message = cgi.escape(message).encode('utf-8') html = self._html_wrapper % ('Failed', self._html_failure % ( message )) try: self.req.send(html, status = 500) except trac.web.api.RequestDone: pass def show_success(self, message = ''): message = cgi.escape(message).encode('utf-8') html = self._html_wrapper % ('Succeeded', self._html_success % ( message )) try: self.req.send(html) except trac.web.api.RequestDone: pass def show_form(self): try: self.req.send(self._html_wrapper % ('Input Information', self._html_form)) except trac.web.api.RequestDone: pass def do_create(self): req = self.req if req.args['repo'] == '' or req.args['project'] == '': self.show_failure('Invalid parameters') return try: path_trac = os.path.join( req.environ.get('trac_builder.project_parent_dir'), req.args['repo']) path_repo = os.path.join( req.environ.get('trac_builder.repos_parent_dir'), req.args['repo']) except: self.show_failure('Bad configuration') return r, status = TracProject().create(req.args['project'], path_trac, path_repo, req.args['type']) if r > 0: # error occured self.show_failure(status) else: # succeed self.show_success(status) #try: # req.redirect(req.base_url, False) #except trac.web.api.RequestDone: pass def run(self): if self.req.method == 'POST': self.do_create() else: self.show_form() # for WSGI def application(environ, start_response): if os.environ.get('GATEWAY_INTERFACE', '').startswith('CGI/'): environ.setdefault('trac_builder.project_parent_dir', os.environ.get('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac_builder.repos_parent_dir', os.environ.get('TRAC_REPOS_PARENT_DIR')) else: if 'mod_python.options' in environ: options = environ['mod_python.options'] else: options = environ environ.setdefault('trac_builder.project_parent_dir', options.get('TracEnvParentDir')) environ.setdefault('trac_builder.repos_parent_dir', options.get('TracReposParentDir')) req = trac.web.api.Request(environ, start_response) req.callbacks.update({ 'session': lambda(self): None, }) TracBuilder(req).run() return [] # for MOD_PYTHON def handler(req): from trac.web.modpython_frontend import ModPythonGateway from mod_python import apache options = req.get_options() gateway = ModPythonGateway(req, options) gateway.run(application) return apache.OK # for CGI if os.environ.get('GATEWAY_INTERFACE', '').startswith('CGI/'): from trac.web.cgi_frontend import CGIGateway gateway = CGIGateway() gateway.run(application)