4141from sphinx .util .docutils import switch_source_input
4242from sphinx .util import logging
4343
44+ srctree = os .path .abspath (os .environ ["srctree" ])
45+ sys .path .insert (0 , os .path .join (srctree , "scripts/lib/kdoc" ))
46+
47+ from kdoc_files import KernelFiles
48+ from kdoc_output import RestFormat
49+
4450__version__ = '1.0'
51+ use_kfiles = False
4552
4653def cmd_str (cmd ):
4754 """
@@ -82,11 +89,32 @@ class KernelDocDirective(Directive):
8289 logger = logging .getLogger ('kerneldoc' )
8390 verbose = 0
8491
85- def run (self ):
92+ parse_args = {}
93+ msg_args = {}
94+
95+ def handle_args (self ):
96+
8697 env = self .state .document .settings .env
8798 cmd = [env .config .kerneldoc_bin , '-rst' , '-enable-lineno' ]
8899
89100 filename = env .config .kerneldoc_srctree + '/' + self .arguments [0 ]
101+
102+ # Arguments used by KernelFiles.parse() function
103+ self .parse_args = {
104+ "file_list" : [filename ],
105+ "export_file" : []
106+ }
107+
108+ # Arguments used by KernelFiles.msg() function
109+ self .msg_args = {
110+ "enable_lineno" : True ,
111+ "export" : False ,
112+ "internal" : False ,
113+ "symbol" : [],
114+ "nosymbol" : [],
115+ "no_doc_sections" : False
116+ }
117+
90118 export_file_patterns = []
91119
92120 verbose = os .environ .get ("V" )
@@ -99,7 +127,8 @@ def run(self):
99127 # Tell sphinx of the dependency
100128 env .note_dependency (os .path .abspath (filename ))
101129
102- tab_width = self .options .get ('tab-width' , self .state .document .settings .tab_width )
130+ self .tab_width = self .options .get ('tab-width' ,
131+ self .state .document .settings .tab_width )
103132
104133 # 'function' is an alias of 'identifiers'
105134 if 'functions' in self .options :
@@ -108,12 +137,16 @@ def run(self):
108137 # FIXME: make this nicer and more robust against errors
109138 if 'export' in self .options :
110139 cmd += ['-export' ]
140+ self .msg_args ["export" ] = True
111141 export_file_patterns = str (self .options .get ('export' )).split ()
112142 elif 'internal' in self .options :
113143 cmd += ['-internal' ]
144+ self .msg_args ["internal" ] = True
114145 export_file_patterns = str (self .options .get ('internal' )).split ()
115146 elif 'doc' in self .options :
116- cmd += ['-function' , str (self .options .get ('doc' ))]
147+ func = str (self .options .get ('doc' ))
148+ cmd += ['-function' , func ]
149+ self .msg_args ["symbol" ].append (func )
117150 elif 'identifiers' in self .options :
118151 identifiers = self .options .get ('identifiers' ).split ()
119152 if identifiers :
@@ -123,8 +156,10 @@ def run(self):
123156 continue
124157
125158 cmd += ['-function' , i ]
159+ self .msg_args ["symbol" ].append (i )
126160 else :
127161 cmd += ['-no-doc-sections' ]
162+ self .msg_args ["no_doc_sections" ] = True
128163
129164 if 'no-identifiers' in self .options :
130165 no_identifiers = self .options .get ('no-identifiers' ).split ()
@@ -135,6 +170,7 @@ def run(self):
135170 continue
136171
137172 cmd += ['-nosymbol' , i ]
173+ self .msg_args ["nosymbol" ].append (i )
138174
139175 for pattern in export_file_patterns :
140176 pattern = pattern .rstrip ("\\ " ).strip ()
@@ -144,12 +180,29 @@ def run(self):
144180 for f in glob .glob (env .config .kerneldoc_srctree + '/' + pattern ):
145181 env .note_dependency (os .path .abspath (f ))
146182 cmd += ['-export-file' , f ]
183+ self .parse_args ["export_file" ].append (f )
184+
185+ # Export file is needed by both parse and msg, as kernel-doc
186+ # cache exports.
187+ self .msg_args ["export_file" ] = self .parse_args ["export_file" ]
147188
148189 cmd += [filename ]
149190
191+ return cmd
192+
193+ def run_cmd (self ):
194+ """
195+ Execute an external kernel-doc command.
196+ """
197+
198+ env = self .state .document .settings .env
199+ cmd = self .handle_args ()
200+
150201 if self .verbose >= 1 :
151202 print (cmd_str (cmd ))
152203
204+ node = nodes .section ()
205+
153206 try :
154207 self .logger .verbose ("calling kernel-doc '%s'" % (" " .join (cmd )))
155208
@@ -167,7 +220,29 @@ def run(self):
167220 elif env .config .kerneldoc_verbosity > 0 :
168221 sys .stderr .write (err )
169222
170- lines = statemachine .string2lines (out , tab_width , convert_whitespace = True )
223+ except Exception as e : # pylint: disable=W0703
224+ self .logger .warning ("kernel-doc '%s' processing failed with: %s" %
225+ (" " .join (cmd ), str (e )))
226+ return [nodes .error (None , nodes .paragraph (text = "kernel-doc missing" ))]
227+
228+ filenames = self .parse_args ["file_list" ]
229+ for filename in filenames :
230+ ret = self .parse_msg (filename , node , out , cmd )
231+ if ret :
232+ return ret
233+
234+ return node .children
235+
236+ def parse_msg (self , filename , node , out , cmd ):
237+ """
238+ Handles a kernel-doc output for a given file
239+ """
240+
241+ env = self .state .document .settings .env
242+
243+ try :
244+ lines = statemachine .string2lines (out , self .tab_width ,
245+ convert_whitespace = True )
171246 result = ViewList ()
172247
173248 lineoffset = 0 ;
@@ -183,27 +258,74 @@ def run(self):
183258 result .append (line , doc + ": " + filename , lineoffset )
184259 lineoffset += 1
185260
186- node = nodes .section ()
187261 self .do_parse (result , node )
188262
189- return node .children
190-
191263 except Exception as e : # pylint: disable=W0703
192264 self .logger .warning ("kernel-doc '%s' processing failed with: %s" %
193- (" " . join (cmd ), str (e )))
265+ (cmd_str (cmd ), str (e )))
194266 return [nodes .error (None , nodes .paragraph (text = "kernel-doc missing" ))]
195267
268+ return None
269+
270+ def run_kdoc (self , kfiles ):
271+ """
272+ Execute kernel-doc classes directly instead of running as a separate
273+ command.
274+ """
275+
276+ cmd = self .handle_args ()
277+ env = self .state .document .settings .env
278+
279+ node = nodes .section ()
280+
281+ kfiles .parse (** self .parse_args )
282+ filenames = self .parse_args ["file_list" ]
283+
284+ for filename , out in kfiles .msg (** self .msg_args , filenames = filenames ):
285+ if self .verbose >= 1 :
286+ print (cmd_str (cmd ))
287+
288+ ret = self .parse_msg (filename , node , out , cmd )
289+ if ret :
290+ return ret
291+
292+ return node .children
293+
294+ def run (self ):
295+ global use_kfiles
296+
297+ if use_kfiles :
298+ out_style = RestFormat ()
299+ kfiles = KernelFiles (out_style = out_style , logger = self .logger )
300+ return self .run_kdoc (kfiles )
301+ else :
302+ return self .run_cmd ()
303+
196304 def do_parse (self , result , node ):
197305 with switch_source_input (self .state , result ):
198306 self .state .nested_parse (result , 0 , node , match_titles = 1 )
199307
308+ def setup_kfiles (app ):
309+ global use_kfiles
310+
311+ kerneldoc_bin = app .env .config .kerneldoc_bin
312+
313+ if kerneldoc_bin and kerneldoc_bin .endswith ("kernel-doc.py" ):
314+ print ("Using Python kernel-doc" )
315+ use_kfiles = True
316+ else :
317+ print (f"Using { kerneldoc_bin } " )
318+
319+
200320def setup (app ):
201321 app .add_config_value ('kerneldoc_bin' , None , 'env' )
202322 app .add_config_value ('kerneldoc_srctree' , None , 'env' )
203323 app .add_config_value ('kerneldoc_verbosity' , 1 , 'env' )
204324
205325 app .add_directive ('kernel-doc' , KernelDocDirective )
206326
327+ app .connect ('builder-inited' , setup_kfiles )
328+
207329 return dict (
208330 version = __version__ ,
209331 parallel_read_safe = True ,
0 commit comments