~ [ 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 (Version linux-6.12-rc7) and /tools/net/ynl/ynl-gen-rst.py (Version linux-6.9.12)


  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(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"\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: << 
106     """Add a hyperlink to the document"""      << 
107     mappings = {'enum': 'definition',          << 
108                 'fixed-header': 'definition',  << 
109                 'nested-attributes': 'attribut << 
110                 'struct': 'definition'}        << 
111     if prefix in mappings:                     << 
112         prefix = mappings[prefix]              << 
113     return f":ref:`{namespace}-{prefix}-{name} << 
114                                                << 
115                                                << 
116 def rst_header() -> str:                          105 def rst_header() -> str:
117     """The headers for all the auto generated     106     """The headers for all the auto generated RST files"""
118     lines = []                                    107     lines = []
119                                                   108 
120     lines.append(rst_paragraph(".. SPDX-Licens    109     lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0"))
121     lines.append(rst_paragraph(".. NOTE: This     110     lines.append(rst_paragraph(".. NOTE: This document was auto-generated.\n\n"))
122                                                   111 
123     return "\n".join(lines)                       112     return "\n".join(lines)
124                                                   113 
125                                                   114 
126 def rst_toctree(maxdepth: int = 2) -> str:        115 def rst_toctree(maxdepth: int = 2) -> str:
127     """Generate a toctree RST primitive"""        116     """Generate a toctree RST primitive"""
128     lines = []                                    117     lines = []
129                                                   118 
130     lines.append(".. toctree::")                  119     lines.append(".. toctree::")
131     lines.append(f"   :maxdepth: {maxdepth}\n\    120     lines.append(f"   :maxdepth: {maxdepth}\n\n")
132                                                   121 
133     return "\n".join(lines)                       122     return "\n".join(lines)
134                                                   123 
135                                                   124 
136 def rst_label(title: str) -> str:                 125 def rst_label(title: str) -> str:
137     """Return a formatted label"""                126     """Return a formatted label"""
138     return f".. _{title}:\n\n"                    127     return f".. _{title}:\n\n"
139                                                   128 
140                                                   129 
141 # Parsers                                         130 # Parsers
142 # =======                                         131 # =======
143                                                   132 
144                                                   133 
145 def parse_mcast_group(mcast_group: List[Dict[s    134 def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str:
146     """Parse 'multicast' group list and return    135     """Parse 'multicast' group list and return a formatted string"""
147     lines = []                                    136     lines = []
148     for group in mcast_group:                     137     for group in mcast_group:
149         lines.append(rst_bullet(group["name"])    138         lines.append(rst_bullet(group["name"]))
150                                                   139 
151     return "\n".join(lines)                       140     return "\n".join(lines)
152                                                   141 
153                                                   142 
154 def parse_do(do_dict: Dict[str, Any], level: i    143 def parse_do(do_dict: Dict[str, Any], level: int = 0) -> str:
155     """Parse 'do' section and return a formatt    144     """Parse 'do' section and return a formatted string"""
156     lines = []                                    145     lines = []
157     for key in do_dict.keys():                    146     for key in do_dict.keys():
158         lines.append(rst_paragraph(bold(key),     147         lines.append(rst_paragraph(bold(key), level + 1))
159         if key in ['request', 'reply']:        !! 148         lines.append(parse_do_attributes(do_dict[key], level + 1) + "\n")
160             lines.append(parse_do_attributes(d << 
161         else:                                  << 
162             lines.append(headroom(level + 2) + << 
163                                                   149 
164     return "\n".join(lines)                       150     return "\n".join(lines)
165                                                   151 
166                                                   152 
167 def parse_do_attributes(attrs: Dict[str, Any],    153 def parse_do_attributes(attrs: Dict[str, Any], level: int = 0) -> str:
168     """Parse 'attributes' section"""              154     """Parse 'attributes' section"""
169     if "attributes" not in attrs:                 155     if "attributes" not in attrs:
170         return ""                                 156         return ""
171     lines = [rst_fields("attributes", rst_list    157     lines = [rst_fields("attributes", rst_list_inline(attrs["attributes"]), level + 1)]
172                                                   158 
173     return "\n".join(lines)                       159     return "\n".join(lines)
174                                                   160 
175                                                   161 
176 def parse_operations(operations: List[Dict[str !! 162 def parse_operations(operations: List[Dict[str, Any]]) -> str:
177     """Parse operations block"""                  163     """Parse operations block"""
178     preprocessed = ["name", "doc", "title", "d !! 164     preprocessed = ["name", "doc", "title", "do", "dump"]
179     linkable = ["fixed-header", "attribute-set << 
180     lines = []                                    165     lines = []
181                                                   166 
182     for operation in operations:                  167     for operation in operations:
183         lines.append(rst_section(namespace, 'o !! 168         lines.append(rst_section(operation["name"]))
184         lines.append(rst_paragraph(operation[" !! 169         lines.append(rst_paragraph(sanitize(operation["doc"])) + "\n")
185                                                   170 
186         for key in operation.keys():              171         for key in operation.keys():
187             if key in preprocessed:               172             if key in preprocessed:
188                 # Skip the special fields         173                 # Skip the special fields
189                 continue                          174                 continue
190             value = operation[key]             !! 175             lines.append(rst_fields(key, operation[key], 0))
191             if key in linkable:                << 
192                 value = rst_ref(namespace, key << 
193             lines.append(rst_fields(key, value << 
194         if 'flags' in operation:               << 
195             lines.append(rst_fields('flags', r << 
196                                                   176 
197         if "do" in operation:                     177         if "do" in operation:
198             lines.append(rst_paragraph(":do:",    178             lines.append(rst_paragraph(":do:", 0))
199             lines.append(parse_do(operation["d    179             lines.append(parse_do(operation["do"], 0))
200         if "dump" in operation:                   180         if "dump" in operation:
201             lines.append(rst_paragraph(":dump:    181             lines.append(rst_paragraph(":dump:", 0))
202             lines.append(parse_do(operation["d    182             lines.append(parse_do(operation["dump"], 0))
203                                                   183 
204         # New line after fields                   184         # New line after fields
205         lines.append("\n")                        185         lines.append("\n")
206                                                   186 
207     return "\n".join(lines)                       187     return "\n".join(lines)
208                                                   188 
209                                                   189 
210 def parse_entries(entries: List[Dict[str, Any]    190 def parse_entries(entries: List[Dict[str, Any]], level: int) -> str:
211     """Parse a list of entries"""                 191     """Parse a list of entries"""
212     ignored = ["pad"]                             192     ignored = ["pad"]
213     lines = []                                    193     lines = []
214     for entry in entries:                         194     for entry in entries:
215         if isinstance(entry, dict):               195         if isinstance(entry, dict):
216             # entries could be a list or a dic    196             # entries could be a list or a dictionary
217             field_name = entry.get("name", "")    197             field_name = entry.get("name", "")
218             if field_name in ignored:             198             if field_name in ignored:
219                 continue                          199                 continue
220             type_ = entry.get("type")             200             type_ = entry.get("type")
221             if type_:                             201             if type_:
222                 field_name += f" ({inline(type    202                 field_name += f" ({inline(type_)})"
223             lines.append(                         203             lines.append(
224                 rst_fields(field_name, sanitiz    204                 rst_fields(field_name, sanitize(entry.get("doc", "")), level)
225             )                                     205             )
226         elif isinstance(entry, list):             206         elif isinstance(entry, list):
227             lines.append(rst_list_inline(entry    207             lines.append(rst_list_inline(entry, level))
228         else:                                     208         else:
229             lines.append(rst_bullet(inline(san    209             lines.append(rst_bullet(inline(sanitize(entry)), level))
230                                                   210 
231     lines.append("\n")                            211     lines.append("\n")
232     return "\n".join(lines)                       212     return "\n".join(lines)
233                                                   213 
234                                                   214 
235 def parse_definitions(defs: Dict[str, Any], na !! 215 def parse_definitions(defs: Dict[str, Any]) -> str:
236     """Parse definitions section"""               216     """Parse definitions section"""
237     preprocessed = ["name", "entries", "member    217     preprocessed = ["name", "entries", "members"]
238     ignored = ["render-max"]  # This is not pr    218     ignored = ["render-max"]  # This is not printed
239     lines = []                                    219     lines = []
240                                                   220 
241     for definition in defs:                       221     for definition in defs:
242         lines.append(rst_section(namespace, 'd !! 222         lines.append(rst_section(definition["name"]))
243         for k in definition.keys():               223         for k in definition.keys():
244             if k in preprocessed + ignored:       224             if k in preprocessed + ignored:
245                 continue                          225                 continue
246             lines.append(rst_fields(k, sanitiz    226             lines.append(rst_fields(k, sanitize(definition[k]), 0))
247                                                   227 
248         # Field list needs to finish with a ne    228         # Field list needs to finish with a new line
249         lines.append("\n")                        229         lines.append("\n")
250         if "entries" in definition:               230         if "entries" in definition:
251             lines.append(rst_paragraph(":entri    231             lines.append(rst_paragraph(":entries:", 0))
252             lines.append(parse_entries(definit    232             lines.append(parse_entries(definition["entries"], 1))
253         if "members" in definition:               233         if "members" in definition:
254             lines.append(rst_paragraph(":membe    234             lines.append(rst_paragraph(":members:", 0))
255             lines.append(parse_entries(definit    235             lines.append(parse_entries(definition["members"], 1))
256                                                   236 
257     return "\n".join(lines)                       237     return "\n".join(lines)
258                                                   238 
259                                                   239 
260 def parse_attr_sets(entries: List[Dict[str, An !! 240 def parse_attr_sets(entries: List[Dict[str, Any]]) -> str:
261     """Parse attribute from attribute-set"""      241     """Parse attribute from attribute-set"""
262     preprocessed = ["name", "type"]               242     preprocessed = ["name", "type"]
263     linkable = ["enum", "nested-attributes", " << 
264     ignored = ["checks"]                          243     ignored = ["checks"]
265     lines = []                                    244     lines = []
266                                                   245 
267     for entry in entries:                         246     for entry in entries:
268         lines.append(rst_section(namespace, 'a !! 247         lines.append(rst_section(entry["name"]))
269         for attr in entry["attributes"]:          248         for attr in entry["attributes"]:
270             type_ = attr.get("type")              249             type_ = attr.get("type")
271             attr_line = attr["name"]              250             attr_line = attr["name"]
272             if type_:                             251             if type_:
273                 # Add the attribute type in th    252                 # Add the attribute type in the same line
274                 attr_line += f" ({inline(type_    253                 attr_line += f" ({inline(type_)})"
275                                                   254 
276             lines.append(rst_subsubsection(att    255             lines.append(rst_subsubsection(attr_line))
277                                                   256 
278             for k in attr.keys():                 257             for k in attr.keys():
279                 if k in preprocessed + ignored    258                 if k in preprocessed + ignored:
280                     continue                      259                     continue
281                 if k in linkable:              !! 260                 lines.append(rst_fields(k, sanitize(attr[k]), 0))
282                     value = rst_ref(namespace, << 
283                 else:                          << 
284                     value = sanitize(attr[k])  << 
285                 lines.append(rst_fields(k, val << 
286             lines.append("\n")                    261             lines.append("\n")
287                                                   262 
288     return "\n".join(lines)                       263     return "\n".join(lines)
289                                                   264 
290                                                   265 
291 def parse_sub_messages(entries: List[Dict[str, !! 266 def parse_sub_messages(entries: List[Dict[str, Any]]) -> str:
292     """Parse sub-message definitions"""           267     """Parse sub-message definitions"""
293     lines = []                                    268     lines = []
294                                                   269 
295     for entry in entries:                         270     for entry in entries:
296         lines.append(rst_section(namespace, 's !! 271         lines.append(rst_section(entry["name"]))
297         for fmt in entry["formats"]:              272         for fmt in entry["formats"]:
298             value = fmt["value"]                  273             value = fmt["value"]
299                                                   274 
300             lines.append(rst_bullet(bold(value    275             lines.append(rst_bullet(bold(value)))
301             for attr in ['fixed-header', 'attr    276             for attr in ['fixed-header', 'attribute-set']:
302                 if attr in fmt:                   277                 if attr in fmt:
303                     lines.append(rst_fields(at !! 278                     lines.append(rst_fields(attr, fmt[attr], 1))
304                                             rs << 
305                                             1) << 
306             lines.append("\n")                    279             lines.append("\n")
307                                                   280 
308     return "\n".join(lines)                       281     return "\n".join(lines)
309                                                   282 
310                                                   283 
311 def parse_yaml(obj: Dict[str, Any]) -> str:       284 def parse_yaml(obj: Dict[str, Any]) -> str:
312     """Format the whole YAML into a RST string    285     """Format the whole YAML into a RST string"""
313     lines = []                                    286     lines = []
314                                                   287 
315     # Main header                                 288     # Main header
316                                                   289 
317     lines.append(rst_header())                    290     lines.append(rst_header())
318                                                   291 
319     family = obj['name']                       !! 292     title = f"Family ``{obj['name']}`` netlink specification"
320                                                << 
321     title = f"Family ``{family}`` netlink spec << 
322     lines.append(rst_title(title))                293     lines.append(rst_title(title))
323     lines.append(rst_paragraph(".. contents::  !! 294     lines.append(rst_paragraph(".. contents::\n"))
324                                                   295 
325     if "doc" in obj:                              296     if "doc" in obj:
326         lines.append(rst_subtitle("Summary"))     297         lines.append(rst_subtitle("Summary"))
327         lines.append(rst_paragraph(obj["doc"],    298         lines.append(rst_paragraph(obj["doc"], 0))
328                                                   299 
329     # Operations                                  300     # Operations
330     if "operations" in obj:                       301     if "operations" in obj:
331         lines.append(rst_subtitle("Operations"    302         lines.append(rst_subtitle("Operations"))
332         lines.append(parse_operations(obj["ope !! 303         lines.append(parse_operations(obj["operations"]["list"]))
333                                                   304 
334     # Multicast groups                            305     # Multicast groups
335     if "mcast-groups" in obj:                     306     if "mcast-groups" in obj:
336         lines.append(rst_subtitle("Multicast g    307         lines.append(rst_subtitle("Multicast groups"))
337         lines.append(parse_mcast_group(obj["mc    308         lines.append(parse_mcast_group(obj["mcast-groups"]["list"]))
338                                                   309 
339     # Definitions                                 310     # Definitions
340     if "definitions" in obj:                      311     if "definitions" in obj:
341         lines.append(rst_subtitle("Definitions    312         lines.append(rst_subtitle("Definitions"))
342         lines.append(parse_definitions(obj["de !! 313         lines.append(parse_definitions(obj["definitions"]))
343                                                   314 
344     # Attributes set                              315     # Attributes set
345     if "attribute-sets" in obj:                   316     if "attribute-sets" in obj:
346         lines.append(rst_subtitle("Attribute s    317         lines.append(rst_subtitle("Attribute sets"))
347         lines.append(parse_attr_sets(obj["attr !! 318         lines.append(parse_attr_sets(obj["attribute-sets"]))
348                                                   319 
349     # Sub-messages                                320     # Sub-messages
350     if "sub-messages" in obj:                     321     if "sub-messages" in obj:
351         lines.append(rst_subtitle("Sub-message    322         lines.append(rst_subtitle("Sub-messages"))
352         lines.append(parse_sub_messages(obj["s !! 323         lines.append(parse_sub_messages(obj["sub-messages"]))
353                                                   324 
354     return "\n".join(lines)                       325     return "\n".join(lines)
355                                                   326 
356                                                   327 
357 # Main functions                                  328 # Main functions
358 # ==============                                  329 # ==============
359                                                   330 
360                                                   331 
361 def parse_arguments() -> argparse.Namespace:      332 def parse_arguments() -> argparse.Namespace:
362     """Parse arguments from user"""               333     """Parse arguments from user"""
363     parser = argparse.ArgumentParser(descripti    334     parser = argparse.ArgumentParser(description="Netlink RST generator")
364                                                   335 
365     parser.add_argument("-v", "--verbose", act    336     parser.add_argument("-v", "--verbose", action="store_true")
366     parser.add_argument("-o", "--output", help    337     parser.add_argument("-o", "--output", help="Output file name")
367                                                   338 
368     # Index and input are mutually exclusive      339     # Index and input are mutually exclusive
369     group = parser.add_mutually_exclusive_grou    340     group = parser.add_mutually_exclusive_group()
370     group.add_argument(                           341     group.add_argument(
371         "-x", "--index", action="store_true",     342         "-x", "--index", action="store_true", help="Generate the index page"
372     )                                             343     )
373     group.add_argument("-i", "--input", help="    344     group.add_argument("-i", "--input", help="YAML file name")
374                                                   345 
375     args = parser.parse_args()                    346     args = parser.parse_args()
376                                                   347 
377     if args.verbose:                              348     if args.verbose:
378         logging.basicConfig(level=logging.DEBU    349         logging.basicConfig(level=logging.DEBUG)
379                                                   350 
380     if args.input and not os.path.isfile(args.    351     if args.input and not os.path.isfile(args.input):
381         logging.warning("%s is not a valid fil    352         logging.warning("%s is not a valid file.", args.input)
382         sys.exit(-1)                              353         sys.exit(-1)
383                                                   354 
384     if not args.output:                           355     if not args.output:
385         logging.error("No output file specifie    356         logging.error("No output file specified.")
386         sys.exit(-1)                              357         sys.exit(-1)
387                                                   358 
388     if os.path.isfile(args.output):               359     if os.path.isfile(args.output):
389         logging.debug("%s already exists. Over    360         logging.debug("%s already exists. Overwriting it.", args.output)
390                                                   361 
391     return args                                   362     return args
392                                                   363 
393                                                   364 
394 def parse_yaml_file(filename: str) -> str:        365 def parse_yaml_file(filename: str) -> str:
395     """Transform the YAML specified by filenam    366     """Transform the YAML specified by filename into a rst-formmated string"""
396     with open(filename, "r", encoding="utf-8")    367     with open(filename, "r", encoding="utf-8") as spec_file:
397         yaml_data = yaml.safe_load(spec_file)     368         yaml_data = yaml.safe_load(spec_file)
398         content = parse_yaml(yaml_data)           369         content = parse_yaml(yaml_data)
399                                                   370 
400     return content                                371     return content
401                                                   372 
402                                                   373 
403 def write_to_rstfile(content: str, filename: s    374 def write_to_rstfile(content: str, filename: str) -> None:
404     """Write the generated content into an RST    375     """Write the generated content into an RST file"""
405     logging.debug("Saving RST file to %s", fil    376     logging.debug("Saving RST file to %s", filename)
406                                                   377 
407     with open(filename, "w", encoding="utf-8")    378     with open(filename, "w", encoding="utf-8") as rst_file:
408         rst_file.write(content)                   379         rst_file.write(content)
409                                                   380 
410                                                   381 
411 def generate_main_index_rst(output: str) -> No    382 def generate_main_index_rst(output: str) -> None:
412     """Generate the `networking_spec/index` co    383     """Generate the `networking_spec/index` content and write to the file"""
413     lines = []                                    384     lines = []
414                                                   385 
415     lines.append(rst_header())                    386     lines.append(rst_header())
416     lines.append(rst_label("specs"))              387     lines.append(rst_label("specs"))
417     lines.append(rst_title("Netlink Family Spe    388     lines.append(rst_title("Netlink Family Specifications"))
418     lines.append(rst_toctree(1))                  389     lines.append(rst_toctree(1))
419                                                   390 
420     index_dir = os.path.dirname(output)           391     index_dir = os.path.dirname(output)
421     logging.debug("Looking for .rst files in %    392     logging.debug("Looking for .rst files in %s", index_dir)
422     for filename in sorted(os.listdir(index_di    393     for filename in sorted(os.listdir(index_dir)):
423         if not filename.endswith(".rst") or fi    394         if not filename.endswith(".rst") or filename == "index.rst":
424             continue                              395             continue
425         lines.append(f"   {filename.replace('.    396         lines.append(f"   {filename.replace('.rst', '')}\n")
426                                                   397 
427     logging.debug("Writing an index file at %s    398     logging.debug("Writing an index file at %s", output)
428     write_to_rstfile("".join(lines), output)      399     write_to_rstfile("".join(lines), output)
429                                                   400 
430                                                   401 
431 def main() -> None:                               402 def main() -> None:
432     """Main function that reads the YAML files    403     """Main function that reads the YAML files and generates the RST files"""
433                                                   404 
434     args = parse_arguments()                      405     args = parse_arguments()
435                                                   406 
436     if args.input:                                407     if args.input:
437         logging.debug("Parsing %s", args.input    408         logging.debug("Parsing %s", args.input)
438         try:                                      409         try:
439             content = parse_yaml_file(os.path.    410             content = parse_yaml_file(os.path.join(args.input))
440         except Exception as exception:            411         except Exception as exception:
441             logging.warning("Failed to parse %    412             logging.warning("Failed to parse %s.", args.input)
442             logging.warning(exception)            413             logging.warning(exception)
443             sys.exit(-1)                          414             sys.exit(-1)
444                                                   415 
445         write_to_rstfile(content, args.output)    416         write_to_rstfile(content, args.output)
446                                                   417 
447     if args.index:                                418     if args.index:
448         # Generate the index RST file             419         # Generate the index RST file
449         generate_main_index_rst(args.output)      420         generate_main_index_rst(args.output)
450                                                   421 
451                                                   422 
452 if __name__ == "__main__":                        423 if __name__ == "__main__":
453     main()                                        424     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