~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/net/ynl/ynl-gen-rst.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/net/ynl/ynl-gen-rst.py (Architecture ppc) and /tools/net/ynl/ynl-gen-rst.py (Architecture alpha)


  1 #!/usr/bin/env python3                              1 #!/usr/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0                  2 # SPDX-License-Identifier: GPL-2.0
  3 # -*- coding: utf-8; mode: python -*-               3 # -*- coding: utf-8; mode: python -*-
  4                                                     4 
  5 """                                                 5 """
  6     Script to auto generate the documentation       6     Script to auto generate the documentation for Netlink specifications.
  7                                                     7 
  8     :copyright:  Copyright (C) 2023  Breno Lei<      8     :copyright:  Copyright (C) 2023  Breno Leitao <leitao@debian.org>
  9     :license:    GPL Version 2, June 1991 see       9     :license:    GPL Version 2, June 1991 see linux/COPYING for details.
 10                                                    10 
 11     This script performs extensive parsing to      11     This script performs extensive parsing to the Linux kernel's netlink YAML
 12     spec files, in an effort to avoid needing      12     spec files, in an effort to avoid needing to heavily mark up the original
 13     YAML file.                                     13     YAML file.
 14                                                    14 
 15     This code is split in three big parts:         15     This code is split in three big parts:
 16         1) RST formatters: Use to convert a st     16         1) RST formatters: Use to convert a string to a RST output
 17         2) Parser helpers: Functions to parse      17         2) Parser helpers: Functions to parse the YAML data structure
 18         3) Main function and small helpers         18         3) Main function and small helpers
 19 """                                                19 """
 20                                                    20 
 21 from typing import Any, Dict, List                 21 from typing import Any, Dict, List
 22 import os.path                                     22 import os.path
 23 import sys                                         23 import sys
 24 import argparse                                    24 import argparse
 25 import logging                                     25 import logging
 26 import yaml                                        26 import yaml
 27                                                    27 
 28                                                    28 
 29 SPACE_PER_LEVEL = 4                                29 SPACE_PER_LEVEL = 4
 30                                                    30 
 31                                                    31 
 32 # RST Formatters                                   32 # RST Formatters
 33 # ==============                                   33 # ==============
 34 def headroom(level: int) -> str:                   34 def headroom(level: int) -> str:
 35     """Return space to format"""                   35     """Return space to format"""
 36     return " " * (level * SPACE_PER_LEVEL)         36     return " " * (level * SPACE_PER_LEVEL)
 37                                                    37 
 38                                                    38 
 39 def bold(text: str) -> str:                        39 def bold(text: str) -> str:
 40     """Format bold text"""                         40     """Format bold text"""
 41     return f"**{text}**"                           41     return f"**{text}**"
 42                                                    42 
 43                                                    43 
 44 def inline(text: str) -> str:                      44 def inline(text: str) -> str:
 45     """Format inline text"""                       45     """Format inline text"""
 46     return f"``{text}``"                           46     return f"``{text}``"
 47                                                    47 
 48                                                    48 
 49 def sanitize(text: str) -> str:                    49 def sanitize(text: str) -> str:
 50     """Remove newlines and multiple spaces"""      50     """Remove newlines and multiple spaces"""
 51     # This is useful for some fields that are      51     # This is useful for some fields that are spread across multiple lines
 52     return str(text).replace("\n", " ").strip(     52     return str(text).replace("\n", " ").strip()
 53                                                    53 
 54                                                    54 
 55 def rst_fields(key: str, value: str, level: in     55 def rst_fields(key: str, value: str, level: int = 0) -> str:
 56     """Return a RST formatted field"""             56     """Return a RST formatted field"""
 57     return headroom(level) + f":{key}: {value}     57     return headroom(level) + f":{key}: {value}"
 58                                                    58 
 59                                                    59 
 60 def rst_definition(key: str, value: Any, level     60 def rst_definition(key: str, value: Any, level: int = 0) -> str:
 61     """Format a single rst definition"""           61     """Format a single rst definition"""
 62     return headroom(level) + key + "\n" + head     62     return headroom(level) + key + "\n" + headroom(level + 1) + str(value)
 63                                                    63 
 64                                                    64 
 65 def rst_paragraph(paragraph: str, level: int =     65 def rst_paragraph(paragraph: str, level: int = 0) -> str:
 66     """Return a formatted paragraph"""             66     """Return a formatted paragraph"""
 67     return headroom(level) + paragraph             67     return headroom(level) + paragraph
 68                                                    68 
 69                                                    69 
 70 def rst_bullet(item: str, level: int = 0) -> s     70 def rst_bullet(item: str, level: int = 0) -> str:
 71     """Return a formatted a bullet"""              71     """Return a formatted a bullet"""
 72     return headroom(level) + f"- {item}"           72     return headroom(level) + f"- {item}"
 73                                                    73 
 74                                                    74 
 75 def rst_subsection(title: str) -> str:             75 def rst_subsection(title: str) -> str:
 76     """Add a sub-section to the document"""        76     """Add a sub-section to the document"""
 77     return f"{title}\n" + "-" * len(title)         77     return f"{title}\n" + "-" * len(title)
 78                                                    78 
 79                                                    79 
 80 def rst_subsubsection(title: str) -> str:          80 def rst_subsubsection(title: str) -> str:
 81     """Add a sub-sub-section to the document""     81     """Add a sub-sub-section to the document"""
 82     return f"{title}\n" + "~" * len(title)         82     return f"{title}\n" + "~" * len(title)
 83                                                    83 
 84                                                    84 
 85 def rst_section(namespace: str, prefix: str, t     85 def rst_section(namespace: str, prefix: str, title: str) -> str:
 86     """Add a section to the document"""            86     """Add a section to the document"""
 87     return f".. _{namespace}-{prefix}-{title}:     87     return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=" * len(title)
 88                                                    88 
 89                                                    89 
 90 def rst_subtitle(title: str) -> str:               90 def rst_subtitle(title: str) -> str:
 91     """Add a subtitle to the document"""           91     """Add a subtitle to the document"""
 92     return "\n" + "-" * len(title) + f"\n{titl     92     return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n"
 93                                                    93 
 94                                                    94 
 95 def rst_title(title: str) -> str:                  95 def rst_title(title: str) -> str:
 96     """Add a title to the document"""              96     """Add a title to the document"""
 97     return "=" * len(title) + f"\n{title}\n" +     97     return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n"
 98                                                    98 
 99                                                    99 
100 def rst_list_inline(list_: List[str], level: i    100 def rst_list_inline(list_: List[str], level: int = 0) -> str:
101     """Format a list using inlines"""             101     """Format a list using inlines"""
102     return headroom(level) + "[" + ", ".join(i    102     return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "]"
103                                                   103 
104                                                   104 
105 def rst_ref(namespace: str, prefix: str, name:    105 def rst_ref(namespace: str, prefix: str, name: str) -> str:
106     """Add a hyperlink to the document"""         106     """Add a hyperlink to the document"""
107     mappings = {'enum': 'definition',             107     mappings = {'enum': 'definition',
108                 'fixed-header': 'definition',     108                 'fixed-header': 'definition',
109                 'nested-attributes': 'attribut    109                 'nested-attributes': 'attribute-set',
110                 'struct': 'definition'}           110                 'struct': 'definition'}
111     if prefix in mappings:                        111     if prefix in mappings:
112         prefix = mappings[prefix]                 112         prefix = mappings[prefix]
113     return f":ref:`{namespace}-{prefix}-{name}    113     return f":ref:`{namespace}-{prefix}-{name}`"
114                                                   114 
115                                                   115 
116 def rst_header() -> str:                          116 def rst_header() -> str:
117     """The headers for all the auto generated     117     """The headers for all the auto generated RST files"""
118     lines = []                                    118     lines = []
119                                                   119 
120     lines.append(rst_paragraph(".. SPDX-Licens    120     lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0"))
121     lines.append(rst_paragraph(".. NOTE: This     121     lines.append(rst_paragraph(".. NOTE: This document was auto-generated.\n\n"))
122                                                   122 
123     return "\n".join(lines)                       123     return "\n".join(lines)
124                                                   124 
125                                                   125 
126 def rst_toctree(maxdepth: int = 2) -> str:        126 def rst_toctree(maxdepth: int = 2) -> str:
127     """Generate a toctree RST primitive"""        127     """Generate a toctree RST primitive"""
128     lines = []                                    128     lines = []
129                                                   129 
130     lines.append(".. toctree::")                  130     lines.append(".. toctree::")
131     lines.append(f"   :maxdepth: {maxdepth}\n\    131     lines.append(f"   :maxdepth: {maxdepth}\n\n")
132                                                   132 
133     return "\n".join(lines)                       133     return "\n".join(lines)
134                                                   134 
135                                                   135 
136 def rst_label(title: str) -> str:                 136 def rst_label(title: str) -> str:
137     """Return a formatted label"""                137     """Return a formatted label"""
138     return f".. _{title}:\n\n"                    138     return f".. _{title}:\n\n"
139                                                   139 
140                                                   140 
141 # Parsers                                         141 # Parsers
142 # =======                                         142 # =======
143                                                   143 
144                                                   144 
145 def parse_mcast_group(mcast_group: List[Dict[s    145 def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str:
146     """Parse 'multicast' group list and return    146     """Parse 'multicast' group list and return a formatted string"""
147     lines = []                                    147     lines = []
148     for group in mcast_group:                     148     for group in mcast_group:
149         lines.append(rst_bullet(group["name"])    149         lines.append(rst_bullet(group["name"]))
150                                                   150 
151     return "\n".join(lines)                       151     return "\n".join(lines)
152                                                   152 
153                                                   153 
154 def parse_do(do_dict: Dict[str, Any], level: i    154 def parse_do(do_dict: Dict[str, Any], level: int = 0) -> str:
155     """Parse 'do' section and return a formatt    155     """Parse 'do' section and return a formatted string"""
156     lines = []                                    156     lines = []
157     for key in do_dict.keys():                    157     for key in do_dict.keys():
158         lines.append(rst_paragraph(bold(key),     158         lines.append(rst_paragraph(bold(key), level + 1))
159         if key in ['request', 'reply']:           159         if key in ['request', 'reply']:
160             lines.append(parse_do_attributes(d    160             lines.append(parse_do_attributes(do_dict[key], level + 1) + "\n")
161         else:                                     161         else:
162             lines.append(headroom(level + 2) +    162             lines.append(headroom(level + 2) + do_dict[key] + "\n")
163                                                   163 
164     return "\n".join(lines)                       164     return "\n".join(lines)
165                                                   165 
166                                                   166 
167 def parse_do_attributes(attrs: Dict[str, Any],    167 def parse_do_attributes(attrs: Dict[str, Any], level: int = 0) -> str:
168     """Parse 'attributes' section"""              168     """Parse 'attributes' section"""
169     if "attributes" not in attrs:                 169     if "attributes" not in attrs:
170         return ""                                 170         return ""
171     lines = [rst_fields("attributes", rst_list    171     lines = [rst_fields("attributes", rst_list_inline(attrs["attributes"]), level + 1)]
172                                                   172 
173     return "\n".join(lines)                       173     return "\n".join(lines)
174                                                   174 
175                                                   175 
176 def parse_operations(operations: List[Dict[str    176 def parse_operations(operations: List[Dict[str, Any]], namespace: str) -> str:
177     """Parse operations block"""                  177     """Parse operations block"""
178     preprocessed = ["name", "doc", "title", "d    178     preprocessed = ["name", "doc", "title", "do", "dump", "flags"]
179     linkable = ["fixed-header", "attribute-set    179     linkable = ["fixed-header", "attribute-set"]
180     lines = []                                    180     lines = []
181                                                   181 
182     for operation in operations:                  182     for operation in operations:
183         lines.append(rst_section(namespace, 'o    183         lines.append(rst_section(namespace, 'operation', operation["name"]))
184         lines.append(rst_paragraph(operation["    184         lines.append(rst_paragraph(operation["doc"]) + "\n")
185                                                   185 
186         for key in operation.keys():              186         for key in operation.keys():
187             if key in preprocessed:               187             if key in preprocessed:
188                 # Skip the special fields         188                 # Skip the special fields
189                 continue                          189                 continue
190             value = operation[key]                190             value = operation[key]
191             if key in linkable:                   191             if key in linkable:
192                 value = rst_ref(namespace, key    192                 value = rst_ref(namespace, key, value)
193             lines.append(rst_fields(key, value    193             lines.append(rst_fields(key, value, 0))
194         if 'flags' in operation:                  194         if 'flags' in operation:
195             lines.append(rst_fields('flags', r    195             lines.append(rst_fields('flags', rst_list_inline(operation['flags'])))
196                                                   196 
197         if "do" in operation:                     197         if "do" in operation:
198             lines.append(rst_paragraph(":do:",    198             lines.append(rst_paragraph(":do:", 0))
199             lines.append(parse_do(operation["d    199             lines.append(parse_do(operation["do"], 0))
200         if "dump" in operation:                   200         if "dump" in operation:
201             lines.append(rst_paragraph(":dump:    201             lines.append(rst_paragraph(":dump:", 0))
202             lines.append(parse_do(operation["d    202             lines.append(parse_do(operation["dump"], 0))
203                                                   203 
204         # New line after fields                   204         # New line after fields
205         lines.append("\n")                        205         lines.append("\n")
206                                                   206 
207     return "\n".join(lines)                       207     return "\n".join(lines)
208                                                   208 
209                                                   209 
210 def parse_entries(entries: List[Dict[str, Any]    210 def parse_entries(entries: List[Dict[str, Any]], level: int) -> str:
211     """Parse a list of entries"""                 211     """Parse a list of entries"""
212     ignored = ["pad"]                             212     ignored = ["pad"]
213     lines = []                                    213     lines = []
214     for entry in entries:                         214     for entry in entries:
215         if isinstance(entry, dict):               215         if isinstance(entry, dict):
216             # entries could be a list or a dic    216             # entries could be a list or a dictionary
217             field_name = entry.get("name", "")    217             field_name = entry.get("name", "")
218             if field_name in ignored:             218             if field_name in ignored:
219                 continue                          219                 continue
220             type_ = entry.get("type")             220             type_ = entry.get("type")
221             if type_:                             221             if type_:
222                 field_name += f" ({inline(type    222                 field_name += f" ({inline(type_)})"
223             lines.append(                         223             lines.append(
224                 rst_fields(field_name, sanitiz    224                 rst_fields(field_name, sanitize(entry.get("doc", "")), level)
225             )                                     225             )
226         elif isinstance(entry, list):             226         elif isinstance(entry, list):
227             lines.append(rst_list_inline(entry    227             lines.append(rst_list_inline(entry, level))
228         else:                                     228         else:
229             lines.append(rst_bullet(inline(san    229             lines.append(rst_bullet(inline(sanitize(entry)), level))
230                                                   230 
231     lines.append("\n")                            231     lines.append("\n")
232     return "\n".join(lines)                       232     return "\n".join(lines)
233                                                   233 
234                                                   234 
235 def parse_definitions(defs: Dict[str, Any], na    235 def parse_definitions(defs: Dict[str, Any], namespace: str) -> str:
236     """Parse definitions section"""               236     """Parse definitions section"""
237     preprocessed = ["name", "entries", "member    237     preprocessed = ["name", "entries", "members"]
238     ignored = ["render-max"]  # This is not pr    238     ignored = ["render-max"]  # This is not printed
239     lines = []                                    239     lines = []
240                                                   240 
241     for definition in defs:                       241     for definition in defs:
242         lines.append(rst_section(namespace, 'd    242         lines.append(rst_section(namespace, 'definition', definition["name"]))
243         for k in definition.keys():               243         for k in definition.keys():
244             if k in preprocessed + ignored:       244             if k in preprocessed + ignored:
245                 continue                          245                 continue
246             lines.append(rst_fields(k, sanitiz    246             lines.append(rst_fields(k, sanitize(definition[k]), 0))
247                                                   247 
248         # Field list needs to finish with a ne    248         # Field list needs to finish with a new line
249         lines.append("\n")                        249         lines.append("\n")
250         if "entries" in definition:               250         if "entries" in definition:
251             lines.append(rst_paragraph(":entri    251             lines.append(rst_paragraph(":entries:", 0))
252             lines.append(parse_entries(definit    252             lines.append(parse_entries(definition["entries"], 1))
253         if "members" in definition:               253         if "members" in definition:
254             lines.append(rst_paragraph(":membe    254             lines.append(rst_paragraph(":members:", 0))
255             lines.append(parse_entries(definit    255             lines.append(parse_entries(definition["members"], 1))
256                                                   256 
257     return "\n".join(lines)                       257     return "\n".join(lines)
258                                                   258 
259                                                   259 
260 def parse_attr_sets(entries: List[Dict[str, An    260 def parse_attr_sets(entries: List[Dict[str, Any]], namespace: str) -> str:
261     """Parse attribute from attribute-set"""      261     """Parse attribute from attribute-set"""
262     preprocessed = ["name", "type"]               262     preprocessed = ["name", "type"]
263     linkable = ["enum", "nested-attributes", "    263     linkable = ["enum", "nested-attributes", "struct", "sub-message"]
264     ignored = ["checks"]                          264     ignored = ["checks"]
265     lines = []                                    265     lines = []
266                                                   266 
267     for entry in entries:                         267     for entry in entries:
268         lines.append(rst_section(namespace, 'a    268         lines.append(rst_section(namespace, 'attribute-set', entry["name"]))
269         for attr in entry["attributes"]:          269         for attr in entry["attributes"]:
270             type_ = attr.get("type")              270             type_ = attr.get("type")
271             attr_line = attr["name"]              271             attr_line = attr["name"]
272             if type_:                             272             if type_:
273                 # Add the attribute type in th    273                 # Add the attribute type in the same line
274                 attr_line += f" ({inline(type_    274                 attr_line += f" ({inline(type_)})"
275                                                   275 
276             lines.append(rst_subsubsection(att    276             lines.append(rst_subsubsection(attr_line))
277                                                   277 
278             for k in attr.keys():                 278             for k in attr.keys():
279                 if k in preprocessed + ignored    279                 if k in preprocessed + ignored:
280                     continue                      280                     continue
281                 if k in linkable:                 281                 if k in linkable:
282                     value = rst_ref(namespace,    282                     value = rst_ref(namespace, k, attr[k])
283                 else:                             283                 else:
284                     value = sanitize(attr[k])     284                     value = sanitize(attr[k])
285                 lines.append(rst_fields(k, val    285                 lines.append(rst_fields(k, value, 0))
286             lines.append("\n")                    286             lines.append("\n")
287                                                   287 
288     return "\n".join(lines)                       288     return "\n".join(lines)
289                                                   289 
290                                                   290 
291 def parse_sub_messages(entries: List[Dict[str,    291 def parse_sub_messages(entries: List[Dict[str, Any]], namespace: str) -> str:
292     """Parse sub-message definitions"""           292     """Parse sub-message definitions"""
293     lines = []                                    293     lines = []
294                                                   294 
295     for entry in entries:                         295     for entry in entries:
296         lines.append(rst_section(namespace, 's    296         lines.append(rst_section(namespace, 'sub-message', entry["name"]))
297         for fmt in entry["formats"]:              297         for fmt in entry["formats"]:
298             value = fmt["value"]                  298             value = fmt["value"]
299                                                   299 
300             lines.append(rst_bullet(bold(value    300             lines.append(rst_bullet(bold(value)))
301             for attr in ['fixed-header', 'attr    301             for attr in ['fixed-header', 'attribute-set']:
302                 if attr in fmt:                   302                 if attr in fmt:
303                     lines.append(rst_fields(at    303                     lines.append(rst_fields(attr,
304                                             rs    304                                             rst_ref(namespace, attr, fmt[attr]),
305                                             1)    305                                             1))
306             lines.append("\n")                    306             lines.append("\n")
307                                                   307 
308     return "\n".join(lines)                       308     return "\n".join(lines)
309                                                   309 
310                                                   310 
311 def parse_yaml(obj: Dict[str, Any]) -> str:       311 def parse_yaml(obj: Dict[str, Any]) -> str:
312     """Format the whole YAML into a RST string    312     """Format the whole YAML into a RST string"""
313     lines = []                                    313     lines = []
314                                                   314 
315     # Main header                                 315     # Main header
316                                                   316 
317     lines.append(rst_header())                    317     lines.append(rst_header())
318                                                   318 
319     family = obj['name']                          319     family = obj['name']
320                                                   320 
321     title = f"Family ``{family}`` netlink spec    321     title = f"Family ``{family}`` netlink specification"
322     lines.append(rst_title(title))                322     lines.append(rst_title(title))
323     lines.append(rst_paragraph(".. contents::     323     lines.append(rst_paragraph(".. contents:: :depth: 3\n"))
324                                                   324 
325     if "doc" in obj:                              325     if "doc" in obj:
326         lines.append(rst_subtitle("Summary"))     326         lines.append(rst_subtitle("Summary"))
327         lines.append(rst_paragraph(obj["doc"],    327         lines.append(rst_paragraph(obj["doc"], 0))
328                                                   328 
329     # Operations                                  329     # Operations
330     if "operations" in obj:                       330     if "operations" in obj:
331         lines.append(rst_subtitle("Operations"    331         lines.append(rst_subtitle("Operations"))
332         lines.append(parse_operations(obj["ope    332         lines.append(parse_operations(obj["operations"]["list"], family))
333                                                   333 
334     # Multicast groups                            334     # Multicast groups
335     if "mcast-groups" in obj:                     335     if "mcast-groups" in obj:
336         lines.append(rst_subtitle("Multicast g    336         lines.append(rst_subtitle("Multicast groups"))
337         lines.append(parse_mcast_group(obj["mc    337         lines.append(parse_mcast_group(obj["mcast-groups"]["list"]))
338                                                   338 
339     # Definitions                                 339     # Definitions
340     if "definitions" in obj:                      340     if "definitions" in obj:
341         lines.append(rst_subtitle("Definitions    341         lines.append(rst_subtitle("Definitions"))
342         lines.append(parse_definitions(obj["de    342         lines.append(parse_definitions(obj["definitions"], family))
343                                                   343 
344     # Attributes set                              344     # Attributes set
345     if "attribute-sets" in obj:                   345     if "attribute-sets" in obj:
346         lines.append(rst_subtitle("Attribute s    346         lines.append(rst_subtitle("Attribute sets"))
347         lines.append(parse_attr_sets(obj["attr    347         lines.append(parse_attr_sets(obj["attribute-sets"], family))
348                                                   348 
349     # Sub-messages                                349     # Sub-messages
350     if "sub-messages" in obj:                     350     if "sub-messages" in obj:
351         lines.append(rst_subtitle("Sub-message    351         lines.append(rst_subtitle("Sub-messages"))
352         lines.append(parse_sub_messages(obj["s    352         lines.append(parse_sub_messages(obj["sub-messages"], family))
353                                                   353 
354     return "\n".join(lines)                       354     return "\n".join(lines)
355                                                   355 
356                                                   356 
357 # Main functions                                  357 # Main functions
358 # ==============                                  358 # ==============
359                                                   359 
360                                                   360 
361 def parse_arguments() -> argparse.Namespace:      361 def parse_arguments() -> argparse.Namespace:
362     """Parse arguments from user"""               362     """Parse arguments from user"""
363     parser = argparse.ArgumentParser(descripti    363     parser = argparse.ArgumentParser(description="Netlink RST generator")
364                                                   364 
365     parser.add_argument("-v", "--verbose", act    365     parser.add_argument("-v", "--verbose", action="store_true")
366     parser.add_argument("-o", "--output", help    366     parser.add_argument("-o", "--output", help="Output file name")
367                                                   367 
368     # Index and input are mutually exclusive      368     # Index and input are mutually exclusive
369     group = parser.add_mutually_exclusive_grou    369     group = parser.add_mutually_exclusive_group()
370     group.add_argument(                           370     group.add_argument(
371         "-x", "--index", action="store_true",     371         "-x", "--index", action="store_true", help="Generate the index page"
372     )                                             372     )
373     group.add_argument("-i", "--input", help="    373     group.add_argument("-i", "--input", help="YAML file name")
374                                                   374 
375     args = parser.parse_args()                    375     args = parser.parse_args()
376                                                   376 
377     if args.verbose:                              377     if args.verbose:
378         logging.basicConfig(level=logging.DEBU    378         logging.basicConfig(level=logging.DEBUG)
379                                                   379 
380     if args.input and not os.path.isfile(args.    380     if args.input and not os.path.isfile(args.input):
381         logging.warning("%s is not a valid fil    381         logging.warning("%s is not a valid file.", args.input)
382         sys.exit(-1)                              382         sys.exit(-1)
383                                                   383 
384     if not args.output:                           384     if not args.output:
385         logging.error("No output file specifie    385         logging.error("No output file specified.")
386         sys.exit(-1)                              386         sys.exit(-1)
387                                                   387 
388     if os.path.isfile(args.output):               388     if os.path.isfile(args.output):
389         logging.debug("%s already exists. Over    389         logging.debug("%s already exists. Overwriting it.", args.output)
390                                                   390 
391     return args                                   391     return args
392                                                   392 
393                                                   393 
394 def parse_yaml_file(filename: str) -> str:        394 def parse_yaml_file(filename: str) -> str:
395     """Transform the YAML specified by filenam    395     """Transform the YAML specified by filename into a rst-formmated string"""
396     with open(filename, "r", encoding="utf-8")    396     with open(filename, "r", encoding="utf-8") as spec_file:
397         yaml_data = yaml.safe_load(spec_file)     397         yaml_data = yaml.safe_load(spec_file)
398         content = parse_yaml(yaml_data)           398         content = parse_yaml(yaml_data)
399                                                   399 
400     return content                                400     return content
401                                                   401 
402                                                   402 
403 def write_to_rstfile(content: str, filename: s    403 def write_to_rstfile(content: str, filename: str) -> None:
404     """Write the generated content into an RST    404     """Write the generated content into an RST file"""
405     logging.debug("Saving RST file to %s", fil    405     logging.debug("Saving RST file to %s", filename)
406                                                   406 
407     with open(filename, "w", encoding="utf-8")    407     with open(filename, "w", encoding="utf-8") as rst_file:
408         rst_file.write(content)                   408         rst_file.write(content)
409                                                   409 
410                                                   410 
411 def generate_main_index_rst(output: str) -> No    411 def generate_main_index_rst(output: str) -> None:
412     """Generate the `networking_spec/index` co    412     """Generate the `networking_spec/index` content and write to the file"""
413     lines = []                                    413     lines = []
414                                                   414 
415     lines.append(rst_header())                    415     lines.append(rst_header())
416     lines.append(rst_label("specs"))              416     lines.append(rst_label("specs"))
417     lines.append(rst_title("Netlink Family Spe    417     lines.append(rst_title("Netlink Family Specifications"))
418     lines.append(rst_toctree(1))                  418     lines.append(rst_toctree(1))
419                                                   419 
420     index_dir = os.path.dirname(output)           420     index_dir = os.path.dirname(output)
421     logging.debug("Looking for .rst files in %    421     logging.debug("Looking for .rst files in %s", index_dir)
422     for filename in sorted(os.listdir(index_di    422     for filename in sorted(os.listdir(index_dir)):
423         if not filename.endswith(".rst") or fi    423         if not filename.endswith(".rst") or filename == "index.rst":
424             continue                              424             continue
425         lines.append(f"   {filename.replace('.    425         lines.append(f"   {filename.replace('.rst', '')}\n")
426                                                   426 
427     logging.debug("Writing an index file at %s    427     logging.debug("Writing an index file at %s", output)
428     write_to_rstfile("".join(lines), output)      428     write_to_rstfile("".join(lines), output)
429                                                   429 
430                                                   430 
431 def main() -> None:                               431 def main() -> None:
432     """Main function that reads the YAML files    432     """Main function that reads the YAML files and generates the RST files"""
433                                                   433 
434     args = parse_arguments()                      434     args = parse_arguments()
435                                                   435 
436     if args.input:                                436     if args.input:
437         logging.debug("Parsing %s", args.input    437         logging.debug("Parsing %s", args.input)
438         try:                                      438         try:
439             content = parse_yaml_file(os.path.    439             content = parse_yaml_file(os.path.join(args.input))
440         except Exception as exception:            440         except Exception as exception:
441             logging.warning("Failed to parse %    441             logging.warning("Failed to parse %s.", args.input)
442             logging.warning(exception)            442             logging.warning(exception)
443             sys.exit(-1)                          443             sys.exit(-1)
444                                                   444 
445         write_to_rstfile(content, args.output)    445         write_to_rstfile(content, args.output)
446                                                   446 
447     if args.index:                                447     if args.index:
448         # Generate the index RST file             448         # Generate the index RST file
449         generate_main_index_rst(args.output)      449         generate_main_index_rst(args.output)
450                                                   450 
451                                                   451 
452 if __name__ == "__main__":                        452 if __name__ == "__main__":
453     main()                                        453     main()
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php