# vim: expandtab
from StringIO import StringIO
from string import Template
from trac.util import TracError
from trac.WikiFormatter import wiki_to_html
from trac.Wiki import WikiPage
import trac.perm
import re, string, svn, os, time
from trac.core import open_svn_repos
import fcntl
SVN_URL = 'http://trac-hacks.swapoff.org/svn/'
SVN_LOCAL_PATH = 'file:///srv/svn/trac-hacks/'
SVN_PERMISSIONS = '/srv/trac-hacks/permissions'
tag_cache = {}
def fetch_page(cursor, page):
cursor.execute("SELECT text FROM wiki WHERE name='%s' ORDER BY version DESC LIMIT 1" % page)
text = cursor.fetchone()
if not text:
raise TracError("No such template page %s" % (page, page))
return text[0]
def expand_vars(text, vars):
s = Template(text)
return s.substitute(vars)
def get_branch_values(hdf, branch):
out = []
o = hdf.getObj(branch)
if not o: return out
if o.value():
out.append(o.value())
else:
o = o.child()
while o:
out.append(o.value())
o = o.next()
return out
def generate_vars(hdf):
vars = {}
vars['OWNER'] = hdf.getValue('trac.authname', 'anonymous')
vars['WIKINAME'] = hdf.getValue('args.name', 'NoPage')
if not vars['WIKINAME'].lower().endswith(hdf.getValue('args.type', '')):
vars['WIKINAME'] += hdf.getValue('args.type', '').title()
vars['TITLE'] = hdf.getValue('args.title', ' '.join(re.findall('[A-Z][a-z]+', vars['WIKINAME'])))
vars['LCNAME'] = vars['WIKINAME'].lower()
vars['TYPE'] = hdf.getValue('args.type', '')
if not hdf.getValue('args.previewhack', ''):
vars['TAGIT'] = '[[TagIt(%s,%s,%s)]]' % (vars['TYPE'], vars['OWNER'], ','.join(get_branch_values(hdf, 'args.tags') + get_branch_values(hdf, 'args.releases')))
else:
vars['TAGIT'] = "''(Tags not expanded during preview)''"
vars['SOURCEURL'] = SVN_URL + vars['LCNAME']
vars['DOWNLOADLINKS'] = '[[BR]]\n'.join([
'[source:%(lcname)s/%(release)s %(name)s for %(release)s].' % {
'release' : release,
'name' : vars['WIKINAME'],
'lcname' : vars['LCNAME'],
} for release in get_branch_values(hdf, 'args.releases')])
vars['DESCRIPTION'] = hdf.getValue('args.description', 'No description available')
vars['EXAMPLE'] = hdf.getValue('args.example', 'No example available')
return vars
def execute(hdf, template, env):
out = StringIO()
errors = []
authname = hdf.getValue("trac.authname", "anonymous")
if not template:
raise TracError("No template page supplied")
if authname == "anonymous":
errors.append('You need to register then login in order to create a new hack.' % (hdf.getValue("trac.href.registration", ""), hdf.getValue("trac.href.login", "")))
db = env.get_db_cnx()
cursor = db.cursor()
# Fetch meta-data from tags
META_TAGS = []
cursor.execute("SELECT name FROM wiki_namespace WHERE namespace=%s", 'metatag')
for tag in cursor.fetchall():
tag = tag[0]
cursor.execute("SELECT name FROM wiki_namespace WHERE namespace=%s", tag)
META_TAGS += [x[0] for x in cursor.fetchall()]
cursor.execute("SELECT name FROM wiki_namespace WHERE namespace=%s", 'type')
TYPES = [x[0] for x in cursor.fetchall()]
cursor.execute("SELECT name FROM wiki_namespace WHERE namespace=%s", 'release')
RELEASES = [x[0] for x in cursor.fetchall()]
page_name = hdf.getValue('args.name', '')
if not page_name.lower().endswith(hdf.getValue('args.type', '')):
page_name += hdf.getValue('args.type', '').title()
page_title = hdf.getValue('args.title', '')
page_description = hdf.getValue('args.description', '')
page_example = hdf.getValue('args.example', '')
page_type = hdf.getValue('args.type', 'macro')
page_tags = get_branch_values(hdf, 'args.tags')
page_releases = get_branch_values(hdf, 'args.releases')
page_preview = hdf.getValue('args.previewhack', '')
page_create = hdf.getValue('args.createhack', '')
def write_tags(out, tags, checked = (), name = "tags", type="checkbox"):
count = 0
for tag in sorted(tags):
if tag[0].isupper():
continue
(linktext,title,desc) = getInfo(db,tag)
link = env.href.wiki(tag)
check = ""
if tag in checked:
check = " checked"
out.write(' %s \n' % (type, name, tag, check, link, title, tag))
count += 1
if count % 8 == 0:
out.write("
\n")
return count
# Validation
if page_preview or page_create:
try:
fetch_page(cursor, page_name)
except:
pass
else:
errors.append("Page name %s already exists" % page_name)
if not re.match('^([A-Z][a-z]+){2,}$', page_name): errors.append('Invalid WikiName, only alpha characters are accepted and must be CamelCase')
if not page_name: errors.append("No WikiName provided")
if not page_title: errors.append("No page title provided")
if not page_type: errors.append('No page type selected')
if not page_description: errors.append("No description provided")
if not page_example: errors.append("No example provided")
if not page_releases: errors.append("No releases selected")
if page_create and not errors:
repos_dir = env.get_config('trac', 'repository_dir')
pool, rep, fs_ptr = open_svn_repos(repos_dir)
rev = svn.fs.youngest_rev(fs_ptr, pool)
root = svn.fs.revision_root(fs_ptr, rev, pool)
node_type = svn.fs.check_path(root, page_name.lower(), pool)
cursor.execute("SELECT name FROM component WHERE name='%s'" % page_name)
row = cursor.fetchone()
if row:
errors.append("Component '%s' already exists" % page_name)
if node_type:
errors.append("Repository path '%s' already exists" % page_name.lower())
if not os.access(SVN_PERMISSIONS, os.W_OK):
errors.append("Can't write to Subversion permissions file")
lockfile = open("/var/tmp/newhack.lock", "w")
try:
rv = fcntl.flock(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
if rv:
errors.append('Failed to acquire lock, received error code %i' % rv)
except IOError:
errors.append('A hack is currently being created by another user. Try again later.')
if not errors:
try:
# Insert component
cursor.execute('INSERT INTO component (name, owner) VALUES (%s, %s)', page_name, authname)
# Create page
perm = trac.perm.PermissionCache(db, authname)
page = WikiPage(page_name, None, perm, db)
page.set_content(expand_vars(fetch_page(cursor, template), generate_vars(hdf)))
out.write('Created wiki page.
\n')
# Creating SVN paths
paths = ['%s%s' % (SVN_LOCAL_PATH, page_name.lower())]
for release in page_releases:
paths.append("%s%s/%s" % (SVN_LOCAL_PATH, page_name.lower(), release))
output = os.popen('umask 775; /usr/bin/op create-hack %s "New hack %s, created by %s" %s 2>&1' % (authname, page_name, authname, ' '.join(paths))).readlines()
if output:
raise Exception("Failed to create Subversion paths:\n
%s" % ''.join(output)) out.write("Created SVN layout.