doc: remove PDF requirements
[dpdk.git] / doc / guides / conf.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2010-2015 Intel Corporation
4
5 from docutils import nodes
6 from distutils.version import LooseVersion
7 from sphinx import __version__ as sphinx_version
8 from os import listdir
9 from os import environ
10 from os.path import basename
11 from os.path import dirname
12 from os.path import join as path_join
13 from sys import argv, stderr
14
15 import configparser
16
17 try:
18     import sphinx_rtd_theme
19
20     html_theme = "sphinx_rtd_theme"
21 except:
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
27 stop_on_error = ('-W' in argv)
28
29 project = 'Data Plane Development Kit'
30 html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
31 if LooseVersion(sphinx_version) >= LooseVersion('3.5'):
32     html_permalinks = False
33 else:
34     html_add_permalinks = ""
35 html_show_copyright = False
36 highlight_language = 'none'
37
38 release = environ.setdefault('DPDK_VERSION', "None")
39 version = release
40
41 master_doc = 'index'
42
43 # Maximum feature description string length
44 feature_str_len = 30
45
46 # Figures, tables and code-blocks automatically numbered if they have caption
47 numfig = True
48
49 # Configuration for man pages
50 man_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.
67 def 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
81 def 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
117 def 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
214 def 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
234 def 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
248 def 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
254 def 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
265 def 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
336 def 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')