Edgewall Software

Ticket #2041: trac-0.9-intertrac.patch

File trac-0.9-intertrac.patch, 32.5 KB (added by cboos, 6 years ago)

The InterTrac and InterWiki features added to Trac 0.9 (from the repository)

  • wiki-default/InterTrac

     
     1= InterTrac Extension for TracLinks = 
     2 
     3''This is a proposal for implementing #234''. 
     4''It's candidate for integration in the trunk, after the 0.9 release (see #2041)'' 
     5 
     6== Definitions == 
     7 
     8An InterTrac link is used for referring to a Trac object  
     9(Wiki page, changeset, ticket, ...) located in another 
     10Trac environment. 
     11 
     12== Link Syntax == 
     13 
     14{{{ 
     15<target_environment>:<TracLinks> 
     16}}} 
     17 
     18The link is composed by the target environment name,  
     19followed by a colon (e.g. `trac:`), 
     20followed by a regular TracLinks, of any flavor. 
     21 
     22That target environment name is either the real name of the  
     23environment, or an alias for it.  
     24The aliases are defined in `trac.ini` (see below). 
     25The prefix is case insensitive. 
     26 
     27For convenience, there's also an alternative short-hand form,  
     28where one can use an alias as an immediate prefix  
     29for the identifier of a ticket, changeset or report: 
     30(e.g. `#T234`, `[T1508]`, `[trac 1508]`, ...) 
     31 
     32== Examples == 
     33 
     34Besides the other environments run by the same server process 
     35(called ''sibling'' environments), which are automatically detected, 
     36(''Note: currently only in `tracd`''), 
     37it is necessary to setup a configuration for the InterTrac facility: 
     38 * in order to refer to a remote Trac 
     39 * for defining environment aliases 
     40 
     41This is done quite simply in an `[intertrac]` section 
     42within the `trac.ini` file. 
     43 
     44Example configuration: 
     45{{{ 
     46... 
     47[intertrac] 
     48## -- Example of setting up an alias: 
     49t = trac 
     50 
     51## -- Link to an external Trac: 
     52trac.title = Edgewall's Trac for Trac 
     53trac.url = http://projects.edgewall.com/trac 
     54 
     55#trac.svn = http://repos.edgewall.com/projects/trac  
     56# Hint: .svn information could be used in the future to support svn:externals... 
     57}}} 
     58 
     59Now, given this configuration, one could create the following links: 
     60 * to the current InterTrac page: 
     61   * `trac:wiki:InterTrac` -> 
     62     [http://projects.edgewall.com/trac/wiki/InterTrac trac:wiki:InterTrac] 
     63   * `t:wiki:InterTrac` -> 
     64     [http://projects.edgewall.com/trac/wiki/InterTrac t:wiki:InterTrac] 
     65   * Keys are case insensitive: `T:wiki:InterTrac` ->  
     66     [http://projects.edgewall.com/trac/wiki/InterTrac T:wiki:InterTrac] 
     67 * to the ticket #234: 
     68   * `trac:ticket:234` -> 
     69     [http://projects.edgewall.com/trac/ticket/234 trac:ticket:234] 
     70   * `trac:#234` -> 
     71     [http://projects.edgewall.com/trac/ticket/234 trac:#234] 
     72   * `#T234` -> 
     73     [http://projects.edgewall.com/trac/search?q=#234 #T234] 
     74 * to the changeset [1912]: 
     75   * `trac:changeset:1912` -> 
     76     [http://projects.edgewall.com/trac/changeset/1912 trac:changeset:1912] 
     77   * `trac:[1912]` -> 
     78     [http:"//projects.edgewall.com/trac/search?q=[1912]" "trac:[1912]"] 
     79   * `[T1912]` -> 
     80     [http://projects.edgewall.com/trac/changeset/1912 "[T1912]"] 
     81 
     82Anything not given as explicit links (intertrac_prefix:module:id) 
     83is interpreted by the remote Trac, relying on its quickjump 
     84facility. 
     85 
     86 
     87 
     88See also: TracLinks, InterWiki 
     89 
     90---- 
     91== Implementation Notes == 
     92 
     93Currently, the `[intertrac]` configuration has to be repeated  
     94for each Trac environment, but there's work in progress concerning a  
     95[ticket:1051 centralized trac.ini], which would help greatly here. 
     96 
     97This idea was first proposed as a patch for #234, and  
     98has been implemented in the following branch:  
     99source:branches/cboos-dev/intertrac-branch 
     100 
     101The general idea is that any `[a-zA-Z.+-]+:` prefix,  
     102followed by anything which is not a space, has to be interpreted as: 
     103 1. maybe an alias to something else; if yes, it is dereferenced 
     104    before going on 
     105 1. then, it's maybe a link prefix given by an `IWikiSyntaxProvider` component  
     106 1. if not, it's maybe an environment name (!InterTrac link) 
     107 1. if not, it's maybe an !InterWiki link 
     108 1. if not, it is not a link 
  • wiki-default/InterMapTxt

    Property changes on: wiki-default\InterTrac
    ___________________________________________________________________
    Name: svn:mime-type
       + text/x-trac-wiki
    
     
     1= InterMapTxt = 
     2== This is the place for defining InterWiki prefixes == 
     3 
     4This page was modelled after the MeatBall:InterMapTxt page. 
     5In addition, an optional comment is allowed after the mapping. 
     6 
     7 
     8This page is interpreted in a special way by Trac, in order to support 
     9!InterWiki links in a flexible and dynamic way. 
     10 
     11The code block after the first line separator in this page 
     12will be interpreted as a list of !InterWiki specifications: 
     13{{{ 
     14prefix <space> URL [<space> # comment] 
     15}}} 
     16 
     17By using `$1`, `$2`, etc. within the URL, it is possible to create  
     18InterWiki links which support multiple arguments, e.g. Trac:ticket:40. 
     19The URL itself can be optionally followed by a comment,  
     20which will subsequently be used for decorating the links  
     21using that prefix. 
     22 
     23New !InterWiki links can be created by adding to that list, in real time. 
     24Note however that ''deletions'' are also taken into account immediately, 
     25so it may be better to use comments for disabling prefixes. 
     26 
     27Also note that !InterWiki prefixes are case insensitive. 
     28 
     29 
     30== List of Active Prefixes == 
     31 
     32[[InterWiki]] 
     33 
     34---- 
     35 
     36== Prefix Definitions == 
     37 
     38{{{ 
     39PEP     http://www.python.org/peps/pep-$1.html                                       # Python Enhancement Proposal  
     40TracML  http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/  # Trac Mailing List 
     41 
     42# 
     43# A arbitrary pick of InterWiki prefixes... 
     44# 
     45Acronym          http://www.acronymfinder.com/af-query.asp?String=exact&Acronym= 
     46C2find           http://c2.com/cgi/wiki?FindPage&value= 
     47Cache            http://www.google.com/search?q=cache: 
     48CPAN             http://search.cpan.org/perldoc? 
     49DebianBug        http://bugs.debian.org/ 
     50DebianPackage    http://packages.debian.org/ 
     51Dictionary       http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query= 
     52Google           http://www.google.com/search?q= 
     53GoogleGroups     http://groups.google.com/groups?q= 
     54JargonFile       http://downlode.org/perl/jargon-redirect.cgi?term= 
     55MeatBall         http://www.usemod.com/cgi-bin/mb.pl? 
     56MetaWiki         http://sunir.org/apps/meta.pl? 
     57MetaWikiPedia    http://meta.wikipedia.org/wiki/ 
     58MoinMoin         http://moinmoin.wikiwikiweb.de/ 
     59WhoIs            http://www.whois.sc/ 
     60Why              http://clublet.com/c/c/why? 
     61Wiki             http://c2.com/cgi/wiki? 
     62WikiPedia        http://en.wikipedia.org/wiki/ 
     63}}} 
  • wiki-default/WikiStart

    Property changes on: wiki-default\InterMapTxt
    ___________________________________________________________________
    Name: svn:mime-type
       + text/x-trac-wiki
    
     
    1 = Welcome to Trac 0.9 = 
     1= Welcome to Trac 0.9-intertrac = 
    22 
    33Trac is a '''minimalistic''' approach to '''web-based''' management of 
    44'''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress. 
  • wiki-default/checkwiki.py

     
    1515# Pages to include in distribution 
    1616wiki_pages = [ 
    1717 "CamelCase", 
     18 "InterMapTxt", 
     19 "InterTrac", 
     20 "InterWiki", 
    1821 "RecentChanges", 
    1922 "TitleIndex", 
    2023 "TracAccessibility", 
  • wiki-default/InterWiki

     
     1= Support for InterWiki links = 
     2 
     3''This is a proposal for implementing #40 and #1414'' 
     4''It's candidate for integration in the trunk, after the 0.9 release (see #2041)'' 
     5 
     6== Definition == 
     7 
     8An InterWiki link can be used for referring to a Wiki page 
     9located in another Wiki system, and by extension, to any object 
     10located in any other Web application, provided a simple URL  
     11mapping can be done. 
     12 
     13== Link Syntax == 
     14 
     15{{{ 
     16<target_wiki>(:<identifier>)+ 
     17}}} 
     18 
     19The link is composed by the targeted Wiki (or system) name, 
     20followed by a column (e.g. {{{MeatBall:}}}), 
     21followed by a page specification in the target. 
     22Note that, as for InterTrac prefixes, InterWiki prefixes are case insensitive. 
     23 
     24The target Wiki URL is looked up in a the InterMapTxt wiki page,  
     25modelled after 
     26[http://www.usemod.com/cgi-bin/mb.pl?InterMapTxt MeatBall:InterMapTxt]. 
     27 
     28An addition to traditional InterWiki links, where the target 
     29is simply ''appended'' to the URL,  
     30Trac supports parametric InterWiki URLs: 
     31identifiers `$1`, `$2`, ... in the URL 
     32will be replaced by corresponding arguments from a list 
     33made up from the page specification split by the ":" token. 
     34 
     35== Examples == 
     36 
     37If the following is an excerpt of the InterMapTxt page: 
     38 
     39{{{ 
     40= InterMapTxt = 
     41== This is the place for defining InterWiki prefixes == 
     42 
     43Currently active prefixes: [[InterWiki]] 
     44 
     45This page is modelled after the MeatBall:InterMapTxt page. 
     46In addition, an optional comment is allowed after the mapping. 
     47---- 
     48{{{ 
     49PEP     http://www.python.org/peps/pep-$1.html                                       # Python Enhancement Proposal  
     50TracML  http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/  # Trac Mailing List 
     51 
     52... 
     53MeatBall http://www.usemod.com/cgi-bin/mb.pl? 
     54MetaWiki http://sunir.org/apps/meta.pl? 
     55MetaWikiPedia http://meta.wikipedia.org/wiki/ 
     56MoinMoin http://moinmoin.wikiwikiweb.de/ 
     57... 
     58}}} 
     59}}} 
     60 
     61Then,  
     62 * `MoinMoin:InterWikiMap` should be rendered as  
     63   [http://moinmoin.wikiwikiweb.de/InterWikiMap MoinMoin:InterWikiMap] 
     64   and the ''title'' for that link would be "!InterWikiMap in !MoinMoin" 
     65 * {{{TracML:4346}}} should be rendered as  
     66   [http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/4346 TracML:4346] 
     67   and the ''title'' for that link would be "4346 in Trac Mailing List" 
     68   (idea: I should allow positional parameters in the comment as well) 
  • trac/env.py

    Property changes on: wiki-default\InterWiki
    ___________________________________________________________________
    Name: svn:mime-type
       + text/x-trac-wiki
    
     
    7474        ComponentManager.__init__(self) 
    7575 
    7676        self.path = path 
     77        self.siblings = {} 
    7778        self.__cnx_pool = None 
    7879        if create: 
    7980            self.create(db_str) 
  • trac/ticket/api.py

     
    1919from trac import util 
    2020from trac.core import * 
    2121from trac.perm import IPermissionRequestor 
    22 from trac.wiki import IWikiSyntaxProvider 
     22from trac.wiki import IWikiSyntaxProvider, Formatter 
    2323from trac.Search import ISearchSource, query_to_sql, shorten_result 
    2424 
    2525 
     
    140140                ('ticket', self._format_link)] 
    141141 
    142142    def get_wiki_syntax(self): 
    143         yield (r"!?#\d+", 
    144                lambda x, y, z: self._format_link(x, 'ticket', y[1:], y)) 
     143        yield (r"!?#(?P<it_ticket>%s)?\d+" % Formatter.INTERTRAC_SCHEME, 
     144               lambda x, y, z: self._format_link(x, 'ticket', y[1:], y, z)) 
    145145 
    146     def _format_link(self, formatter, ns, target, label): 
     146    def _format_link(self, formatter, ns, target, label, fullmatch=None): 
     147        intertrac = formatter.shorthand_intertrac_helper(ns, target, label, 
     148                                                         fullmatch) 
     149        if intertrac: 
     150            return intertrac 
    147151        cursor = formatter.db.cursor() 
    148152        cursor.execute("SELECT summary,status FROM ticket WHERE id=%s", 
    149153                       (target,)) 
  • trac/ticket/report.py

     
    2424from trac.perm import IPermissionRequestor 
    2525from trac.web import IRequestHandler 
    2626from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 
    27 from trac.wiki import wiki_to_html, IWikiSyntaxProvider 
     27from trac.wiki import wiki_to_html, IWikiSyntaxProvider, Formatter 
    2828 
    2929 
    3030dynvars_re = re.compile('\$([A-Z]+)') 
     
    510510        yield ('report', self._format_link) 
    511511 
    512512    def get_wiki_syntax(self): 
    513         yield (r"!?\{\d+\}", lambda x, y, z: self._format_link(x, 'report', y[1:-1], y)) 
     513        yield (r"!?\{(?P<it_report>%s\s*)?\d+\}" % Formatter.INTERTRAC_SCHEME, 
     514               lambda x, y, z: self._format_link(x, 'report', y[1:-1], y, z)) 
    514515 
    515     def _format_link(self, formatter, ns, target, label): 
     516    def _format_link(self, formatter, ns, target, label, fullmatch=None): 
     517        intertrac = formatter.shorthand_intertrac_helper(ns, target, label, 
     518                                                         fullmatch) 
     519        if intertrac: 
     520            return intertrac 
    516521        report, args = target, '' 
    517522        if '?' in target: 
    518523            report, args = target.split('?') 
  • trac/__init__.py

     
    1010""" 
    1111__docformat__ = 'epytext en' 
    1212 
    13 __version__ = '0.9' 
     13__version__ = '0.9-intertrac' 
    1414__url__ = 'http://trac.edgewall.com/' 
    1515__copyright__ = '(C) 2003-2005 Edgewall Software' 
    1616__license__ = 'BSD' 
  • trac/versioncontrol/web_ui/changeset.py

     
    3030from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diff 
    3131from trac.web import IRequestHandler 
    3232from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 
    33 from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider 
     33from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider, \ 
     34                      Formatter 
    3435 
    3536 
    3637class ChangesetModule(Component): 
     
    354355    # IWikiSyntaxProvider methods 
    355356     
    356357    def get_wiki_syntax(self): 
    357         yield (r"!?\[\d+\]|(?:\b|!)r\d+\b(?!:\d)", 
     358        yield (r"!?\[(?P<it_changeset>%s\s*)?\d+\]|" \ 
     359               % Formatter.INTERTRAC_SCHEME +           # [1], [T1] or [trac 1] 
     360               r"(?:\b|!)r\d+\b(?!:\d)",                # r1 but not r1:2 
    358361               lambda x, y, z: self._format_link(x, 'changeset', 
    359362                                                 y[0] == 'r' and y[1:] 
    360                                                  or y[1:-1], y)) 
     363                                                 or y[1:-1], y, z)) 
    361364 
    362365    def get_link_resolvers(self): 
    363366        yield ('changeset', self._format_link) 
    364367 
    365     def _format_link(self, formatter, ns, rev, label): 
     368    def _format_link(self, formatter, ns, rev, label, fullmatch=None): 
     369        intertrac = formatter.shorthand_intertrac_helper(ns, rev, label, 
     370                                                         fullmatch) 
     371        if intertrac: 
     372            return intertrac 
    366373        cursor = formatter.db.cursor() 
    367374        cursor.execute('SELECT message FROM revision WHERE rev=%s', (rev,)) 
    368375        row = cursor.fetchone() 
  • trac/wiki/api.py

     
    214214        else: 
    215215            return '<a class="wiki" href="%s">%s</a>' \ 
    216216                   % (formatter.href.wiki(page) + anchor, label) 
     217 
  • trac/wiki/tests/wiki-tests.txt

     
    5151<a class="ext-link" href="http://www.edgewall.com/"><span class="icon"></span>http://www.edgewall.com/</a> 
    5252============================== 
    5353#1, [1], r1, {1} 
     54#12, [12], r12, {12} 
    5455------------------------------ 
    5556<p> 
    5657<a class="missing ticket" href="/ticket/1" rel="nofollow">#1</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">[1]</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">r1</a>, <a class="report" href="/report/1">{1}</a> 
     58<a class="missing ticket" href="/ticket/12" rel="nofollow">#12</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">[12]</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">r12</a>, <a class="report" href="/report/12">{12}</a> 
    5759</p> 
    5860------------------------------ 
    5961============================== 
     
    137139</p> 
    138140------------------------------ 
    139141============================== 
    140 CamelCase,CamelCase.CamelCase:CamelCase 
     142CamelCase,CamelCase.CamelCase: CamelCase 
    141143------------------------------ 
    142144<p> 
    143 <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>.CamelCase:CamelCase 
     145<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> 
    144146</p> 
    145147------------------------------ 
    146148============================== 
     
    855857------------------------------ 
    856858|| a ||  
    857859|| b || 
     860============================== 
     861t:wiki:InterTrac 
     862trac:wiki:InterTrac 
     863[t:wiki:InterTrac intertrac] 
     864[trac:wiki:InterTrac intertrac] 
     865------------------------------ 
     866<p> 
     867<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> 
     868<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> 
     869<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> 
     870<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> 
     871</p> 
     872------------------------------ 
     873============================== 
     874trac:ticket:2041 
     875[trac:ticket:2041 Trac #2041] 
     876#T2041 
     877#trac2041 
     878------------------------------ 
     879<p> 
     880<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> 
     881<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> 
     882<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> 
     883<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> 
     884</p> 
     885------------------------------ 
     886============================== 
     887trac:changeset:2081 
     888[trac:changeset:2081 Trac r2081] 
     889[T2081] 
     890[trac2081] 
     891[trac 2081] 
     892------------------------------ 
     893<p> 
     894<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> 
     895<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> 
     896<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> 
     897<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> 
     898<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> 
     899</p> 
     900------------------------------ 
     901============================== 
     902trac:report:1 
     903[trac:report:1 Trac r1] 
     904{T1} 
     905{trac1} 
     906{trac 1} 
     907------------------------------ 
     908<p> 
     909<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> 
     910<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> 
     911<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> 
     912<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> 
     913<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> 
     914</p> 
     915------------------------------ 
     916============================== 
     917t:InterTrac 
     918trac:InterTrac 
     919[t:InterTrac intertrac] 
     920[trac:InterTrac intertrac] 
     921T:r2081 
     922T:#2041 
     923trac:#2041 
     924------------------------------ 
     925<p> 
     926<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> 
     927<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> 
     928<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> 
     929<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> 
     930<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> 
     931<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> 
     932<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> 
     933</p> 
     934------------------------------ 
  • trac/wiki/tests/formatter.py

     
    5555                self.config = Configuration(None) 
    5656                self.href = Href('/') 
    5757                self.abs_href = Href('http://www.example.com/') 
    58                 self._wiki_pages = {} 
    5958                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') 
    6065            def component_activated(self, component): 
    6166                component.env = self 
    6267                component.config = self.config 
  • trac/wiki/formatter.py

     
    2727    from StringIO import StringIO 
    2828 
    2929from trac import util 
     30from trac.core import * 
    3031from trac.mimeview import * 
    31 from trac.wiki.api import WikiSystem 
     32from trac.wiki.api import WikiSystem, IWikiChangeListener, IWikiMacroProvider 
    3233 
    33 __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline'] 
     34__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline', 'Formatter' ] 
    3435 
    3536 
    3637def system_message(msg, text): 
     
    134135    INLINE_TOKEN = "`" 
    135136 
    136137    LINK_SCHEME = r"[\w.+-]+" # as per RFC 2396 
     138    INTERTRAC_SCHEME = r"[a-zA-Z.+-]+?" # no digits (support for shorthand links) 
    137139 
    138140    QUOTED_STRING = r"'[^']+'|\"[^\"]+\"" 
    139141 
     
    296298            return self._make_link(ns, target, match, label) 
    297299 
    298300    def _make_link(self, ns, target, match, label): 
     301        # check first for an alias defined in trac.ini 
     302        ns = self.env.config.get('intertrac', ns.upper(), ns) 
    299303        if ns in self.link_resolvers: 
    300304            return self.link_resolvers[ns](self, ns, target, label) 
    301305        elif target.startswith('//') or ns == "mailto": 
    302306            return self._make_ext_link(ns+':'+target, label) 
    303307        else: 
    304             return match 
     308            intertrac = self._make_intertrac_link(ns, target, label) 
     309            if intertrac: 
     310                return intertrac 
     311            else: 
     312                interwiki = self._make_interwiki_link(ns, target, label) 
     313                if interwiki: 
     314                    return interwiki 
     315                else: 
     316                    return match 
    305317 
     318    def _make_intertrac_link(self, ns, target, label): 
     319        if self.env.siblings.has_key(ns): 
     320            sibling = self.env.siblings[ns] 
     321            if not hasattr(sibling, 'href'): 
     322                from trac.web.href import Href 
     323                def xchg_base(base): 
     324                    return '/'.join(base.split('/')[:-1] + [ns]) 
     325                sibling.href = Href(xchg_base(self.env.href.base)) 
     326                sibling.abs_href = Href(xchg_base(self.env.abs_href.base)) 
     327            ref = wiki_to_oneliner(target, sibling) 
     328            return ref.replace('>%s' % target, '>%s' % label) 
     329        url = self.env.config.get('intertrac', ns.upper()+'.url') 
     330        if url: 
     331            name = self.env.config.get('intertrac', ns.upper()+'.title', 
     332                                       'Trac project %s' % ns) 
     333            sep = target.find(':') 
     334            if sep != -1: 
     335                url = '%s/%s/%s' % (url, target[:sep], target[sep+1:]) 
     336            else:  
     337                url = '%s/search?q=%s' % (url, urllib.quote_plus(target)) 
     338            return self._make_ext_link(url, label, '%s in %s' % (target, name)) 
     339        else: 
     340            return None 
     341 
     342    def shorthand_intertrac_helper(self, ns, target, label, fullmatch): 
     343        if fullmatch: # short form 
     344            it_grp = fullmatch.group('it_%s' % ns) 
     345            if it_grp: 
     346                alias = it_grp.strip() 
     347                intertrac = self.env.config.get('intertrac', alias.upper(), 
     348                                                alias) 
     349                target = '%s:%s' % (ns, target[len(it_grp):]) 
     350                it = self._make_intertrac_link(intertrac, target, label) 
     351                return it or label 
     352        return None 
     353 
     354    def _make_interwiki_link(self, ns, target, label): 
     355        interwiki = InterWikiMap(self.env) 
     356        if interwiki.has_key(ns): 
     357            url, title = interwiki.url(ns, target) 
     358            return self._make_ext_link(url, label, '%s in %s' % (target, title)) 
     359        else: 
     360            return None 
     361 
    306362    def _make_ext_link(self, url, text, title=''): 
    307363        title_attr = title and ' title="%s"' % title or '' 
    308364        if Formatter.img_re.search(url) and self.flavor != 'oneliner': 
     
    762818    OutlineFormatter(env, absurls, db).format(wikitext, out, max_depth, 
    763819                                              min_depth) 
    764820    return out.getvalue() 
     821 
     822 
     823# -- InterWiki support 
     824 
     825class InterWikiMap(Component): 
     826 
     827    implements(IWikiChangeListener, IWikiMacroProvider) 
     828 
     829    _page_name = 'InterMapTxt' 
     830    _interwiki_re = re.compile(r"(\w+)[ \t]+([^ \t]+)(?:[ \t]+#(.*))?", 
     831                               re.UNICODE) 
     832    _argspec_re = re.compile(r"\$\d") 
     833 
     834    def __init__(self): 
     835        self._interwiki_map = None 
     836        # This dictionary maps upper-cased namespaces 
     837        # to (namespace, prefix, title) values 
     838 
     839    def has_key(self, ns): 
     840        if not self._interwiki_map: 
     841            self._update() 
     842        return self._interwiki_map.has_key(ns.upper()) 
     843 
     844    def url(self, ns, target): 
     845        ns, url, title = self._interwiki_map[ns.upper()] 
     846        args = target.split(':') 
     847        def setarg(match): 
     848            num = int(match.group()[1:]) 
     849            return 0 < num <= len(args) and args[num-1] or '' 
     850        url_with_args = re.sub(InterWikiMap._argspec_re, setarg, url) 
     851        if url_with_args == url:  
     852            return url + target, title 
     853        else: 
     854            return url_with_args, title 
     855 
     856    # IWikiChangeListener methods 
     857 
     858    def wiki_page_added(self, page): 
     859        if page.name == InterWikiMap._page_name: 
     860            self._update() 
     861 
     862    def wiki_page_changed(self, page, version, t, comment, author, ipnr): 
     863        if page.name == InterWikiMap._page_name: 
     864            self._update() 
     865 
     866    def wiki_page_deleted(self, page): 
     867        if page.name == InterWikiMap._page_name: 
     868            self._interwiki_map.clear() 
     869 
     870    def _update(self): 
     871        from trac.wiki.model import WikiPage 
     872        self._interwiki_map = {} 
     873        content = WikiPage(self.env, InterWikiMap._page_name).text 
     874        in_map = False 
     875        for line in content.split('\n'): 
     876            if in_map: 
     877                if line.startswith('----'): 
     878                    in_map = False 
     879                else: 
     880                    m = re.match(InterWikiMap._interwiki_re, line) 
     881                    if m: 
     882                        prefix, url, title = m.groups() 
     883                        url = url.strip() 
     884                        title = title and title.strip() or prefix 
     885                        self._interwiki_map[prefix.upper()] = (prefix, url, 
     886                                                               title) 
     887            elif line.startswith('----'): 
     888                in_map = True 
     889 
     890    # IWikiMacroProvider 
     891 
     892    def get_macros(self): 
     893        yield 'InterWiki' 
     894 
     895    def get_macro_description(self, name):  
     896        return "Provide a description list for the known InterWiki prefixes." 
     897 
     898    def render_macro(self, req, name, content): 
     899        if not self._interwiki_map: 
     900            self._update() 
     901        keys = self._interwiki_map.keys() 
     902        keys.sort() 
     903        buf = StringIO() 
     904        buf.write('<table><tr><th>Prefix</th><td>Site</td></tr>\n') 
     905        for k in keys: 
     906            prefix, url, title = self._interwiki_map[k] 
     907            shortened_url = url and url[:-1] 
     908            description = title == prefix and shortened_url or title 
     909            buf.write('<tr>\n' + 
     910                      ('<td><a href="%sRecentChanges">%s</a></td>' 
     911                       '<td><a href="%s">%s</a></td>\n') \ 
     912                      % (url, prefix, shortened_url, description) + 
     913                      '</tr>\n') 
     914        buf.write('</table>\n') 
     915        return buf.getvalue() 
  • trac/web/standalone.py

     
    206206        self.auths = auths 
    207207 
    208208        self.projects = {} 
     209        siblings = {} 
    209210        for env_path in env_paths: 
    210211            # Remove trailing slashes 
    211212            while env_path and not os.path.split(env_path)[1]: 
     
    217218                                    % (env_path, self.projects[project]) 
    218219            else: 
    219220                self.projects[project] = env_path 
     221            env = get_environment(None, self.get_env_opts(project)) 
     222            siblings[project] = env 
     223        for p in siblings.values(): 
     224            p.siblings = siblings 
    220225 
    221226    def get_env_opts(self, project=None): 
    222227        if self.env_parent_dir: 
    223228            opts = self.env_parent_dir.items() 
    224229        else: 
    225230            opts = [('TRAC_ENV', self.projects[project])] 
    226         return dict(opts + os.environ.items()) 
     231        return dict(os.environ.items() + opts) # TODO: backport 
    227232 
    228233    def send_project_index(self, req): 
    229234        if self.env_parent_dir: