3 # Copyright © 2016 Intel Corporation
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 # Jani Nikula <jani.nikula@intel.com>
27 # Please make sure this works on both python2 and python3.
37 from docutils
import nodes
, statemachine
38 from docutils
.statemachine
import ViewList
39 from docutils
.parsers
.rst
import directives
, Directive
42 # AutodocReporter is only good up to Sphinx 1.7
46 Use_SSI
= sphinx
.__version
__[:3] >= '1.7'
48 from sphinx
.util
.docutils
import switch_source_input
50 from sphinx
.ext
.autodoc
import AutodocReporter
56 class KernelDocDirective(Directive
):
57 """Extract kernel-doc comments from the specified file"""
59 optional_arguments
= 4
61 'doc': directives
.unchanged_required
,
62 'export': directives
.unchanged
,
63 'internal': directives
.unchanged
,
64 'identifiers': directives
.unchanged
,
65 'no-identifiers': directives
.unchanged
,
66 'functions': directives
.unchanged
,
71 env
= self
.state
.document
.settings
.env
72 cmd
= [env
.config
.kerneldoc_bin
, '-rst', '-enable-lineno']
74 # Pass the version string to kernel-doc, as it needs to use a different
75 # dialect, depending what the C domain supports for each specific
77 cmd
+= ['-sphinx-version', sphinx
.__version
__]
79 filename
= env
.config
.kerneldoc_srctree
+ '/' + self
.arguments
[0]
80 export_file_patterns
= []
82 # Tell sphinx of the dependency
83 env
.note_dependency(os
.path
.abspath(filename
))
85 tab_width
= self
.options
.get('tab-width', self
.state
.document
.settings
.tab_width
)
87 # 'function' is an alias of 'identifiers'
88 if 'functions' in self
.options
:
89 self
.options
['identifiers'] = self
.options
.get('functions')
91 # FIXME: make this nicer and more robust against errors
92 if 'export' in self
.options
:
94 export_file_patterns
= str(self
.options
.get('export')).split()
95 elif 'internal' in self
.options
:
97 export_file_patterns
= str(self
.options
.get('internal')).split()
98 elif 'doc' in self
.options
:
99 cmd
+= ['-function', str(self
.options
.get('doc'))]
100 elif 'identifiers' in self
.options
:
101 identifiers
= self
.options
.get('identifiers').split()
103 for i
in identifiers
:
104 cmd
+= ['-function', i
]
106 cmd
+= ['-no-doc-sections']
108 if 'no-identifiers' in self
.options
:
109 no_identifiers
= self
.options
.get('no-identifiers').split()
111 for i
in no_identifiers
:
112 cmd
+= ['-nosymbol', i
]
114 for pattern
in export_file_patterns
:
115 for f
in glob
.glob(env
.config
.kerneldoc_srctree
+ '/' + pattern
):
116 env
.note_dependency(os
.path
.abspath(f
))
117 cmd
+= ['-export-file', f
]
122 kernellog
.verbose(env
.app
,
123 'calling kernel-doc \'%s\'' % (" ".join(cmd
)))
125 p
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
126 out
, err
= p
.communicate()
128 out
, err
= codecs
.decode(out
, 'utf-8'), codecs
.decode(err
, 'utf-8')
130 if p
.returncode
!= 0:
131 sys
.stderr
.write(err
)
133 kernellog
.warn(env
.app
,
134 'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd
), p
.returncode
))
135 return [nodes
.error(None, nodes
.paragraph(text
= "kernel-doc missing"))]
136 elif env
.config
.kerneldoc_verbosity
> 0:
137 sys
.stderr
.write(err
)
139 lines
= statemachine
.string2lines(out
, tab_width
, convert_whitespace
=True)
143 line_regex
= re
.compile("^#define LINENO ([0-9]+)$")
145 match
= line_regex
.search(line
)
147 # sphinx counts lines from 0
148 lineoffset
= int(match
.group(1)) - 1
149 # we must eat our comments since the upset the markup
151 doc
= env
.srcdir
+ "/" + env
.docname
+ ":" + str(self
.lineno
)
152 result
.append(line
, doc
+ ": " + filename
, lineoffset
)
155 node
= nodes
.section()
156 self
.do_parse(result
, node
)
160 except Exception as e
: # pylint: disable=W0703
161 kernellog
.warn(env
.app
, 'kernel-doc \'%s\' processing failed with: %s' %
162 (" ".join(cmd
), str(e
)))
163 return [nodes
.error(None, nodes
.paragraph(text
= "kernel-doc missing"))]
165 def do_parse(self
, result
, node
):
167 with
switch_source_input(self
.state
, result
):
168 self
.state
.nested_parse(result
, 0, node
, match_titles
=1)
170 save
= self
.state
.memo
.title_styles
, self
.state
.memo
.section_level
, self
.state
.memo
.reporter
171 self
.state
.memo
.reporter
= AutodocReporter(result
, self
.state
.memo
.reporter
)
172 self
.state
.memo
.title_styles
, self
.state
.memo
.section_level
= [], 0
174 self
.state
.nested_parse(result
, 0, node
, match_titles
=1)
176 self
.state
.memo
.title_styles
, self
.state
.memo
.section_level
, self
.state
.memo
.reporter
= save
180 app
.add_config_value('kerneldoc_bin', None, 'env')
181 app
.add_config_value('kerneldoc_srctree', None, 'env')
182 app
.add_config_value('kerneldoc_verbosity', 1, 'env')
184 app
.add_directive('kernel-doc', KernelDocDirective
)
187 version
= __version__
,
188 parallel_read_safe
= True,
189 parallel_write_safe
= True