kernel_feat.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # coding=utf-8
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. """
  5. kernel-feat
  6. ~~~~~~~~~~~
  7. Implementation of the ``kernel-feat`` reST-directive.
  8. :copyright: Copyright (C) 2016 Markus Heiser
  9. :copyright: Copyright (C) 2016-2019 Mauro Carvalho Chehab
  10. :maintained-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
  11. :license: GPL Version 2, June 1991 see Linux/COPYING for details.
  12. The ``kernel-feat`` (:py:class:`KernelFeat`) directive calls the
  13. tools/docs/get_feat.pl script to parse the Kernel ABI files.
  14. Overview of directive's argument and options.
  15. .. code-block:: rst
  16. .. kernel-feat:: <ABI directory location>
  17. :debug:
  18. The argument ``<ABI directory location>`` is required. It contains the
  19. location of the ABI files to be parsed.
  20. ``debug``
  21. Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
  22. what reST is generated.
  23. """
  24. import codecs
  25. import os
  26. import re
  27. import sys
  28. from docutils import nodes, statemachine
  29. from docutils.statemachine import ViewList
  30. from docutils.parsers.rst import directives, Directive
  31. from sphinx.util.docutils import switch_source_input
  32. srctree = os.path.abspath(os.environ["srctree"])
  33. sys.path.insert(0, os.path.join(srctree, "tools/lib/python"))
  34. from feat.parse_features import ParseFeature # pylint: disable=C0413
  35. def ErrorString(exc): # Shamelessly stolen from docutils
  36. return f'{exc.__class__.__name}: {exc}'
  37. __version__ = '1.0'
  38. def setup(app):
  39. app.add_directive("kernel-feat", KernelFeat)
  40. return dict(
  41. version = __version__
  42. , parallel_read_safe = True
  43. , parallel_write_safe = True
  44. )
  45. class KernelFeat(Directive):
  46. """KernelFeat (``kernel-feat``) directive"""
  47. required_arguments = 1
  48. optional_arguments = 2
  49. has_content = False
  50. final_argument_whitespace = True
  51. option_spec = {
  52. "debug" : directives.flag
  53. }
  54. def warn(self, message, **replace):
  55. replace["fname"] = self.state.document.current_source
  56. replace["line_no"] = replace.get("line_no", self.lineno)
  57. message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
  58. self.state.document.settings.env.app.warn(message, prefix="")
  59. def run(self):
  60. doc = self.state.document
  61. if not doc.settings.file_insertion_enabled:
  62. raise self.warning("docutils: file insertion disabled")
  63. env = doc.settings.env
  64. srctree = os.path.abspath(os.environ["srctree"])
  65. feature_dir = os.path.join(srctree, 'Documentation', self.arguments[0])
  66. feat = ParseFeature(feature_dir, False, True)
  67. feat.parse()
  68. if len(self.arguments) > 1:
  69. arch = self.arguments[1]
  70. lines = feat.output_arch_table(arch)
  71. else:
  72. lines = feat.output_matrix()
  73. line_regex = re.compile(r"^\.\. FILE (\S+)$")
  74. out_lines = ""
  75. for line in lines.split("\n"):
  76. match = line_regex.search(line)
  77. if match:
  78. fname = match.group(1)
  79. # Add the file to Sphinx build dependencies
  80. env.note_dependency(os.path.abspath(fname))
  81. else:
  82. out_lines += line + "\n"
  83. nodeList = self.nestedParse(out_lines, self.arguments[0])
  84. return nodeList
  85. def nestedParse(self, lines, fname):
  86. content = ViewList()
  87. node = nodes.section()
  88. if "debug" in self.options:
  89. code_block = "\n\n.. code-block:: rst\n :linenos:\n"
  90. for l in lines.split("\n"):
  91. code_block += "\n " + l
  92. lines = code_block + "\n\n"
  93. for c, l in enumerate(lines.split("\n")):
  94. content.append(l, fname, c)
  95. buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
  96. with switch_source_input(self.state, content):
  97. self.state.nested_parse(content, 0, node, match_titles=1)
  98. return node.children