Ticket #2041: intertrac-for-trac-0.9.4pre-r2830.patch
| File intertrac-for-trac-0.9.4pre-r2830.patch, 34.8 kB (added by cboos, 3 years ago) |
|---|
-
wiki-default/checkwiki.py
15 15 # Pages to include in distribution 16 16 wiki_pages = [ 17 17 "CamelCase", 18 "InterMapTxt", 19 "InterTrac", 20 "InterWiki", 18 21 "RecentChanges", 19 22 "TitleIndex", 20 23 "TracAccessibility", -
trac/env.py
74 74 ComponentManager.__init__(self) 75 75 76 76 self.path = path 77 self.siblings = {} 77 78 self.__cnx_pool = None 78 79 if create: 79 80 self.create(db_str) -
trac/ticket/api.py
19 19 from trac import util 20 20 from trac.core import * 21 21 from trac.perm import IPermissionRequestor 22 from trac.wiki import IWikiSyntaxProvider 22 from trac.wiki import IWikiSyntaxProvider, Formatter 23 23 from trac.Search import ISearchSource, query_to_sql, shorten_result 24 24 25 25 … … 140 140 ('ticket', self._format_link)] 141 141 142 142 def get_wiki_syntax(self): 143 yield (r"!?(?<!&)#\d+", # #123 but not { (HTML entity) 144 lambda x, y, z: self._format_link(x, 'ticket', y[1:], y)) 143 yield ( 144 # matches #... but not &#... (HTML entity) 145 r"!?(?<!&)#" 146 # optional intertrac shorthand #T... + digits 147 r"(?P<it_ticket>%s)?\d+" % Formatter.INTERTRAC_SCHEME, 148 lambda x, y, z: self._format_link(x, 'ticket', y[1:], y, z)) 145 149 146 def _format_link(self, formatter, ns, target, label): 150 def _format_link(self, formatter, ns, target, label, fullmatch=None): 151 intertrac = formatter.shorthand_intertrac_helper(ns, target, label, 152 fullmatch) 153 if intertrac: 154 return intertrac 147 155 cursor = formatter.db.cursor() 148 156 cursor.execute("SELECT summary,status FROM ticket WHERE id=%s", 149 157 (target,)) -
trac/ticket/report.py
25 25 from trac.perm import IPermissionRequestor 26 26 from trac.web import IRequestHandler 27 27 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 28 from trac.wiki import wiki_to_html, IWikiSyntaxProvider 28 from trac.wiki import wiki_to_html, IWikiSyntaxProvider, Formatter 29 29 30 30 31 31 dynvars_re = re.compile('\$([A-Z]+)') … … 501 501 yield ('report', self._format_link) 502 502 503 503 def get_wiki_syntax(self): 504 yield (r"!?\{\d+\}", lambda x, y, z: self._format_link(x, 'report', y[1:-1], y)) 504 yield (r"!?\{(?P<it_report>%s\s*)?\d+\}" % Formatter.INTERTRAC_SCHEME, 505 lambda x, y, z: self._format_link(x, 'report', y[1:-1], y, z)) 505 506 506 def _format_link(self, formatter, ns, target, label): 507 def _format_link(self, formatter, ns, target, label, fullmatch=None): 508 intertrac = formatter.shorthand_intertrac_helper(ns, target, label, 509 fullmatch) 510 if intertrac: 511 return intertrac 507 512 report, args = target, '' 508 513 if '?' in target: 509 514 report, args = target.split('?') -
trac/versioncontrol/web_ui/changeset.py
30 30 from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diff 31 31 from trac.web import IRequestHandler 32 32 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 33 from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider 33 from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider, \ 34 Formatter 34 35 35 36 36 37 class ChangesetModule(Component): … … 353 354 # IWikiSyntaxProvider methods 354 355 355 356 def get_wiki_syntax(self): 356 yield (r"!?\[\d+\]|(?:\b|!)r\d+\b(?!:\d)", 357 lambda x, y, z: self._format_link(x, 'changeset', 358 y[0] == 'r' and y[1:] 359 or y[1:-1], y)) 357 yield ( 358 # [...] form: start with optional intertrac: [T... or [trac ... 359 r"!?\[(?P<it_changeset>%s\s*)?" % Formatter.INTERTRAC_SCHEME + 360 # digits 361 r"\d+\]|" 362 # r... form: allow r1 but not r1:2 (handled by the log syntax) 363 r"(?:\b|!)r\d+\b(?!:\d)", 364 lambda x, y, z: 365 self._format_link(x, 'changeset', 366 y[0] == 'r' and y[1:] or y[1:-1], 367 y, z)) 360 368 361 369 def get_link_resolvers(self): 362 370 yield ('changeset', self._format_link) 363 371 364 def _format_link(self, formatter, ns, rev, label): 372 def _format_link(self, formatter, ns, rev, label, fullmatch=None): 373 intertrac = formatter.shorthand_intertrac_helper(ns, rev, label, 374 fullmatch) 375 if intertrac: 376 return intertrac 365 377 cursor = formatter.db.cursor() 366 378 cursor.execute('SELECT message FROM revision WHERE rev=%s', (rev,)) 367 379 row = cursor.fetchone() -
trac/wiki/api.py
187 187 def get_wiki_syntax(self): 188 188 ignore_missing = self.config.getbool('wiki', 'ignore_missing_pages') 189 189 yield (r"!?(?<!/)\b[A-Z][a-z]+(?:[A-Z][a-z]*[a-z/])+" 190 "(?:#[A-Za-z0-9]+)?(?= \Z|\s|[.,;:!?\)}\]])",190 "(?:#[A-Za-z0-9]+)?(?=:?\Z|:?\s|[.,;!?\)}\]])", 191 191 lambda x, y, z: self._format_link(x, 'wiki', y, y, 192 192 ignore_missing)) 193 193 -
trac/wiki/tests/wiki-tests.txt
148 148 </p> 149 149 ------------------------------ 150 150 ============================== 151 CamelCase,CamelCase.CamelCase: CamelCase151 CamelCase,CamelCase.CamelCase: CamelCase 152 152 ------------------------------ 153 153 <p> 154 <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>. CamelCase:CamelCase154 <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>.<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>: <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a> 155 155 </p> 156 156 ------------------------------ 157 157 ============================== … … 872 872 ------------------------------ 873 873 || a || 874 874 || b || 875 ============================== 876 t:wiki:InterTrac 877 trac:wiki:InterTrac 878 [t:wiki:InterTrac intertrac] 879 [trac:wiki:InterTrac intertrac] 880 ------------------------------ 881 <p> 882 <a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>t:wiki:InterTrac</a> 883 <a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>trac:wiki:InterTrac</a> 884 <a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a> 885 <a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a> 886 </p> 887 ------------------------------ 888 ============================== 889 trac:ticket:2041 890 [trac:ticket:2041 Trac #2041] 891 #T2041 892 #trac2041 893 ------------------------------ 894 <p> 895 <a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>trac:ticket:2041</a> 896 <a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>Trac #2041</a> 897 <a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>#T2041</a> 898 <a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>#trac2041</a> 899 </p> 900 ------------------------------ 901 ============================== 902 trac:changeset:2081 903 [trac:changeset:2081 Trac r2081] 904 [T2081] 905 [trac2081] 906 [trac 2081] 907 ------------------------------ 908 <p> 909 <a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>trac:changeset:2081</a> 910 <a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>Trac r2081</a> 911 <a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[T2081]</a> 912 <a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[trac2081]</a> 913 <a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[trac 2081]</a> 914 </p> 915 ------------------------------ 916 ============================== 917 trac:report:1 918 [trac:report:1 Trac r1] 919 {T1} 920 {trac1} 921 {trac 1} 922 ------------------------------ 923 <p> 924 <a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>trac:report:1</a> 925 <a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>Trac r1</a> 926 <a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{T1}</a> 927 <a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{trac1}</a> 928 <a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{trac 1}</a> 929 </p> 930 ------------------------------ 931 ============================== 932 t:InterTrac 933 trac:InterTrac 934 [t:InterTrac intertrac] 935 [trac:InterTrac intertrac] 936 T:r2081 937 T:#2041 938 trac:#2041 939 ------------------------------ 940 <p> 941 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>t:InterTrac</a> 942 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>trac:InterTrac</a> 943 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a> 944 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a> 945 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=r2081" title="r2081 in Trac's Trac"><span class="icon"></span>T:r2081</a> 946 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=%232041" title="#2041 in Trac's Trac"><span class="icon"></span>T:#2041</a> 947 <a class="ext-link" href="http://projects.edgewall.com/trac/search?q=%232041" title="#2041 in Trac's Trac"><span class="icon"></span>trac:#2041</a> 948 </p> 949 ------------------------------ -
trac/wiki/tests/formatter.py
1 from __future__ import generators 2 import os 3 import inspect 4 import StringIO 5 import unittest 6 7 from trac.core import * 8 from trac.wiki.formatter import Formatter, OneLinerFormatter 9 from trac.wiki.api import IWikiMacroProvider 10 11 12 class DummyHelloWorldMacro(Component): 13 """ 14 A dummy macro used by the unit test. We need to supply our own macro 15 because the real HelloWorld-macro can not be loaded using our 16 'fake' environment. 17 """ 18 implements(IWikiMacroProvider) 19 20 def get_macros(self): 21 yield 'HelloWorld' 22 23 def get_macro_description(self, name): 24 return inspect.getdoc(MacroListMacro) 25 26 def render_macro(self, req, name, content): 27 return 'Hello World, args = ' + content 28 29 30 class WikiTestCase(unittest.TestCase): 31 32 def __init__(self, input, correct, file, line): 33 unittest.TestCase.__init__(self, 'test') 34 self.input = input 35 self.correct = correct 36 self.file = file 37 self.line = line 38 39 def test(self): 40 """Testing WikiFormatter""" 41 42 # Environment stub 43 from trac.core import ComponentManager 44 from trac.config import Configuration 45 from trac.log import logger_factory 46 from trac.test import InMemoryDatabase 47 from trac.web.href import Href 48 49 db = InMemoryDatabase() 50 51 class DummyEnvironment(ComponentManager): 52 def __init__(self): 53 ComponentManager.__init__(self) 54 self.log = logger_factory('null') 55 self.config = Configuration(None) 56 self.href = Href('/') 57 self.abs_href = Href('http://www.example.com/') 58 self._wiki_pages = {} 59 self.path = '' 60 def component_activated(self, component): 61 component.env = self 62 component.config = self.config 63 component.log = self.log 64 def get_db_cnx(self): 65 return db 66 67 # Load all the components that provide IWikiSyntaxProvider 68 # implementations that are tested. Ideally those should be tested 69 # in separate unit tests. 70 import trac.versioncontrol.web_ui.browser 71 import trac.versioncontrol.web_ui.changeset 72 import trac.ticket.query 73 import trac.ticket.report 74 import trac.ticket.roadmap 75 import trac.Search 76 77 env = DummyEnvironment() 78 79 out = StringIO.StringIO() 80 formatter = self.formatter(env) 81 formatter.format(self.input, out) 82 v = out.getvalue().replace('\r','') 83 try: 84 self.assertEquals(self.correct, v) 85 except AssertionError, e: 86 raise AssertionError('%s\n\n%s:%s: for the input ' 87 '(formatter flavor was "%s")' \ 88 % (str(e), self.file, self.line, 89 formatter.flavor)) 90 91 def formatter(self, env): 92 return Formatter(env) 93 94 95 class OneLinerTestCase(WikiTestCase): 96 def formatter(self, env): 97 return OneLinerFormatter(env) 98 99 100 def suite(): 101 suite = unittest.TestSuite() 102 file = os.path.join(os.path.split(__file__)[0], 'wiki-tests.txt') 103 data = open(file, 'r').read() 104 tests = data.split('=' * 30 + '\n') 105 line = 1 106 for test in tests: 107 input, page, oneliner = test.split('-' * 30 + '\n') 108 suite.addTest(WikiTestCase(input, page, file, line)) 109 if oneliner: 110 suite.addTest(OneLinerTestCase(input, oneliner[:-1], file, line)) 111 line += len(test.split('\n')) 112 return suite 113 114 if __name__ == '__main__': 115 runner = unittest.TextTestRunner() 116 runner.run(suite()) 1 from __future__ import generators 2 import os 3 import inspect 4 import StringIO 5 import unittest 6 7 from trac.core import * 8 from trac.wiki.formatter import Formatter, OneLinerFormatter 9 from trac.wiki.api import IWikiMacroProvider 10 11 12 class DummyHelloWorldMacro(Component): 13 """ 14 A dummy macro used by the unit test. We need to supply our own macro 15 because the real HelloWorld-macro can not be loaded using our 16 'fake' environment. 17 """ 18 implements(IWikiMacroProvider) 19 20 def get_macros(self): 21 yield 'HelloWorld' 22 23 def get_macro_description(self, name): 24 return inspect.getdoc(MacroListMacro) 25 26 def render_macro(self, req, name, content): 27 return 'Hello World, args = ' + content 28 29 30 class WikiTestCase(unittest.TestCase): 31 32 def __init__(self, input, correct, file, line): 33 unittest.TestCase.__init__(self, 'test') 34 self.input = input 35 self.correct = correct 36 self.file = file 37 self.line = line 38 39 def test(self): 40 """Testing WikiFormatter""" 41 42 # Environment stub 43 from trac.core import ComponentManager 44 from trac.config import Configuration 45 from trac.log import logger_factory 46 from trac.test import InMemoryDatabase 47 from trac.web.href import Href 48 49 db = InMemoryDatabase() 50 51 class DummyEnvironment(ComponentManager): 52 def __init__(self): 53 ComponentManager.__init__(self) 54 self.log = logger_factory('null') 55 self.config = Configuration(None) 56 self.href = Href('/') 57 self.abs_href = Href('http://www.example.com/') 58 self.path = '' 59 # -- intertrac support 60 self.siblings = {} 61 self.config.set('intertrac', 'trac.title', "Trac's Trac") 62 self.config.set('intertrac', 'trac.url', 63 "http://projects.edgewall.com/trac") 64 self.config.set('intertrac', 't', 'trac') 65 def component_activated(self, component): 66 component.env = self 67 component.config = self.config 68 component.log = self.log 69 def get_db_cnx(self): 70 return db 71 72 # Load all the components that provide IWikiSyntaxProvider 73 # implementations that are tested. Ideally those should be tested 74 # in separate unit tests. 75 import trac.versioncontrol.web_ui.browser 76 import trac.versioncontrol.web_ui.changeset 77 import trac.ticket.query 78 import trac.ticket.report 79 import trac.ticket.roadmap 80 import trac.Search 81 82 env = DummyEnvironment() 83 84 out = StringIO.StringIO() 85 formatter = self.formatter(env) 86 formatter.format(self.input, out) 87 v = out.getvalue().replace('\r','') 88 try: 89 self.assertEquals(self.correct, v) 90 except AssertionError, e: 91 raise AssertionError('%s\n\n%s:%s: for the input ' 92 '(formatter flavor was "%s")' \ 93 % (str(e), self.file, self.line, 94 formatter.flavor)) 95 96 def formatter(self, env): 97 return Formatter(env) 98 99 100 class OneLinerTestCase(WikiTestCase): 101 def formatter(self, env): 102 return OneLinerFormatter(env) 103 104 105 def suite(): 106 suite = unittest.TestSuite() 107 file = os.path.join(os.path.split(__file__)[0], 'wiki-tests.txt') 108 data = open(file, 'r').read() 109 tests = data.split('=' * 30 + '\n') 110 line = 1 111 for test in tests: 112 input, page, oneliner = test.split('-' * 30 + '\n') 113 suite.addTest(WikiTestCase(input, page, file, line)) 114 if oneliner: 115 suite.addTest(OneLinerTestCase(input, oneliner[:-1], file, line)) 116 line += len(test.split('\n')) 117 return suite 118 119 if __name__ == '__main__': 120 runner = unittest.TextTestRunner() 121 runner.run(suite()) -
trac/wiki/formatter.py
28 28 from StringIO import StringIO 29 29 30 30 from trac import util 31 from trac.core import * 31 32 from trac.mimeview import * 32 from trac.wiki.api import WikiSystem 33 from trac.wiki.api import WikiSystem, IWikiChangeListener, IWikiMacroProvider 33 34 34 __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline' ]35 __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline', 'Formatter' ] 35 36 36 37 37 38 def system_message(msg, text): … … 132 133 INLINE_TOKEN = "`" 133 134 134 135 LINK_SCHEME = r"[\w.+-]+" # as per RFC 2396 136 INTERTRAC_SCHEME = r"[a-zA-Z.+-]+?" # no digits (support for shorthand links) 135 137 136 138 QUOTED_STRING = r"'[^']+'|\"[^\"]+\"" 137 139 … … 290 292 return self._make_link(ns, target, match, label) 291 293 292 294 def _make_link(self, ns, target, match, label): 295 # check first for an alias defined in trac.ini 296 ns = self.env.config.get('intertrac', ns.upper(), ns) 293 297 if ns in self.link_resolvers: 294 298 return self.link_resolvers[ns](self, ns, target, 295 299 util.escape(label, False)) 296 300 elif target.startswith('//') or ns == "mailto": 297 301 return self._make_ext_link(ns+':'+target, label) 298 302 else: 299 return util.escape(match) 303 return self._make_intertrac_link(ns, target, label) or \ 304 self._make_interwiki_link(ns, target, label) or \ 305 match 300 306 307 def _make_intertrac_link(self, ns, target, label): 308 if self.env.siblings.has_key(ns): 309 sibling = self.env.siblings[ns] 310 # The following is currently needed because env.href is set 311 # in trac.web.main.dispatch_request: for an environment which 312 # has not yet been queried by a client, .href is not defined. 313 if not hasattr(sibling, 'href'): 314 from trac.web.href import Href 315 def xchg_base(base): 316 return '/'.join(base.split('/')[:-1] + [ns]) 317 sibling.href = Href(xchg_base(self.env.href.base)) 318 sibling.abs_href = Href(xchg_base(self.env.abs_href.base)) 319 # EOKludge 320 ref = wiki_to_oneliner(target, sibling) 321 return ref.replace('>%s' % target, '>%s' % label) 322 url = self.env.config.get('intertrac', ns.upper()+'.url') 323 if url: 324 name = self.env.config.get('intertrac', ns.upper()+'.title', 325 'Trac project %s' % ns) 326 sep = target.find(':') 327 if sep != -1: 328 url = '%s/%s/%s' % (url, target[:sep], target[sep+1:]) 329 else: 330 url = '%s/search?q=%s' % (url, urllib.quote_plus(target)) 331 return self._make_ext_link(url, label, '%s in %s' % (target, name)) 332 else: 333 return None 334 335 def shorthand_intertrac_helper(self, ns, target, label, fullmatch): 336 if fullmatch: # short form 337 it_group = fullmatch.group('it_%s' % ns) 338 if it_group: 339 alias = it_group.strip() 340 intertrac = self.env.config.get('intertrac', alias.upper(), 341 alias) 342 target = '%s:%s' % (ns, target[len(it_group):]) 343 return self._make_intertrac_link(intertrac, target, label) or \ 344 label 345 return None 346 347 def _make_interwiki_link(self, ns, target, label): 348 interwiki = InterWikiMap(self.env) 349 if interwiki.has_key(ns): 350 url, title = interwiki.url(ns, target) 351 return self._make_ext_link(url, label, '%s in %s' % (target, title)) 352 else: 353 return None 354 301 355 def _make_ext_link(self, url, text, title=''): 302 356 url = util.escape(url) 303 357 text, title = util.escape(text), util.escape(title) … … 755 809 OutlineFormatter(env, absurls, db).format(wikitext, out, max_depth, 756 810 min_depth) 757 811 return util.Markup(out.getvalue()) 812 813 814 # -- InterWiki support 815 816 class InterWikiMap(Component): 817 818 implements(IWikiChangeListener, IWikiMacroProvider) 819 820 _page_name = 'InterMapTxt' 821 _interwiki_re = re.compile(r"(\w+)[ \t]+([^ \t]+)(?:[ \t]+#(.*))?", 822 re.UNICODE) 823 _argspec_re = re.compile(r"\$\d") 824 825 def __init__(self): 826 self._interwiki_map = None 827 # This dictionary maps upper-cased namespaces 828 # to (namespace, prefix, title) values 829 830 def has_key(self, ns): 831 if not self._interwiki_map: 832 self._update() 833 return self._interwiki_map.has_key(ns.upper()) 834 835 def url(self, ns, target): 836 ns, url, title = self._interwiki_map[ns.upper()] 837 args = target.split(':') 838 def setarg(match): 839 num = int(match.group()[1:]) 840 return 0 < num <= len(args) and args[num-1] or '' 841 url_with_args = re.sub(InterWikiMap._argspec_re, setarg, url) 842 if url_with_args == url: 843 return url + target, title 844 else: 845 return url_with_args, title 846 847 # IWikiChangeListener methods 848 849 def wiki_page_added(self, page): 850 if page.name == InterWikiMap._page_name: 851 self._update() 852 853 def wiki_page_changed(self, page, version, t, comment, author, ipnr): 854 if page.name == InterWikiMap._page_name: 855 self._update() 856 857 def wiki_page_deleted(self, page): 858 if page.name == InterWikiMap._page_name: 859 self._interwiki_map.clear() 860 861 def _update(self): 862 from trac.wiki.model import WikiPage 863 self._interwiki_map = {} 864 content = WikiPage(self.env, InterWikiMap._page_name).text 865 in_map = False 866 for line in content.split('\n'): 867 if in_map: 868 if line.startswith('----'): 869 in_map = False 870 else: 871 m = re.match(InterWikiMap._interwiki_re, line) 872 if m: 873 prefix, url, title = m.groups() 874 url = url.strip() 875 title = title and title.strip() or prefix 876 self._interwiki_map[prefix.upper()] = (prefix, url, 877 title) 878 elif line.startswith('----'): 879 in_map = True 880 881 # IWikiMacroProvider 882 883 def get_macros(self): 884 yield 'InterWiki' 885 886 def get_macro_description(self, name): 887 return "Provide a description list for the known InterWiki prefixes." 888 889 def render_macro(self, req, name, content): 890 if not self._interwiki_map: 891 self._update() 892 keys = self._interwiki_map.keys() 893 keys.sort() 894 buf = StringIO() 895 buf.write('<table><tr><th>Prefix</th><td>Site</td></tr>\n') 896 for k in keys: 897 prefix, url, title = self._interwiki_map[k] 898 shortened_url = url and url[:-1] 899 description = title == prefix and shortened_url or title 900 buf.write('<tr>\n' + 901 ('<td><a href="%sRecentChanges">%s</a></td>' 902 '<td><a href="%s">%s</a></td>\n') \ 903 % (url, prefix, shortened_url, description) + 904 '</tr>\n') 905 buf.write('</table>\n') 906 return buf.getvalue() -
trac/web/standalone.py
24 24 from trac.web.api import Request 25 25 from trac.web.cgi_frontend import TracFieldStorage 26 26 from trac.web.main import dispatch_request, get_environment, \ 27 setup_sibling_environments, \ 27 28 send_pretty_error, send_project_index 28 29 from trac.util import md5crypt 29 30 … … 201 202 else: 202 203 self.http_host = '%s:%d' % (self.server_name, self.server_port) 203 204 204 self.env_parent_dir = env_parent_dir and {'TRAC_ENV_PARENT_DIR': 205 env_parent_dir} 205 self.env_paths = env_paths 206 206 self.auths = auths 207 self.options = os.environ.copy() 208 if env_parent_dir: 209 self.options['TRAC_ENV_PARENT_DIR'] = env_parent_dir 210 self.projects = setup_sibling_environments(self.options, self.env_paths) 207 211 208 self.projects = {}209 for env_path in env_paths:210 # Remove trailing slashes211 while env_path and not os.path.split(env_path)[1]:212 env_path = os.path.split(env_path)[0]213 &
