# -*- coding: iso8859-1 -*- # # Copyright (C) 2003-2005 Edgewall Software # Copyright (C) 2003-2005 Jonas Borgström # Copyright (C) 2004-2005 Christopher Lenz # 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.com/license.html. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://projects.edgewall.com/trac/. # # Author: Jonas Borgström # Christopher Lenz from __future__ import generators try: import threading except ImportError: import dummy_threading as threading import time import urllib from trac.core import * from trac.util import to_utf8, TRUE class IWikiChangeListener(Interface): """Extension point interface for components that should get notified about the creation, deletion and modification of wiki pages. """ def wiki_page_added(page): """Called whenever a new Wiki page is added.""" def wiki_page_changed(page, version, t, comment, author, ipnr): """Called when a page has been modified.""" def wiki_page_deleted(page): """Called when a page has been deleted.""" class IWikiMacroProvider(Interface): """Extension point interface for components that provide Wiki macros.""" def get_macros(): """Return an iterable that provides the names of the provided macros.""" def get_macro_description(name): """Return a plain text description of the macro with the specified name. """ def render_macro(req, name, content): """Return the HTML output of the macro.""" class IWikiSyntaxProvider(Interface): def get_wiki_syntax(): """Return an iterable that provides additional wiki syntax.""" def get_link_resolvers(): """Return an iterable over (namespace, formatter) tuples.""" class WikiSystem(Component): """Represents the wiki system.""" implements(IWikiChangeListener, IWikiSyntaxProvider) change_listeners = ExtensionPoint(IWikiChangeListener) macro_providers = ExtensionPoint(IWikiMacroProvider) syntax_providers = ExtensionPoint(IWikiSyntaxProvider) INDEX_UPDATE_INTERVAL = 5 # seconds def __init__(self): self._index = None self._last_index_update = 0 self._index_lock = threading.RLock() def _update_index(self): self._index_lock.acquire() try: now = time.time() if now > self._last_index_update + WikiSystem.INDEX_UPDATE_INTERVAL: self.log.debug('Updating wiki page index') db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT DISTINCT name FROM wiki") self._index = {} for (name,) in cursor: self._index[name] = True self._last_index_update = now finally: self._index_lock.release() # Public API def get_pages(self, prefix=None): """Iterate over the names of existing Wiki pages. If the `prefix` parameter is given, only names that start with that prefix are included. """ self._update_index() for page in self._index.keys(): if not prefix or page.startswith(prefix): yield page def has_page(self, pagename): """Whether a page with the specified name exists.""" self._update_index() return pagename in self._index.keys() # IWikiChangeListener methods def wiki_page_added(self, page): if not self.has_page(page.name): self.log.debug('Adding page %s to index' % page.name) self._pages[page.name] = True def wiki_page_changed(self, page, version, t, comment, author, ipnr): pass def wiki_page_deleted(self, page): if self.has_page(page.name): self.log.debug('Removing page %s from index' % page.name) del self._pages[page.name] # IWikiSyntaxProvider methods def get_wiki_syntax(self): ignore_missing = self.config.get('wiki', 'ignore_missing_pages') ignore_missing = ignore_missing in TRUE yield (r"!?(?%s?' \ % (formatter.href.wiki(page) + anchor, label) else: return '%s' \ % (formatter.href.wiki(page) + anchor, label)