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