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