kernel_feat.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. # coding=utf-8
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. u"""
  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. scripts/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 subprocess
  27. import sys
  28. from os import path
  29. from docutils import nodes, statemachine
  30. from docutils.statemachine import ViewList
  31. from docutils.parsers.rst import directives, Directive
  32. from docutils.utils.error_reporting import ErrorString
  33. #
  34. # AutodocReporter is only good up to Sphinx 1.7
  35. #
  36. import sphinx
  37. Use_SSI = sphinx.__version__[:3] >= '1.7'
  38. if Use_SSI:
  39. from sphinx.util.docutils import switch_source_input
  40. else:
  41. from sphinx.ext.autodoc import AutodocReporter
  42. __version__ = '1.0'
  43. def setup(app):
  44. app.add_directive("kernel-feat", KernelFeat)
  45. return dict(
  46. version = __version__
  47. , parallel_read_safe = True
  48. , parallel_write_safe = True
  49. )
  50. class KernelFeat(Directive):
  51. u"""KernelFeat (``kernel-feat``) directive"""
  52. required_arguments = 1
  53. optional_arguments = 2
  54. has_content = False
  55. final_argument_whitespace = True
  56. option_spec = {
  57. "debug" : directives.flag
  58. }
  59. def warn(self, message, **replace):
  60. replace["fname"] = self.state.document.current_source
  61. replace["line_no"] = replace.get("line_no", self.lineno)
  62. message = ("%(fname)s:%(line_no)s: [kernel-feat WARN] : " + message) % replace
  63. self.state.document.settings.env.app.warn(message, prefix="")
  64. def run(self):
  65. doc = self.state.document
  66. if not doc.settings.file_insertion_enabled:
  67. raise self.warning("docutils: file insertion disabled")
  68. env = doc.settings.env
  69. cwd = path.dirname(doc.current_source)
  70. cmd = "get_feat.pl rest --dir "
  71. cmd += self.arguments[0]
  72. if len(self.arguments) > 1:
  73. cmd += " --arch " + self.arguments[1]
  74. srctree = path.abspath(os.environ["srctree"])
  75. fname = cmd
  76. # extend PATH with $(srctree)/scripts
  77. path_env = os.pathsep.join([
  78. srctree + os.sep + "scripts",
  79. os.environ["PATH"]
  80. ])
  81. shell_env = os.environ.copy()
  82. shell_env["PATH"] = path_env
  83. shell_env["srctree"] = srctree
  84. lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
  85. nodeList = self.nestedParse(lines, fname)
  86. return nodeList
  87. def runCmd(self, cmd, **kwargs):
  88. u"""Run command ``cmd`` and return it's stdout as unicode."""
  89. try:
  90. proc = subprocess.Popen(
  91. cmd
  92. , stdout = subprocess.PIPE
  93. , stderr = subprocess.PIPE
  94. , **kwargs
  95. )
  96. out, err = proc.communicate()
  97. out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
  98. if proc.returncode != 0:
  99. raise self.severe(
  100. u"command '%s' failed with return code %d"
  101. % (cmd, proc.returncode)
  102. )
  103. except OSError as exc:
  104. raise self.severe(u"problems with '%s' directive: %s."
  105. % (self.name, ErrorString(exc)))
  106. return out
  107. def nestedParse(self, lines, fname):
  108. content = ViewList()
  109. node = nodes.section()
  110. if "debug" in self.options:
  111. code_block = "\n\n.. code-block:: rst\n :linenos:\n"
  112. for l in lines.split("\n"):
  113. code_block += "\n " + l
  114. lines = code_block + "\n\n"
  115. for c, l in enumerate(lines.split("\n")):
  116. content.append(l, fname, c)
  117. buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
  118. if Use_SSI:
  119. with switch_source_input(self.state, content):
  120. self.state.nested_parse(content, 0, node, match_titles=1)
  121. else:
  122. self.state.memo.title_styles = []
  123. self.state.memo.section_level = 0
  124. self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
  125. try:
  126. self.state.nested_parse(content, 0, node, match_titles=1)
  127. finally:
  128. self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
  129. return node.children