1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# -*- coding: utf-8; mode: python -*- 4 5""" 6 Script to auto generate the documentation for Netlink specifications. 7 8 :copyright: Copyright (C) 2023 Breno Leitao <leitao@debian.org> 9 :license: GPL Version 2, June 1991 see linux/COPYING for details. 10 11 This script performs extensive parsing to the Linux kernel's netlink YAML 12 spec files, in an effort to avoid needing to heavily mark up the original 13 YAML file. It uses the library code from scripts/lib. 14""" 15 16import os.path 17import pathlib 18import sys 19import argparse 20import logging 21 22sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) 23from lib import YnlDocGenerator # pylint: disable=C0413 24 25def parse_arguments() -> argparse.Namespace: 26 """Parse arguments from user""" 27 parser = argparse.ArgumentParser(description="Netlink RST generator") 28 29 parser.add_argument("-v", "--verbose", action="store_true") 30 parser.add_argument("-o", "--output", help="Output file name") 31 32 # Index and input are mutually exclusive 33 group = parser.add_mutually_exclusive_group() 34 group.add_argument( 35 "-x", "--index", action="store_true", help="Generate the index page" 36 ) 37 group.add_argument("-i", "--input", help="YAML file name") 38 39 args = parser.parse_args() 40 41 if args.verbose: 42 logging.basicConfig(level=logging.DEBUG) 43 44 if args.input and not os.path.isfile(args.input): 45 logging.warning("%s is not a valid file.", args.input) 46 sys.exit(-1) 47 48 if not args.output: 49 logging.error("No output file specified.") 50 sys.exit(-1) 51 52 if os.path.isfile(args.output): 53 logging.debug("%s already exists. Overwriting it.", args.output) 54 55 return args 56 57 58def write_to_rstfile(content: str, filename: str) -> None: 59 """Write the generated content into an RST file""" 60 logging.debug("Saving RST file to %s", filename) 61 62 with open(filename, "w", encoding="utf-8") as rst_file: 63 rst_file.write(content) 64 65 66def generate_main_index_rst(parser: YnlDocGenerator, output: str) -> None: 67 """Generate the `networking_spec/index` content and write to the file""" 68 lines = [] 69 70 lines.append(parser.fmt.rst_header()) 71 lines.append(parser.fmt.rst_label("specs")) 72 lines.append(parser.fmt.rst_title("Netlink Family Specifications")) 73 lines.append(parser.fmt.rst_toctree(1)) 74 75 index_dir = os.path.dirname(output) 76 logging.debug("Looking for .rst files in %s", index_dir) 77 for filename in sorted(os.listdir(index_dir)): 78 base, ext = os.path.splitext(filename) 79 if filename == "index.rst" or ext not in [".rst", ".yaml"]: 80 continue 81 lines.append(f" {base}\n") 82 83 logging.debug("Writing an index file at %s", output) 84 write_to_rstfile("".join(lines), output) 85 86 87def main() -> None: 88 """Main function that reads the YAML files and generates the RST files""" 89 90 args = parse_arguments() 91 92 parser = YnlDocGenerator() 93 94 if args.input: 95 logging.debug("Parsing %s", args.input) 96 try: 97 content = parser.parse_yaml_file(os.path.join(args.input)) 98 except Exception as exception: 99 logging.warning("Failed to parse %s.", args.input) 100 logging.warning(exception) 101 sys.exit(-1) 102 103 write_to_rstfile(content, args.output) 104 105 if args.index: 106 # Generate the index RST file 107 generate_main_index_rst(parser, args.output) 108 109 110if __name__ == "__main__": 111 main() 112