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