xref: /aosp_15_r20/external/cronet/net/tools/net_docs/net_docs.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env python
2# Copyright 2015 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6
7"""Reads, parses, and (optionally) writes as HTML the contents of Markdown
8files passed as arguments. Intended for rendering network stack documentation
9stored as Markdown in the source tree to a human-readable format."""
10
11
12import argparse
13import os.path
14import sys
15
16
17def nth_parent_directory(path, n):
18  for i in range(n):
19    path = os.path.dirname(path)
20  return path
21
22
23# Go up the directory tree from this script and add src/third_party to sys.path
24# so "import markdown" can find it in src/third_party/markdown.
25SCRIPT_PATH = os.path.abspath(__file__)
26SRC_PATH = nth_parent_directory(SCRIPT_PATH, 4)
27THIRD_PARTY_PATH = os.path.join(SRC_PATH, 'third_party')
28sys.path.insert(0, THIRD_PARTY_PATH)
29import markdown
30
31
32def ReadFile(filename):
33  with open(filename, 'r') as file:
34    return file.read()
35
36
37def WriteFile(filename, contents):
38  dir = os.path.dirname(filename)
39  if not os.path.isdir(dir):
40    os.mkdir(dir)
41  with open(filename, 'w') as file:
42    file.write(contents)
43
44
45TEMPLATE = """
46<html>
47  <head>
48    <title>{title}</title>
49  </head>
50  <body>
51    {body}
52  </body>
53</html>"""
54
55
56def FormatPage(markdown_html, title):
57  # TODO(juliatuttle): Add a navigation list / table of contents of available
58  # Markdown files, perhaps?
59  return TEMPLATE.format(title=title, body=markdown_html)
60
61
62def ProcessDocs(input_filenames, input_pathname, output_pathname,
63                extensions=None):
64  """Processes a list of Markdown documentation files.
65
66  If input_pathname and output_pathname are specified, outputs HTML files
67  into the corresponding subdirectories of output_pathname. If one or both is
68  not specified, simply ensures the files exist and contain valid Markdown.
69
70  Args:
71      input_filenames: A list of filenames (absolute, or relative to $PWD) of
72          Markdown files to parse and possibly render.
73      input_pathname: The base directory of the input files. (Needed so they
74          can be placed in the same relative path in the output path.)
75      output_pathname: The output directory into which rendered Markdown files
76          go, using that relative path.
77      extensions: a list of Markdown.extensions to apply if any.
78
79  Returns:
80      nothing
81
82  Raises:
83      IOError: if any of the file operations fail (e.g. input_filenames
84          contains a non-existent file).
85  """
86
87  outputting = (input_pathname is not None) and (output_pathname is not None)
88
89  if extensions:
90    markdown_parser = markdown.Markdown(extensions)
91  else:
92    markdown_parser = markdown.Markdown()
93
94  for input_filename in input_filenames:
95    markdown_text = ReadFile(input_filename)
96    markdown_html = markdown_parser.reset().convert(markdown_text)
97    if not outputting:
98      continue
99
100    full_html = FormatPage(markdown_html, title=input_filename)
101    rel_filename = os.path.relpath(input_filename, start=input_pathname)
102    output_filename = os.path.join(output_pathname, rel_filename) + '.html'
103    WriteFile(output_filename, full_html)
104
105
106def main():
107  parser = argparse.ArgumentParser(
108      description='Parse and render Markdown documentation')
109  parser.add_argument('--input_path', default=None,
110      help="Input path for Markdown; required only if output_path set")
111  parser.add_argument('--output_path', default=None,
112      help="Output path for rendered HTML; if unspecified, won't output")
113  parser.add_argument('filenames', nargs=argparse.REMAINDER)
114  args = parser.parse_args()
115
116  extensions = ['markdown.extensions.def_list']
117  ProcessDocs(args.filenames, args.input_path, args.output_path, extensions)
118
119  return 0
120
121
122if __name__ == '__main__':
123  sys.exit(main())
124