diff --git a/config.py.sample b/config.py.sample index b18b1e4..87ee7f7 100644 --- a/config.py.sample +++ b/config.py.sample @@ -2,3 +2,5 @@ USER_MAPPING = { 'adi': ('adiroiban', 'Adi Roiban '), } + +TRAC_TICKET_PREFIX = 'https://trac.chevah.com/ticket/' diff --git a/test/test_wiki_trac_rst_convert.py b/test/test_wiki_trac_rst_convert.py index 0f4ef86..82dbe7d 100644 --- a/test/test_wiki_trac_rst_convert.py +++ b/test/test_wiki_trac_rst_convert.py @@ -3,7 +3,7 @@ from wiki_trac_rst_convert import convert_content -class TracRstToVanillaRst(unittest.TestCase): +class TracToVanillaRst(unittest.TestCase): """ Test conversion of content from Trac-flavored reStructuredText to vanilla reStructuredText, that is supported by GitHub @@ -107,6 +107,59 @@ def test_several_trac_wiki_rst_links_with_content(self): ' List of free software used by Chevah Project.' ) + def test_tracwiki_general_link(self): + """ + Process general links from TracWiki format to plain RST links + """ + self.assertConvertedContent( + '`Buildbot `_\n', + '[https://chevah.com/buildbot/ Buildbot]' + ) + + def test_tracwiki_wiki_link(self): + """ + Process wiki links from TracWiki format to GitHub-compatible + RST wiki links. + There are various combinations of no-link-text, link-text-same- + as-article-name, and link-text-different-from-article-name. + """ + self.assertConvertedContent( + '`Project management and administration `_\n', + '[wiki:Administrative Project management and administration]' + ) + self.assertConvertedContent( + '``_\n', + '[wiki:Administrative Administrative]' + ) + self.assertConvertedContent( + '``_\n', + '[wiki:"Administrative"]' + ) + self.assertConvertedContent( + '``_\n', + '[wiki:"Administrative/AllHandMeeting/Past"]' + ) + self.assertConvertedContent( + '``_\n', + '`[wiki:Infrastructure/Services/FileServer]`:trac:' + ) + self.assertConvertedContent( + '`Overton `_\n', + '`[wiki:Infrastructure/Machines/Overton Overton]`:trac:' + ) + + def test_trac_ticket(self): + """ + Trac tickets get forwarded to the correct address. + This use case requires `config.py` with the following setting: + + TRAC_TICKET_PREFIX = 'https://trac.chevah.com/ticket/' + """ + self.assertConvertedContent( + '`Trac #738 `_\n', + ':trac:`#738`' + ) + if __name__ == '__main__': unittest.main() diff --git a/wiki_trac_rst_convert.py b/wiki_trac_rst_convert.py index 2d6742b..b2cff4e 100644 --- a/wiki_trac_rst_convert.py +++ b/wiki_trac_rst_convert.py @@ -3,6 +3,8 @@ import sys import os +from config import TRAC_TICKET_PREFIX + def main(): """ @@ -44,36 +46,107 @@ def convert_content(text: str): for seq in to_remove: text = text.replace(seq, '') text = text.strip() + '\n' - text = _trac_rst_wiki_to_github_links(text) + text = _trac_to_github_wiki_links(text) + text = _tracwiki_to_rst_links(text) + text = _tracwiki_wiki_link_with_text_to_github_links(text) + text = _trac_ticket_links(text) return text -def _trac_rst_wiki_to_github_links(text: str): +def _trac_to_github_wiki_links(text: str): """ - Takes RST content with Trac wiki link directives - and coverts the directives to inline GitHub wiki links. + Takes content with Trac wiki link directives and coverts + the directives to inline GitHub wiki links. """ - link_matchers =[re.compile(r) for r in [ + link_matchers = [re.compile(r) for r in [ + # RST markup ':trac:`wiki:(.+?)`', - '`wiki:(.+?)`:trac:' + '`wiki:(.+?)`:trac:', + + # TracWiki markup + '`\[wiki:"?([^ ]+?)"?]`:trac:', + '\[wiki:"?([^ ]+?)"?]', ]] for link_re in link_matchers: wiki_titles = re.findall(link_re, text) for title in wiki_titles: - text = re.sub( - link_re, - rf'`<{_wiki_url(title)}>`_', - text, - 1 - ) + text = _sub(link_re, f'`<{_wiki_url(title)}>`_', text) + + return text + + +def _tracwiki_to_rst_links(text: str): + """ + Takes TracWiki markup and converts its links to RST links. + """ + + url = '[a-z]+://[^ ]+' + link_text = '[^]]+' + link_re = re.compile(f'\[({url}) ({link_text})]') + + matches = re.findall(link_re, text) + for url, link_text in matches: + text = _sub(link_re, f'`{link_text} <{url}>`_', text) return text -def _wiki_url(title): +def _tracwiki_wiki_link_with_text_to_github_links(text: str): + """ + Takes TracWiki markup and converts its Wiki links which have + explicit link text into RST links. + If the link text is the same as the article name, generate a more + compact syntax. + """ + + title = '[^ ]+' + link_text = '[^]]+' + + link_matchers = [re.compile(r) for r in [ + f'`\[wiki:({title}) ({link_text})]`:trac:', + f'\[wiki:({title}) ({link_text})]', + ]] + + for link_re in link_matchers: + matches = re.findall(link_re, text) + for title, link_text in matches: + if title == link_text: + text = _sub(link_re, f'`<{_wiki_url(title)}>`_', text) + else: + replacement = f'`{link_text} <{_wiki_url(title)}>`_' + text = _sub(link_re, replacement, text) + + return text + + +def _trac_ticket_links(text: str): + """ + Replace Trac reference to ticket with actual link to the ticket + """ + + ticket_re = ':trac:`#([0-9]+)`' + matches = re.findall(ticket_re, text) + for ticket in matches: + text = _sub( + ticket_re, + f'`Trac #{ticket} <{TRAC_TICKET_PREFIX}{ticket}>`_', + text + ) + return text + + +def _sub(link_re: str, replacement: str, text: str): + """ + Substitute one occurrence of `link_re` in `text` with `replacement`. + Return the resulting new text. + """ + return re.sub(link_re, replacement, text, 1) + + +def _wiki_url(title: str): """ GitHub Wiki collapses directory structure.