doc: render and install man pages
[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
51 project = 'Data Plane Development Kit'
52
53 if LooseVersion(sphinx_version) >= LooseVersion('1.3.1'):
54     html_theme = "sphinx_rtd_theme"
55 html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
56 latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
57 html_add_permalinks = ""
58 html_show_copyright = False
59 highlight_language = 'none'
60
61 version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion']).decode('utf-8').rstrip()
62 release = version
63
64 master_doc = 'index'
65
66 # Figures, tables and code-blocks automatically numbered if they have caption
67 numfig = True
68
69 latex_documents = [
70     ('index',
71      'doc.tex',
72      '',
73      '',
74      'manual')
75 ]
76
77 # Latex directives to be included directly in the latex/pdf docs.
78 latex_preamble = r"""
79 \usepackage[utf8]{inputenc}
80 \usepackage[T1]{fontenc}
81 \usepackage{helvet}
82 \renewcommand{\familydefault}{\sfdefault}
83 \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
84 """
85
86 # Configuration for the latex/pdf docs.
87 latex_elements = {
88     'papersize': 'a4paper',
89     'pointsize': '11pt',
90     # remove blank pages
91     'classoptions': ',openany,oneside',
92     'babel': '\\usepackage[english]{babel}',
93     # customize Latex formatting
94     'preamble': latex_preamble
95 }
96
97 # Override the default Latex formatter in order to modify the
98 # code/verbatim blocks.
99 class CustomLatexFormatter(LatexFormatter):
100     def __init__(self, **options):
101         super(CustomLatexFormatter, self).__init__(**options)
102         # Use the second smallest font size for code/verbatim blocks.
103         self.verboptions = r'formatcom=\footnotesize'
104
105 # Replace the default latex formatter.
106 PygmentsBridge.latex_formatter = CustomLatexFormatter
107
108 # Configuration for man pages
109 man_pages = [("testpmd_app_ug/run_app", "testpmd",
110               "tests for dpdk pmds", "", 1),
111              ("tools/pdump", "dpdk-pdump",
112               "enable packet capture on dpdk ports", "", 1),
113              ("tools/proc_info", "dpdk-procinfo",
114               "access dpdk port stats and memory info", "", 1)]
115
116 ######## :numref: fallback ########
117 # The following hook functions add some simple handling for the :numref:
118 # directive for Sphinx versions prior to 1.3.1. The functions replace the
119 # :numref: reference with a link to the target (for all Sphinx doc types).
120 # It doesn't try to label figures/tables.
121
122 def numref_role(reftype, rawtext, text, lineno, inliner):
123     """
124     Add a Sphinx role to handle numref references. Note, we can't convert
125     the link here because the doctree isn't build and the target information
126     isn't available.
127     """
128     # Add an identifier to distinguish numref from other references.
129     newnode = nodes.reference('',
130                               '',
131                               refuri='_local_numref_#%s' % text,
132                               internal=True)
133     return [newnode], []
134
135 def process_numref(app, doctree, from_docname):
136     """
137     Process the numref nodes once the doctree has been built and prior to
138     writing the files. The processing involves replacing the numref with a
139     link plus text to indicate if it is a Figure or Table link.
140     """
141
142     # Iterate over the reference nodes in the doctree.
143     for node in doctree.traverse(nodes.reference):
144         target = node.get('refuri', '')
145
146         # Look for numref nodes.
147         if target.startswith('_local_numref_#'):
148             target = target.replace('_local_numref_#', '')
149
150             # Get the target label and link information from the Sphinx env.
151             data = app.builder.env.domains['std'].data
152             docname, label, _ = data['labels'].get(target, ('', '', ''))
153             relative_url = app.builder.get_relative_uri(from_docname, docname)
154
155             # Add a text label to the link.
156             if target.startswith('figure'):
157                 caption = 'Figure'
158             elif target.startswith('table'):
159                 caption = 'Table'
160             else:
161                 caption = 'Link'
162
163             # New reference node with the updated link information.
164             newnode = nodes.reference('',
165                                       caption,
166                                       refuri='%s#%s' % (relative_url, label),
167                                       internal=True)
168             node.replace_self(newnode)
169
170
171 def generate_nic_overview_table(output_filename):
172     """
173     Function to generate the NIC Overview Table from the ini files that define
174     the features for each NIC.
175
176     The default features for the table and their order is defined by the
177     'default.ini' file.
178
179     """
180     # Default worning string.
181     warning = 'Warning generate_nic_overview_table()'
182
183     # Get the default features and order from the 'default.ini' file.
184     ini_path = path_join(dirname(output_filename), 'features')
185     config = configparser.ConfigParser()
186     config.optionxform = str
187     config.read(path_join(ini_path, 'default.ini'))
188     default_section = 'Features'
189     default_features = config.items(default_section)
190
191     # Create a dict of the valid features to validate the other ini files.
192     valid_features = {}
193     max_feature_length = 0
194     for feature in default_features:
195         key = feature[0]
196         valid_features[key] = ' '
197         max_feature_length = max(max_feature_length, len(key))
198
199     # Get a list of NIC ini files, excluding 'default.ini'.
200     ini_files = [basename(file) for file in listdir(ini_path)
201                  if file.endswith('.ini') and file != 'default.ini']
202     ini_files.sort()
203
204     # Build up a list of the table header names from the ini filenames.
205     header_names = []
206     for ini_filename in ini_files:
207         name = ini_filename[:-4]
208         name = name.replace('_vf', 'vf')
209
210         # Pad the table header names to match the existing format.
211         if '_vec' in name:
212             pmd, vec = name.split('_')
213             name = '{0:{fill}{align}7}vec'.format(pmd, fill='.', align='<')
214         else:
215             name = '{0:{fill}{align}10}'.format(name, fill=' ', align='<')
216
217         header_names.append(name)
218
219     # Create a dict of the defined features for each NIC from the ini files.
220     ini_data = {}
221     for ini_filename in ini_files:
222         config = configparser.ConfigParser()
223         config.optionxform = str
224         config.read(path_join(ini_path, ini_filename))
225
226         # Initialize the dict with the default.ini value.
227         ini_data[ini_filename] = valid_features.copy()
228
229         # Check for a valid ini section.
230         if not config.has_section(default_section):
231             print("{}: File '{}' has no [{}] secton".format(warning,
232                                                             ini_filename,
233                                                             default_section))
234             continue
235
236         # Check for valid features names.
237         for name, value in config.items(default_section):
238             if name not in valid_features:
239                 print("{}: Unknown feature '{}' in '{}'".format(warning,
240                                                                 name,
241                                                                 ini_filename))
242                 continue
243
244             if value is not '':
245                 # Get the first letter only.
246                 ini_data[ini_filename][name] = value[0]
247
248     # Print out the RST NIC Overview table from the ini file data.
249     outfile = open(output_filename, 'w')
250     num_cols = len(header_names)
251
252     print('.. table:: Features availability in networking drivers\n',
253           file=outfile)
254
255     print_table_header(outfile, num_cols, header_names)
256     print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
257
258
259 def print_table_header(outfile, num_cols, header_names):
260     """ Print the RST table header. The header names are vertical. """
261     print_table_divider(outfile, num_cols)
262
263     line = ''
264     for name in header_names:
265         line += ' ' + name[0]
266
267     print_table_row(outfile, 'Feature', line)
268
269     for i in range(1, 10):
270         line = ''
271         for name in header_names:
272             line += ' ' + name[i]
273
274         print_table_row(outfile, '', line)
275
276     print_table_divider(outfile, num_cols)
277
278
279 def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
280     """ Print out the body of the table. Each row is a NIC feature. """
281
282     for feature, _ in default_features:
283         line = ''
284
285         for ini_filename in ini_files:
286             line += ' ' + ini_data[ini_filename][feature]
287
288         print_table_row(outfile, feature, line)
289
290     print_table_divider(outfile, num_cols)
291
292
293 def print_table_row(outfile, feature, line):
294     """ Print a single row of the table with fixed formatting. """
295     line = line.rstrip()
296     print('   {:<20}{}'.format(feature, line), file=outfile)
297
298
299 def print_table_divider(outfile, num_cols):
300     """ Print the table divider line. """
301     line = ' '
302     column_dividers = ['='] * num_cols
303     line += ' '.join(column_dividers)
304
305     feature = '=' * 20
306
307     print_table_row(outfile, feature, line)
308
309
310 def setup(app):
311     generate_nic_overview_table('doc/guides/nics/overview_table.txt')
312
313     if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
314         print('Upgrade sphinx to version >= 1.3.1 for '
315               'improved Figure/Table number handling.')
316         # Add a role to handle :numref: references.
317         app.add_role('numref', numref_role)
318         # Process the numref references once the doctree has been created.
319         app.connect('doctree-resolved', process_numref)