doc: fix build with python 3.8
[dpdk.git] / doc / guides / conf.py
1 # SPDX-License-Identifier: BSD-3-Clause
2 # Copyright(c) 2010-2015 Intel Corporation
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
12 from os import environ
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
24 try:
25     import sphinx_rtd_theme
26
27     html_theme = "sphinx_rtd_theme"
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'
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
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=""))
44 version = version.decode('utf-8').rstrip()
45 release = version
46
47 master_doc = 'index'
48
49 # Maximum feature description string length
50 feature_str_len = 25
51
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.
64 custom_latex_preamble = r"""
65 \usepackage{textalpha}
66 \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
67 \usepackage{etoolbox}
68 \robustify\(
69 \robustify\)
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
80     'preamble': custom_latex_preamble
81 }
82
83
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
107
108 # ####### :numref: fallback ########
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.
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
126
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
163 def generate_overview_table(output_filename, table_id, section, table_name, title):
164     """
165     Function to generate the Overview Table from the ini files that define
166     the features for each driver.
167
168     The default features for the table and their order is defined by the
169     'default.ini' file.
170
171     """
172     # Default warning string.
173     warning = 'Warning generate_overview_table()'
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'))
180     default_features = config.items(section)
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
190     # Get a list of driver ini files, excluding 'default.ini'.
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.
196     pmd_names = []
197     for ini_filename in ini_files:
198         name = ini_filename[:-4]
199         name = name.replace('_vf', 'vf')
200         pmd_names.append(name)
201
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:
206         if '_vec' in name:
207             pmd, vec = name.split('_')
208             name = '{0:{fill}{align}{width}}vec'.format(pmd,
209                     fill='.', align='<', width=max_header_len-3)
210         else:
211             name = '{0:{fill}{align}{width}}'.format(name,
212                     fill=' ', align='<', width=max_header_len)
213         header_names.append(name)
214
215     # Create a dict of the defined features for each driver from the ini files.
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.
226         if not config.has_section(section):
227             print("{}: File '{}' has no [{}] secton".format(warning,
228                                                             ini_filename,
229                                                             section))
230             continue
231
232         # Check for valid features names.
233         for name, value in config.items(section):
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:
241                 # Get the first letter only.
242                 ini_data[ini_filename][name] = value[0]
243
244     # Print out the RST Driver Overview table from the ini file data.
245     outfile = open(output_filename, 'w')
246     num_cols = len(header_names)
247
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)
251     print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
252
253
254 def print_table_header(outfile, num_cols, header_names, title):
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
262     print_table_row(outfile, title, line)
263
264     for i in range(1, len(header_names[0])):
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()
291     print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
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
300     feature = '=' * feature_str_len
301
302     print_table_row(outfile, feature, line)
303
304
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
368 def setup(app):
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')
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')
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')
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)
412
413     app.add_stylesheet('css/custom.css')