bin/gen_release_notes.py: more robust rST escaping
This copies code from the xml2rst to escape rST strings. Hopefully this will be more robust than what we've done so far. I really wish docutils would have utils for this directly, seems kinda essential. Reviewed-by: Dylan Baker <dylan@pnwbakers.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9917>
This commit is contained in:

committed by
Marge Bot

parent
997c94eb33
commit
7dc1b57abb
@@ -36,6 +36,8 @@ import aiohttp
|
|||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
from mako import exceptions
|
from mako import exceptions
|
||||||
|
|
||||||
|
import docutils.utils
|
||||||
|
import docutils.parsers.rst.states as states
|
||||||
|
|
||||||
CURRENT_GL_VERSION = '4.6'
|
CURRENT_GL_VERSION = '4.6'
|
||||||
CURRENT_VK_VERSION = '1.2'
|
CURRENT_VK_VERSION = '1.2'
|
||||||
@@ -101,16 +103,74 @@ TEMPLATE = Template(textwrap.dedent("""\
|
|||||||
"""))
|
"""))
|
||||||
|
|
||||||
|
|
||||||
def rst_escape(unsafe_str: str) -> str:
|
# copied from https://docutils.sourceforge.io/sandbox/xml2rst/xml2rstlib/markup.py
|
||||||
"Escape rST special chars when they follow or preceed a whitespace"
|
class Inliner(states.Inliner):
|
||||||
special = re.escape(r'`<>*_#[]|')
|
"""
|
||||||
unsafe_str = re.sub(r'(^|\s)([' + special + r'])',
|
Recognizer for inline markup. Derive this from the original inline
|
||||||
r'\1\\\2',
|
markup parser for best results.
|
||||||
unsafe_str)
|
"""
|
||||||
unsafe_str = re.sub(r'([' + special + r'])(\s|$)',
|
|
||||||
r'\\\1\2',
|
# Copy static attributes from super class
|
||||||
unsafe_str)
|
vars().update(vars(states.Inliner))
|
||||||
return unsafe_str
|
|
||||||
|
def quoteInline(self, text):
|
||||||
|
"""
|
||||||
|
`text`: ``str``
|
||||||
|
Return `text` with inline markup quoted.
|
||||||
|
"""
|
||||||
|
# Method inspired by `states.Inliner.parse`
|
||||||
|
self.document = docutils.utils.new_document("<string>")
|
||||||
|
self.document.settings.trim_footnote_reference_space = False
|
||||||
|
self.document.settings.character_level_inline_markup = False
|
||||||
|
self.document.settings.pep_references = False
|
||||||
|
self.document.settings.rfc_references = False
|
||||||
|
|
||||||
|
self.init_customizations(self.document.settings)
|
||||||
|
|
||||||
|
self.reporter = self.document.reporter
|
||||||
|
self.reporter.stream = None
|
||||||
|
self.language = None
|
||||||
|
self.parent = self.document
|
||||||
|
remaining = docutils.utils.escape2null(text)
|
||||||
|
checked = ""
|
||||||
|
processed = []
|
||||||
|
unprocessed = []
|
||||||
|
messages = []
|
||||||
|
while remaining:
|
||||||
|
original = remaining
|
||||||
|
match = self.patterns.initial.search(remaining)
|
||||||
|
if match:
|
||||||
|
groups = match.groupdict()
|
||||||
|
method = self.dispatch[groups['start'] or groups['backquote']
|
||||||
|
or groups['refend'] or groups['fnend']]
|
||||||
|
before, inlines, remaining, sysmessages = method(self, match, 0)
|
||||||
|
checked += before
|
||||||
|
if inlines:
|
||||||
|
assert len(inlines) == 1, "More than one inline found"
|
||||||
|
inline = original[len(before)
|
||||||
|
:len(original) - len(remaining)]
|
||||||
|
rolePfx = re.search("^:" + self.simplename + ":(?=`)",
|
||||||
|
inline)
|
||||||
|
refSfx = re.search("_+$", inline)
|
||||||
|
if rolePfx:
|
||||||
|
# Prefixed roles need to be quoted in the middle
|
||||||
|
checked += (inline[:rolePfx.end()] + "\\"
|
||||||
|
+ inline[rolePfx.end():])
|
||||||
|
elif refSfx and not re.search("^`", inline):
|
||||||
|
# Pure reference markup needs to be quoted at the end
|
||||||
|
checked += (inline[:refSfx.start()] + "\\"
|
||||||
|
+ inline[refSfx.start():])
|
||||||
|
else:
|
||||||
|
# Quote other inlines by prefixing
|
||||||
|
checked += "\\" + inline
|
||||||
|
else:
|
||||||
|
checked += remaining
|
||||||
|
break
|
||||||
|
# Quote all original backslashes
|
||||||
|
checked = re.sub('\x00', "\\\x00", checked)
|
||||||
|
return docutils.utils.unescape(checked, 1)
|
||||||
|
|
||||||
|
inliner = Inliner();
|
||||||
|
|
||||||
|
|
||||||
async def gather_commits(version: str) -> str:
|
async def gather_commits(version: str) -> str:
|
||||||
@@ -262,7 +322,7 @@ async def main() -> None:
|
|||||||
header_underline=header_underline,
|
header_underline=header_underline,
|
||||||
previous_version=previous_version,
|
previous_version=previous_version,
|
||||||
vk_version=CURRENT_VK_VERSION,
|
vk_version=CURRENT_VK_VERSION,
|
||||||
rst_escape=rst_escape,
|
rst_escape=inliner.quoteInline,
|
||||||
))
|
))
|
||||||
except:
|
except:
|
||||||
print(exceptions.text_error_template().render())
|
print(exceptions.text_error_template().render())
|
||||||
|
Reference in New Issue
Block a user