doc_utils.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2014-2016 - Copyright Red Hat Inc
  4. Authors:
  5. Ralph Bean <rbean@redhat.com>
  6. Pierre-Yves Chibon <pingou@pingoured.fr>
  7. """
  8. from __future__ import unicode_literals, absolute_import
  9. import docutils
  10. import docutils.core
  11. import docutils.examples
  12. import jinja2
  13. import kitchen.text.converters as ktc
  14. import markupsafe
  15. import textwrap
  16. from pagure.config import config as pagure_config
  17. import pagure.lib.query
  18. import pagure.lib.encoding_utils
  19. def modify_rst(rst, view_file_url=None):
  20. """ Downgrade some of our rst directives if docutils is too old. """
  21. if view_file_url:
  22. rst = rst.replace(".. image:: ", ".. image:: %s" % view_file_url)
  23. # We catch Exception if we want :-p
  24. # pylint: disable=broad-except
  25. try:
  26. # The rst features we need were introduced in this version
  27. minimum = [0, 9]
  28. version = [int(cpt) for cpt in docutils.__version__.split(".")]
  29. # If we're at or later than that version, no need to downgrade
  30. if version >= minimum:
  31. return rst
  32. except Exception: # pragma: no cover
  33. # If there was some error parsing or comparing versions, run the
  34. # substitutions just to be safe.
  35. pass
  36. # On Fedora this will never work as the docutils version is to recent
  37. # Otherwise, make code-blocks into just literal blocks.
  38. substitutions = {".. code-block:: javascript": "::"} # pragma: no cover
  39. for old, new in substitutions.items(): # pragma: no cover
  40. rst = rst.replace(old, new)
  41. return rst # pragma: no cover
  42. def modify_html(html):
  43. """ Perform style substitutions where docutils doesn't do what we want.
  44. """
  45. substitutions = {
  46. '<tt class="docutils literal">': "<code>",
  47. "</tt>": "</code>",
  48. "$$FLAG_STATUSES_COMMAS$$": ", ".join(
  49. sorted(pagure_config["FLAG_STATUSES_LABELS"].keys())
  50. ),
  51. "$$FLAG_SUCCESS$$": pagure_config["FLAG_SUCCESS"],
  52. "$$FLAG_FAILURE$$": pagure_config["FLAG_FAILURE"],
  53. "$$FLAG_PENDING$$": pagure_config["FLAG_PENDING"],
  54. }
  55. for old, new in substitutions.items():
  56. html = html.replace(old, new)
  57. return html
  58. def convert_doc(rst_string, view_file_url=None):
  59. """ Utility to load an RST file and turn it into fancy HTML. """
  60. rst = modify_rst(rst_string, view_file_url)
  61. overrides = {"report_level": "quiet"}
  62. try:
  63. html = docutils.core.publish_parts(
  64. source=rst, writer_name="html", settings_overrides=overrides
  65. )
  66. except Exception:
  67. return "<pre>%s</pre>" % jinja2.escape(rst)
  68. else:
  69. html_string = html["html_body"]
  70. html_string = modify_html(html_string)
  71. html_string = markupsafe.Markup(html_string)
  72. return html_string
  73. def convert_readme(content, ext, view_file_url=None):
  74. """ Convert the provided content according to the extension of the file
  75. provided.
  76. """
  77. output = pagure.lib.encoding_utils.decode(ktc.to_bytes(content))
  78. safe = False
  79. if ext and ext in [".rst"]:
  80. safe = True
  81. output = convert_doc(output, view_file_url)
  82. elif ext and ext in [".mk", ".md", ".markdown"]:
  83. output = pagure.lib.query.text2markdown(output, readme=True)
  84. safe = True
  85. elif not ext or (ext and ext in [".text", ".txt"]):
  86. safe = True
  87. output = "<pre>%s</pre>" % jinja2.escape(output)
  88. return output, safe
  89. def load_doc(endpoint):
  90. """ Utility to load an RST file and turn it into fancy HTML. """
  91. rst = modify_rst(textwrap.dedent(endpoint.__doc__))
  92. api_docs = docutils.examples.html_body(rst)
  93. api_docs = modify_html(api_docs)
  94. api_docs = markupsafe.Markup(api_docs)
  95. return api_docs