Back to home page

OSCL-LXR

 
 

    


0001 # coding=utf-8
0002 #
0003 # Copyright © 2016 Intel Corporation
0004 #
0005 # Permission is hereby granted, free of charge, to any person obtaining a
0006 # copy of this software and associated documentation files (the "Software"),
0007 # to deal in the Software without restriction, including without limitation
0008 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
0009 # and/or sell copies of the Software, and to permit persons to whom the
0010 # Software is furnished to do so, subject to the following conditions:
0011 #
0012 # The above copyright notice and this permission notice (including the next
0013 # paragraph) shall be included in all copies or substantial portions of the
0014 # Software.
0015 #
0016 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0017 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0018 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0019 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0020 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0021 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0022 # IN THE SOFTWARE.
0023 #
0024 # Authors:
0025 #    Jani Nikula <jani.nikula@intel.com>
0026 #
0027 # Please make sure this works on both python2 and python3.
0028 #
0029 
0030 import codecs
0031 import os
0032 import subprocess
0033 import sys
0034 import re
0035 import glob
0036 
0037 from docutils import nodes, statemachine
0038 from docutils.statemachine import ViewList
0039 from docutils.parsers.rst import directives, Directive
0040 import sphinx
0041 from sphinx.util.docutils import switch_source_input
0042 import kernellog
0043 
0044 __version__  = '1.0'
0045 
0046 class KernelDocDirective(Directive):
0047     """Extract kernel-doc comments from the specified file"""
0048     required_argument = 1
0049     optional_arguments = 4
0050     option_spec = {
0051         'doc': directives.unchanged_required,
0052         'export': directives.unchanged,
0053         'internal': directives.unchanged,
0054         'identifiers': directives.unchanged,
0055         'no-identifiers': directives.unchanged,
0056         'functions': directives.unchanged,
0057     }
0058     has_content = False
0059 
0060     def run(self):
0061         env = self.state.document.settings.env
0062         cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
0063 
0064     # Pass the version string to kernel-doc, as it needs to use a different
0065     # dialect, depending what the C domain supports for each specific
0066     # Sphinx versions
0067         cmd += ['-sphinx-version', sphinx.__version__]
0068 
0069         filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
0070         export_file_patterns = []
0071 
0072         # Tell sphinx of the dependency
0073         env.note_dependency(os.path.abspath(filename))
0074 
0075         tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
0076 
0077         # 'function' is an alias of 'identifiers'
0078         if 'functions' in self.options:
0079             self.options['identifiers'] = self.options.get('functions')
0080 
0081         # FIXME: make this nicer and more robust against errors
0082         if 'export' in self.options:
0083             cmd += ['-export']
0084             export_file_patterns = str(self.options.get('export')).split()
0085         elif 'internal' in self.options:
0086             cmd += ['-internal']
0087             export_file_patterns = str(self.options.get('internal')).split()
0088         elif 'doc' in self.options:
0089             cmd += ['-function', str(self.options.get('doc'))]
0090         elif 'identifiers' in self.options:
0091             identifiers = self.options.get('identifiers').split()
0092             if identifiers:
0093                 for i in identifiers:
0094                     cmd += ['-function', i]
0095             else:
0096                 cmd += ['-no-doc-sections']
0097 
0098         if 'no-identifiers' in self.options:
0099             no_identifiers = self.options.get('no-identifiers').split()
0100             if no_identifiers:
0101                 for i in no_identifiers:
0102                     cmd += ['-nosymbol', i]
0103 
0104         for pattern in export_file_patterns:
0105             for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
0106                 env.note_dependency(os.path.abspath(f))
0107                 cmd += ['-export-file', f]
0108 
0109         cmd += [filename]
0110 
0111         try:
0112             kernellog.verbose(env.app,
0113                               'calling kernel-doc \'%s\'' % (" ".join(cmd)))
0114 
0115             p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
0116             out, err = p.communicate()
0117 
0118             out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
0119 
0120             if p.returncode != 0:
0121                 sys.stderr.write(err)
0122 
0123                 kernellog.warn(env.app,
0124                                'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
0125                 return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
0126             elif env.config.kerneldoc_verbosity > 0:
0127                 sys.stderr.write(err)
0128 
0129             lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
0130             result = ViewList()
0131 
0132             lineoffset = 0;
0133             line_regex = re.compile("^\.\. LINENO ([0-9]+)$")
0134             for line in lines:
0135                 match = line_regex.search(line)
0136                 if match:
0137                     # sphinx counts lines from 0
0138                     lineoffset = int(match.group(1)) - 1
0139                     # we must eat our comments since the upset the markup
0140                 else:
0141                     doc = env.srcdir + "/" + env.docname + ":" + str(self.lineno)
0142                     result.append(line, doc + ": " + filename, lineoffset)
0143                     lineoffset += 1
0144 
0145             node = nodes.section()
0146             self.do_parse(result, node)
0147 
0148             return node.children
0149 
0150         except Exception as e:  # pylint: disable=W0703
0151             kernellog.warn(env.app, 'kernel-doc \'%s\' processing failed with: %s' %
0152                            (" ".join(cmd), str(e)))
0153             return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
0154 
0155     def do_parse(self, result, node):
0156         with switch_source_input(self.state, result):
0157             self.state.nested_parse(result, 0, node, match_titles=1)
0158 
0159 def setup(app):
0160     app.add_config_value('kerneldoc_bin', None, 'env')
0161     app.add_config_value('kerneldoc_srctree', None, 'env')
0162     app.add_config_value('kerneldoc_verbosity', 1, 'env')
0163 
0164     app.add_directive('kernel-doc', KernelDocDirective)
0165 
0166     return dict(
0167         version = __version__,
0168         parallel_read_safe = True,
0169         parallel_write_safe = True
0170     )