]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | # SPDX-License-Identifier: BSD-3-Clause |
2 | # Copyright(c) 2010-2015 Intel Corporation | |
7c673cae FG |
3 | |
4 | from __future__ import print_function | |
5 | import subprocess | |
6 | from docutils import nodes | |
7 | from distutils.version import LooseVersion | |
8 | from sphinx import __version__ as sphinx_version | |
9 | from sphinx.highlighting import PygmentsBridge | |
10 | from pygments.formatters.latex import LatexFormatter | |
11 | from os import listdir | |
9f95a23c | 12 | from os import environ |
7c673cae FG |
13 | from os.path import basename |
14 | from os.path import dirname | |
15 | from os.path import join as path_join | |
16 | ||
17 | try: | |
18 | # Python 2. | |
19 | import ConfigParser as configparser | |
20 | except: | |
21 | # Python 3. | |
22 | import configparser | |
23 | ||
11fdf7f2 TL |
24 | try: |
25 | import sphinx_rtd_theme | |
7c673cae | 26 | |
7c673cae | 27 | html_theme = "sphinx_rtd_theme" |
11fdf7f2 TL |
28 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] |
29 | except: | |
30 | print('Install the sphinx ReadTheDocs theme for improved html documentation ' | |
31 | 'layout: pip install sphinx_rtd_theme') | |
32 | pass | |
33 | ||
34 | project = 'Data Plane Development Kit' | |
7c673cae FG |
35 | html_logo = '../logo/DPDK_logo_vertical_rev_small.png' |
36 | latex_logo = '../logo/DPDK_logo_horizontal_tag.png' | |
37 | html_add_permalinks = "" | |
38 | html_show_copyright = False | |
39 | highlight_language = 'none' | |
40 | ||
9f95a23c TL |
41 | # If MAKEFLAGS is exported by the user, garbage text might end up in version |
42 | version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion'], | |
43 | env=dict(environ, MAKEFLAGS="")) | |
11fdf7f2 | 44 | version = version.decode('utf-8').rstrip() |
7c673cae FG |
45 | release = version |
46 | ||
47 | master_doc = 'index' | |
48 | ||
11fdf7f2 TL |
49 | # Maximum feature description string length |
50 | feature_str_len = 25 | |
51 | ||
7c673cae FG |
52 | # Figures, tables and code-blocks automatically numbered if they have caption |
53 | numfig = True | |
54 | ||
55 | latex_documents = [ | |
56 | ('index', | |
57 | 'doc.tex', | |
58 | '', | |
59 | '', | |
60 | 'manual') | |
61 | ] | |
62 | ||
63 | # Latex directives to be included directly in the latex/pdf docs. | |
11fdf7f2 | 64 | custom_latex_preamble = r""" |
7c673cae FG |
65 | \usepackage[utf8]{inputenc} |
66 | \usepackage[T1]{fontenc} | |
67 | \usepackage{helvet} | |
68 | \renewcommand{\familydefault}{\sfdefault} | |
69 | \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm} | |
70 | """ | |
71 | ||
72 | # Configuration for the latex/pdf docs. | |
73 | latex_elements = { | |
74 | 'papersize': 'a4paper', | |
75 | 'pointsize': '11pt', | |
76 | # remove blank pages | |
77 | 'classoptions': ',openany,oneside', | |
78 | 'babel': '\\usepackage[english]{babel}', | |
79 | # customize Latex formatting | |
11fdf7f2 | 80 | 'preamble': custom_latex_preamble |
7c673cae FG |
81 | } |
82 | ||
11fdf7f2 | 83 | |
7c673cae FG |
84 | # Override the default Latex formatter in order to modify the |
85 | # code/verbatim blocks. | |
86 | class CustomLatexFormatter(LatexFormatter): | |
87 | def __init__(self, **options): | |
88 | super(CustomLatexFormatter, self).__init__(**options) | |
89 | # Use the second smallest font size for code/verbatim blocks. | |
90 | self.verboptions = r'formatcom=\footnotesize' | |
91 | ||
92 | # Replace the default latex formatter. | |
93 | PygmentsBridge.latex_formatter = CustomLatexFormatter | |
94 | ||
95 | # Configuration for man pages | |
96 | man_pages = [("testpmd_app_ug/run_app", "testpmd", | |
97 | "tests for dpdk pmds", "", 1), | |
98 | ("tools/pdump", "dpdk-pdump", | |
99 | "enable packet capture on dpdk ports", "", 1), | |
100 | ("tools/proc_info", "dpdk-procinfo", | |
101 | "access dpdk port stats and memory info", "", 1), | |
102 | ("tools/pmdinfo", "dpdk-pmdinfo", | |
103 | "dump a PMDs hardware support info", "", 1), | |
104 | ("tools/devbind", "dpdk-devbind", | |
105 | "check device status and bind/unbind them from drivers", "", 8)] | |
106 | ||
11fdf7f2 TL |
107 | |
108 | # ####### :numref: fallback ######## | |
7c673cae FG |
109 | # The following hook functions add some simple handling for the :numref: |
110 | # directive for Sphinx versions prior to 1.3.1. The functions replace the | |
111 | # :numref: reference with a link to the target (for all Sphinx doc types). | |
112 | # It doesn't try to label figures/tables. | |
7c673cae FG |
113 | def numref_role(reftype, rawtext, text, lineno, inliner): |
114 | """ | |
115 | Add a Sphinx role to handle numref references. Note, we can't convert | |
116 | the link here because the doctree isn't build and the target information | |
117 | isn't available. | |
118 | """ | |
119 | # Add an identifier to distinguish numref from other references. | |
120 | newnode = nodes.reference('', | |
121 | '', | |
122 | refuri='_local_numref_#%s' % text, | |
123 | internal=True) | |
124 | return [newnode], [] | |
125 | ||
11fdf7f2 | 126 | |
7c673cae FG |
127 | def process_numref(app, doctree, from_docname): |
128 | """ | |
129 | Process the numref nodes once the doctree has been built and prior to | |
130 | writing the files. The processing involves replacing the numref with a | |
131 | link plus text to indicate if it is a Figure or Table link. | |
132 | """ | |
133 | ||
134 | # Iterate over the reference nodes in the doctree. | |
135 | for node in doctree.traverse(nodes.reference): | |
136 | target = node.get('refuri', '') | |
137 | ||
138 | # Look for numref nodes. | |
139 | if target.startswith('_local_numref_#'): | |
140 | target = target.replace('_local_numref_#', '') | |
141 | ||
142 | # Get the target label and link information from the Sphinx env. | |
143 | data = app.builder.env.domains['std'].data | |
144 | docname, label, _ = data['labels'].get(target, ('', '', '')) | |
145 | relative_url = app.builder.get_relative_uri(from_docname, docname) | |
146 | ||
147 | # Add a text label to the link. | |
148 | if target.startswith('figure'): | |
149 | caption = 'Figure' | |
150 | elif target.startswith('table'): | |
151 | caption = 'Table' | |
152 | else: | |
153 | caption = 'Link' | |
154 | ||
155 | # New reference node with the updated link information. | |
156 | newnode = nodes.reference('', | |
157 | caption, | |
158 | refuri='%s#%s' % (relative_url, label), | |
159 | internal=True) | |
160 | node.replace_self(newnode) | |
161 | ||
162 | ||
11fdf7f2 | 163 | def generate_overview_table(output_filename, table_id, section, table_name, title): |
7c673cae | 164 | """ |
11fdf7f2 TL |
165 | Function to generate the Overview Table from the ini files that define |
166 | the features for each driver. | |
7c673cae FG |
167 | |
168 | The default features for the table and their order is defined by the | |
169 | 'default.ini' file. | |
170 | ||
171 | """ | |
11fdf7f2 TL |
172 | # Default warning string. |
173 | warning = 'Warning generate_overview_table()' | |
7c673cae FG |
174 | |
175 | # Get the default features and order from the 'default.ini' file. | |
176 | ini_path = path_join(dirname(output_filename), 'features') | |
177 | config = configparser.ConfigParser() | |
178 | config.optionxform = str | |
179 | config.read(path_join(ini_path, 'default.ini')) | |
11fdf7f2 | 180 | default_features = config.items(section) |
7c673cae FG |
181 | |
182 | # Create a dict of the valid features to validate the other ini files. | |
183 | valid_features = {} | |
184 | max_feature_length = 0 | |
185 | for feature in default_features: | |
186 | key = feature[0] | |
187 | valid_features[key] = ' ' | |
188 | max_feature_length = max(max_feature_length, len(key)) | |
189 | ||
11fdf7f2 | 190 | # Get a list of driver ini files, excluding 'default.ini'. |
7c673cae FG |
191 | ini_files = [basename(file) for file in listdir(ini_path) |
192 | if file.endswith('.ini') and file != 'default.ini'] | |
193 | ini_files.sort() | |
194 | ||
195 | # Build up a list of the table header names from the ini filenames. | |
11fdf7f2 | 196 | pmd_names = [] |
7c673cae FG |
197 | for ini_filename in ini_files: |
198 | name = ini_filename[:-4] | |
199 | name = name.replace('_vf', 'vf') | |
11fdf7f2 | 200 | pmd_names.append(name) |
7c673cae | 201 | |
11fdf7f2 TL |
202 | # Pad the table header names. |
203 | max_header_len = len(max(pmd_names, key=len)) | |
204 | header_names = [] | |
205 | for name in pmd_names: | |
7c673cae FG |
206 | if '_vec' in name: |
207 | pmd, vec = name.split('_') | |
11fdf7f2 TL |
208 | name = '{0:{fill}{align}{width}}vec'.format(pmd, |
209 | fill='.', align='<', width=max_header_len-3) | |
7c673cae | 210 | else: |
11fdf7f2 TL |
211 | name = '{0:{fill}{align}{width}}'.format(name, |
212 | fill=' ', align='<', width=max_header_len) | |
7c673cae FG |
213 | header_names.append(name) |
214 | ||
11fdf7f2 | 215 | # Create a dict of the defined features for each driver from the ini files. |
7c673cae FG |
216 | ini_data = {} |
217 | for ini_filename in ini_files: | |
218 | config = configparser.ConfigParser() | |
219 | config.optionxform = str | |
220 | config.read(path_join(ini_path, ini_filename)) | |
221 | ||
222 | # Initialize the dict with the default.ini value. | |
223 | ini_data[ini_filename] = valid_features.copy() | |
224 | ||
225 | # Check for a valid ini section. | |
11fdf7f2 | 226 | if not config.has_section(section): |
7c673cae FG |
227 | print("{}: File '{}' has no [{}] secton".format(warning, |
228 | ini_filename, | |
11fdf7f2 | 229 | section)) |
7c673cae FG |
230 | continue |
231 | ||
232 | # Check for valid features names. | |
11fdf7f2 | 233 | for name, value in config.items(section): |
7c673cae FG |
234 | if name not in valid_features: |
235 | print("{}: Unknown feature '{}' in '{}'".format(warning, | |
236 | name, | |
237 | ini_filename)) | |
238 | continue | |
239 | ||
240 | if value is not '': | |
241 | # Get the first letter only. | |
242 | ini_data[ini_filename][name] = value[0] | |
243 | ||
11fdf7f2 | 244 | # Print out the RST Driver Overview table from the ini file data. |
7c673cae FG |
245 | outfile = open(output_filename, 'w') |
246 | num_cols = len(header_names) | |
247 | ||
11fdf7f2 TL |
248 | print_table_css(outfile, table_id) |
249 | print('.. table:: ' + table_name + '\n', file=outfile) | |
250 | print_table_header(outfile, num_cols, header_names, title) | |
7c673cae FG |
251 | print_table_body(outfile, num_cols, ini_files, ini_data, default_features) |
252 | ||
253 | ||
11fdf7f2 | 254 | def print_table_header(outfile, num_cols, header_names, title): |
7c673cae FG |
255 | """ Print the RST table header. The header names are vertical. """ |
256 | print_table_divider(outfile, num_cols) | |
257 | ||
258 | line = '' | |
259 | for name in header_names: | |
260 | line += ' ' + name[0] | |
261 | ||
11fdf7f2 | 262 | print_table_row(outfile, title, line) |
7c673cae | 263 | |
11fdf7f2 | 264 | for i in range(1, len(header_names[0])): |
7c673cae FG |
265 | line = '' |
266 | for name in header_names: | |
267 | line += ' ' + name[i] | |
268 | ||
269 | print_table_row(outfile, '', line) | |
270 | ||
271 | print_table_divider(outfile, num_cols) | |
272 | ||
273 | ||
274 | def print_table_body(outfile, num_cols, ini_files, ini_data, default_features): | |
275 | """ Print out the body of the table. Each row is a NIC feature. """ | |
276 | ||
277 | for feature, _ in default_features: | |
278 | line = '' | |
279 | ||
280 | for ini_filename in ini_files: | |
281 | line += ' ' + ini_data[ini_filename][feature] | |
282 | ||
283 | print_table_row(outfile, feature, line) | |
284 | ||
285 | print_table_divider(outfile, num_cols) | |
286 | ||
287 | ||
288 | def print_table_row(outfile, feature, line): | |
289 | """ Print a single row of the table with fixed formatting. """ | |
290 | line = line.rstrip() | |
11fdf7f2 | 291 | print(' {:<{}}{}'.format(feature, feature_str_len, line), file=outfile) |
7c673cae FG |
292 | |
293 | ||
294 | def print_table_divider(outfile, num_cols): | |
295 | """ Print the table divider line. """ | |
296 | line = ' ' | |
297 | column_dividers = ['='] * num_cols | |
298 | line += ' '.join(column_dividers) | |
299 | ||
11fdf7f2 | 300 | feature = '=' * feature_str_len |
7c673cae FG |
301 | |
302 | print_table_row(outfile, feature, line) | |
303 | ||
304 | ||
11fdf7f2 TL |
305 | def print_table_css(outfile, table_id): |
306 | template = """ | |
307 | .. raw:: html | |
308 | ||
309 | <style> | |
310 | .wy-nav-content { | |
311 | opacity: .99; | |
312 | } | |
313 | table#idx { | |
314 | cursor: default; | |
315 | overflow: hidden; | |
316 | } | |
317 | table#idx th, table#idx td { | |
318 | text-align: center; | |
319 | } | |
320 | table#idx th { | |
321 | font-size: 72%; | |
322 | white-space: pre-wrap; | |
323 | vertical-align: top; | |
324 | padding: 0.5em 0; | |
325 | min-width: 0.9em; | |
326 | width: 2em; | |
327 | } | |
328 | table#idx col:first-child { | |
329 | width: 0; | |
330 | } | |
331 | table#idx th:first-child { | |
332 | vertical-align: bottom; | |
333 | } | |
334 | table#idx td { | |
335 | font-size: 70%; | |
336 | padding: 1px; | |
337 | } | |
338 | table#idx td:first-child { | |
339 | padding-left: 1em; | |
340 | text-align: left; | |
341 | } | |
342 | table#idx tr:nth-child(2n-1) td { | |
343 | background-color: rgba(210, 210, 210, 0.2); | |
344 | } | |
345 | table#idx th:not(:first-child):hover, | |
346 | table#idx td:not(:first-child):hover { | |
347 | position: relative; | |
348 | } | |
349 | table#idx th:not(:first-child):hover::after, | |
350 | table#idx td:not(:first-child):hover::after { | |
351 | content: ''; | |
352 | height: 6000px; | |
353 | top: -3000px; | |
354 | width: 100%; | |
355 | left: 0; | |
356 | position: absolute; | |
357 | z-index: -1; | |
358 | background-color: #ffb; | |
359 | } | |
360 | table#idx tr:hover td { | |
361 | background-color: #ffb; | |
362 | } | |
363 | </style> | |
364 | """ | |
365 | print(template.replace("idx", "id%d" % (table_id)), file=outfile) | |
366 | ||
367 | ||
7c673cae | 368 | def setup(app): |
11fdf7f2 TL |
369 | table_file = dirname(__file__) + '/nics/overview_table.txt' |
370 | generate_overview_table(table_file, 1, | |
371 | 'Features', | |
372 | 'Features availability in networking drivers', | |
373 | 'Feature') | |
374 | table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt' | |
375 | generate_overview_table(table_file, 1, | |
376 | 'Features', | |
377 | 'Features availability in crypto drivers', | |
378 | 'Feature') | |
379 | table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt' | |
380 | generate_overview_table(table_file, 2, | |
381 | 'Cipher', | |
382 | 'Cipher algorithms in crypto drivers', | |
383 | 'Cipher algorithm') | |
384 | table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt' | |
385 | generate_overview_table(table_file, 3, | |
386 | 'Auth', | |
387 | 'Authentication algorithms in crypto drivers', | |
388 | 'Authentication algorithm') | |
389 | table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt' | |
390 | generate_overview_table(table_file, 4, | |
391 | 'AEAD', | |
392 | 'AEAD algorithms in crypto drivers', | |
393 | 'AEAD algorithm') | |
9f95a23c TL |
394 | table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt' |
395 | generate_overview_table(table_file, 5, | |
396 | 'Asymmetric', | |
397 | 'Asymmetric algorithms in crypto drivers', | |
398 | 'Asymmetric algorithm') | |
11fdf7f2 TL |
399 | table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt' |
400 | generate_overview_table(table_file, 1, | |
401 | 'Features', | |
402 | 'Features availability in compression drivers', | |
403 | 'Feature') | |
7c673cae FG |
404 | |
405 | if LooseVersion(sphinx_version) < LooseVersion('1.3.1'): | |
406 | print('Upgrade sphinx to version >= 1.3.1 for ' | |
407 | 'improved Figure/Table number handling.') | |
408 | # Add a role to handle :numref: references. | |
409 | app.add_role('numref', numref_role) | |
410 | # Process the numref references once the doctree has been created. | |
411 | app.connect('doctree-resolved', process_numref) | |
11fdf7f2 TL |
412 | |
413 | app.add_stylesheet('css/custom.css') |