|
| 1 | +# -*- coding: iso8859-1 -*- |
| 2 | +# |
| 3 | +# Copyright (C) 2004 Edgewall Software |
| 4 | +# Copyright (C) 2004 Oliver Rutherford |
| 5 | +# |
| 6 | +# Trac is free software; you can redistribute it and/or |
| 7 | +# modify it under the terms of the GNU General Public License as |
| 8 | +# published by the Free Software Foundation; either version 2 of the |
| 9 | +# License, or (at your option) any later version. |
| 10 | +# |
| 11 | +# Trac is distributed in the hope that it will be useful, |
| 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | +# General Public License for more details. |
| 15 | +# |
| 16 | +# You should have received a copy of the GNU General Public License |
| 17 | +# along with this program; if not, write to the Free Software |
| 18 | +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 19 | +# |
| 20 | +# Author: Daniel Lundin |
| 21 | +# Oliver Rutherford |
| 22 | +# |
| 23 | +# Trac support for reStructured Text, including a custom 'trac' directive |
| 24 | +# |
| 25 | +# 'trac' directive code by Oliver Rutherford. |
| 26 | +# |
| 27 | +# Inserts `reference` nodes for TracLinks into the document tree. |
| 28 | + |
| 29 | +import re |
| 30 | + |
| 31 | +from docutils import nodes |
1 | 32 | from docutils.core import publish_string
|
| 33 | +from docutils.parsers.rst import directives |
| 34 | + |
| 35 | +__docformat__ = 'reStructuredText' |
| 36 | + |
| 37 | +TICKET_LINK = re.compile(r'(?:#(\d+))|(?:ticket:(\d+))') |
| 38 | +REPORT_LINK = re.compile(r'(?:{(\d+)})|(?:report:(\d+))') |
| 39 | +CHANGESET_LINK = re.compile(r'(?:\[(\d+)\])|(?:changeset:(\d+))') |
| 40 | +FILE_LINK = re.compile(r'(?:browser|repos|source):([^#]+)#?(.*)') |
| 41 | + |
| 42 | +def _ticket(match,arguments): |
| 43 | + """_ticket(match,arguments) -> (uri,text)""" |
| 44 | + template = 'ticket/%s' |
| 45 | + ticket = int(filter(None,match.groups())[0]) |
| 46 | + text = arguments[int(len(arguments) == 2)] |
| 47 | + return (template % (ticket,), text) |
| 48 | + |
| 49 | +def _report(match,arguments): |
| 50 | + """_report(match,arguments) -> (uri,text)""" |
| 51 | + template = 'report/%d' |
| 52 | + report = int(filter(None,match.groups())[0]) |
| 53 | + text = arguments[int(len(arguments) == 2)] |
| 54 | + return (template % (report,), text) |
| 55 | + |
| 56 | +def _changeset(match,arguments): |
| 57 | + """_changeset(match,arguments) -> (uri,text)""" |
| 58 | + template = 'changeset/%d' |
| 59 | + changeset = int(filter(None,match.groups())[0]) |
| 60 | + text = arguments[int(len(arguments) == 2)] |
| 61 | + return (template % (changeset,), text) |
| 62 | + |
| 63 | +def _browser(match,arguments): |
| 64 | + """_browser(match,arguments) -> (uri,text)""" |
| 65 | + template = 'browser/%s' |
| 66 | + matches = filter(None,match.groups()) |
| 67 | + if len(matches) == 2: |
| 68 | + path,revision = matches |
| 69 | + else: |
| 70 | + path,revision = matches[0],'' |
| 71 | + uri = template % path |
| 72 | + if revision: |
| 73 | + uri += '?rev=%s' % revision |
| 74 | + text = arguments[int(len(arguments) == 2)] |
| 75 | + return (uri, text) |
| 76 | + |
| 77 | +# TracLink REs and callback functions |
| 78 | +LINKS = [ |
| 79 | + (TICKET_LINK, _ticket), |
| 80 | + (REPORT_LINK, _report), |
| 81 | + (CHANGESET_LINK, _changeset), |
| 82 | + (FILE_LINK, _browser), |
| 83 | +] |
| 84 | + |
| 85 | +def trac(name,arguments,options,content,lineno, |
| 86 | + content_offset,block_text,state,state_machine): |
| 87 | + """Inserts a `reference` node into the document |
| 88 | + for a given `TracLink`_, based on the content |
| 89 | + of the arguments. |
| 90 | +
|
| 91 | + Usage:: |
| 92 | +
|
| 93 | + .. trac:: target [text] |
| 94 | +
|
| 95 | + ``target`` may be one of the following: |
| 96 | +
|
| 97 | + * For tickets: ``#1`` or ``ticket:1`` |
| 98 | + * For reports: ``{1}`` or ``report:1`` |
| 99 | + * For changesets: ``[1]`` or ``changeset:1`` |
| 100 | + * For files: ``source:trunk/COPYING`` |
| 101 | +
|
| 102 | + ``[text]`` is optional. If not given, ``target`` is |
| 103 | + used as the reference text. |
| 104 | +
|
| 105 | + .. _TracLink: http://projects.edgewall.com/trac/wiki/TracLinks |
| 106 | + """ |
| 107 | + |
| 108 | + for (pattern, function) in LINKS: |
| 109 | + m = pattern.match(arguments[0]) |
| 110 | + if m: |
| 111 | + uri,text = function(m,arguments) |
| 112 | + reference = nodes.reference(block_text,text) |
| 113 | + reference['refuri']= uri |
| 114 | + return reference |
| 115 | + |
| 116 | + # didn't find a match (invalid TracLink), |
| 117 | + # report a warning |
| 118 | + warning = state_machine.reporter.warning( |
| 119 | + '%s is not a valid TracLink' % (arguments[0]), |
| 120 | + nodes.literal_block(block_text, block_text), |
| 121 | + line=lineno) |
| 122 | + return [warning] |
| 123 | + |
| 124 | +trac.arguments = (1,1,1) # 1 required arg, 1 optional arg, spaces allowed in last arg |
| 125 | +trac.options = None |
| 126 | +trac.content = None |
| 127 | +directives.register_directive('trac', trac) |
2 | 128 |
|
3 | 129 | def execute(hdf, text):
|
4 | 130 | html = publish_string(text, writer_name = 'html')
|
5 | 131 | return html[html.find('<body>')+6:html.find('</body>')].strip()
|
6 | 132 |
|
| 133 | +# A naive test |
| 134 | +if __name__ == '__main__': |
| 135 | + __test = """ |
| 136 | +=============== |
| 137 | +Trac Link Tests |
| 138 | +=============== |
| 139 | +
|
| 140 | +This document is for testing the ``..trac::`` directive. |
| 141 | +
|
| 142 | +tickets |
| 143 | +======= |
| 144 | +
|
| 145 | +``.. trac:: #1``: |
| 146 | + .. trac:: #1 |
| 147 | +``.. trac:: #1 ticket one``: |
| 148 | + .. trac:: #1 ticket one |
| 149 | +``.. trac:: ticket:1``: |
| 150 | + .. trac:: ticket:1 |
| 151 | +``.. trac:: ticket:1 ticket one``: |
| 152 | + .. trac:: ticket:1 ticket one |
| 153 | +
|
| 154 | +reports |
| 155 | +======= |
| 156 | +
|
| 157 | +``.. trac:: {1}``: |
| 158 | + .. trac:: {1} |
| 159 | +``.. trac:: {1} report one``: |
| 160 | + .. trac:: {1} report one |
| 161 | +``.. trac:: report:1``: |
| 162 | + .. trac:: report:1 |
| 163 | +``.. trac:: report:1 report one``: |
| 164 | + .. trac:: report:1 report one |
| 165 | +
|
| 166 | +changesets |
| 167 | +========== |
| 168 | +
|
| 169 | +``.. trac:: [42]``: |
| 170 | + .. trac:: [42] |
| 171 | +``.. trac:: [42] changeset 42``: |
| 172 | + .. trac:: [42] changeset 42 |
| 173 | +``.. trac:: changeset:42``: |
| 174 | + .. trac:: changeset:42 |
| 175 | +``.. trac:: changeset:42 changeset 42``: |
| 176 | + .. trac:: changeset:42 changeset 42 |
| 177 | +``.. trac:: foo``: |
| 178 | + .. trac:: foo |
| 179 | +
|
| 180 | +files |
| 181 | +===== |
| 182 | +
|
| 183 | +``.. trac:: browser:foo/hoo``: |
| 184 | + .. trac:: browser:foo/hoo |
| 185 | +``.. trac:: repos:foo/hoo foo/hoo``: |
| 186 | + .. trac:: repos:foo/hoo foo/hoo |
| 187 | +``.. trac:: source:foo/hoo hoo in foo``: |
| 188 | + .. trac:: source:foo/hoo hoo in foo |
| 189 | +``.. trac:: browser:foo/hoo#latest latest of foo/hoo``: |
| 190 | + .. trac:: browser:foo/hoo#latest latest of foo/hoo |
| 191 | +``.. trac:: repos:foo/hoo#42 foo/hoo in rev 42``: |
| 192 | + .. trac:: repos:foo/hoo#42 foo/hoo in rev 42 |
| 193 | +""" |
| 194 | + |
| 195 | + html = publish_string(__test, writer_name = 'html') |
| 196 | + print html |
| 197 | + |
| 198 | + |
0 commit comments