"Fossies" - the Fresh Open Source Software Archive

Member "PURELIB/trac/wiki/interwiki.py" (27 Aug 2019, 7401 Bytes) of package /windows/misc/Trac-1.4.win32.exe:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "interwiki.py": 1.3.5_vs_1.3.6.

    1 # -*- coding: utf-8 -*-
    2 #
    3 # Copyright (C) 2005-2019 Edgewall Software
    4 # Copyright (C) 2005-2006 Christian Boos <cboos@edgewall.org>
    5 # All rights reserved.
    6 #
    7 # This software is licensed as described in the file COPYING, which
    8 # you should have received as part of this distribution. The terms
    9 # are also available at https://trac.edgewall.org/wiki/TracLicense.
   10 #
   11 # This software consists of voluntary contributions made by many
   12 # individuals. For the exact contribution history, see the revision
   13 # history and logs, available at https://trac.edgewall.org/log/.
   14 #
   15 # Author: Christian Boos <cboos@edgewall.org>
   16 
   17 import re
   18 
   19 from trac.cache import cached
   20 from trac.config import ConfigSection
   21 from trac.core import *
   22 from trac.util import lazy
   23 from trac.util.html import tag
   24 from trac.util.translation import _, N_
   25 from trac.wiki.api import IWikiChangeListener, IWikiMacroProvider, WikiSystem
   26 from trac.wiki.parser import WikiParser
   27 from trac.wiki.formatter import split_url_into_path_query_fragment
   28 
   29 
   30 class InterWikiMap(Component):
   31     """InterWiki map manager."""
   32 
   33     implements(IWikiChangeListener, IWikiMacroProvider)
   34 
   35     interwiki_section = ConfigSection('interwiki',
   36         """Every option in the `[interwiki]` section defines one InterWiki
   37         prefix. The option name defines the prefix. The option value defines
   38         the URL, optionally followed by a description separated from the URL
   39         by whitespace. Parametric URLs are supported as well.
   40 
   41         '''Example:'''
   42         {{{
   43         [interwiki]
   44         MeatBall = http://www.usemod.com/cgi-bin/mb.pl?
   45         PEP = http://www.python.org/peps/pep-$1.html Python Enhancement Proposal $1
   46         tsvn = tsvn: Interact with TortoiseSvn
   47         }}}
   48         """)
   49 
   50     _page_name = 'InterMapTxt'
   51     _interwiki_re = re.compile(r"(%s)[ \t]+([^ \t]+)(?:[ \t]+#(.*))?" %
   52                                WikiParser.LINK_SCHEME, re.UNICODE)
   53     _argspec_re = re.compile(r"\$\d")
   54 
   55     # The component itself behaves as a read-only map
   56 
   57     def __contains__(self, ns):
   58         return ns.upper() in self.interwiki_map
   59 
   60     def __getitem__(self, ns):
   61         return self.interwiki_map[ns.upper()]
   62 
   63     def keys(self):
   64         return list(self.interwiki_map)
   65 
   66     # Expansion of positional arguments ($1, $2, ...) in URL and title
   67     def _expand(self, txt, args):
   68         """Replace "$1" by the first args, "$2" by the second, etc."""
   69         def setarg(match):
   70             num = int(match.group()[1:])
   71             return args[num - 1] if 0 < num <= len(args) else ''
   72         return re.sub(InterWikiMap._argspec_re, setarg, txt)
   73 
   74     def _expand_or_append(self, txt, args):
   75         """Like expand, but also append first arg if there's no "$"."""
   76         if not args:
   77             return txt
   78         expanded = self._expand(txt, args)
   79         return txt + args[0] if expanded == txt else expanded
   80 
   81     def url(self, ns, target):
   82         """Return `(url, title)` for the given InterWiki `ns`.
   83 
   84         Expand the colon-separated `target` arguments.
   85         """
   86         ns, url, title = self[ns]
   87         maxargnum = max([0] + [int(a[1:]) for a in
   88                                re.findall(InterWikiMap._argspec_re, url)])
   89         target, query, fragment = split_url_into_path_query_fragment(target)
   90         if maxargnum > 0:
   91             args = target.split(':', (maxargnum - 1))
   92         else:
   93             args = [target]
   94         url = self._expand_or_append(url, args)
   95         ntarget, nquery, nfragment = split_url_into_path_query_fragment(url)
   96         if query and nquery:
   97             nquery = '%s&%s' % (nquery, query[1:])
   98         else:
   99             nquery = nquery or query
  100         nfragment = fragment or nfragment # user provided takes precedence
  101         expanded_url = ntarget + nquery + nfragment
  102         if not self._is_safe_url(expanded_url):
  103             expanded_url = ''
  104         expanded_title = self._expand(title, args)
  105         if expanded_title == title:
  106             expanded_title = _("%(target)s in %(name)s",
  107                                target=target, name=title)
  108         return expanded_url, expanded_title
  109 
  110     # IWikiChangeListener methods
  111 
  112     def wiki_page_added(self, page):
  113         if page.name == InterWikiMap._page_name:
  114             del self.interwiki_map
  115 
  116     def wiki_page_changed(self, page, version, t, comment, author):
  117         if page.name == InterWikiMap._page_name:
  118             del self.interwiki_map
  119 
  120     def wiki_page_deleted(self, page):
  121         if page.name == InterWikiMap._page_name:
  122             del self.interwiki_map
  123 
  124     def wiki_page_version_deleted(self, page):
  125         if page.name == InterWikiMap._page_name:
  126             del self.interwiki_map
  127 
  128     @cached
  129     def interwiki_map(self):
  130         """Map from upper-cased namespaces to (namespace, prefix, title)
  131         values.
  132         """
  133         from trac.wiki.model import WikiPage
  134         map = {}
  135         content = WikiPage(self.env, InterWikiMap._page_name).text
  136         in_map = False
  137         for line in content.split('\n'):
  138             if in_map:
  139                 if line.startswith('----'):
  140                     in_map = False
  141                 else:
  142                     m = re.match(InterWikiMap._interwiki_re, line)
  143                     if m:
  144                         prefix, url, title = m.groups()
  145                         url = url.strip()
  146                         title = title.strip() if title else prefix
  147                         map[prefix.upper()] = (prefix, url, title)
  148             elif line.startswith('----'):
  149                 in_map = True
  150         for prefix, value in self.interwiki_section.options():
  151             value = value.split(None, 1)
  152             if value:
  153                 url = value[0].strip()
  154                 title = value[1].strip() if len(value) > 1 else prefix
  155                 map[prefix.upper()] = (prefix, url, title)
  156         return map
  157 
  158     # IWikiMacroProvider methods
  159 
  160     def get_macros(self):
  161         yield 'InterWiki'
  162 
  163     def get_macro_description(self, name):
  164         return 'messages', \
  165                N_("Provide a description list for the known InterWiki "
  166                   "prefixes.")
  167 
  168     def expand_macro(self, formatter, name, content):
  169         interwikis = []
  170         for k in sorted(self.keys()):
  171             prefix, url, title = self[k]
  172             interwikis.append({
  173                 'prefix': prefix, 'url': url, 'title': title,
  174                 'rc_url': self._expand_or_append(url, ['RecentChanges']),
  175                 'description': url if title == prefix else title})
  176 
  177         return tag.table(tag.tr(tag.th(tag.em(_("Prefix"))),
  178                                 tag.th(tag.em(_("Site")))),
  179                          [tag.tr(tag.td(tag.a(w['prefix'], href=w['rc_url'])),
  180                                  tag.td(tag.a(w['description'],
  181                                               href=w['url'])))
  182                           for w in interwikis ],
  183                          class_="wiki interwiki")
  184 
  185     # Internal methods
  186 
  187     def _is_safe_url(self, url):
  188         return WikiSystem(self.env).render_unsafe_content or \
  189                ':' not in url or \
  190                url.split(':', 1)[0] in self._safe_schemes
  191 
  192     @lazy
  193     def _safe_schemes(self):
  194         return set(WikiSystem(self.env).safe_schemes)