Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_docgen / py / pw_docgen / docgen.py
1 # Copyright 2019 The Pigweed Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 # use this file except in compliance with the License. You may obtain a copy of
5 # the License at
6 #
7 #     https://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations under
13 # the License.
14 """Renders HTML documentation using Sphinx."""
15
16 # TODO(frolv): Figure out a solution for installing all library dependencies
17 # to run Sphinx and build RTD docs.
18
19 import argparse
20 import collections
21 import json
22 import os
23 import shutil
24 import subprocess
25 import sys
26
27 from typing import Dict, List, Tuple
28
29 SCRIPT_HEADER: str = '''
30 ██████╗ ██╗ ██████╗ ██╗    ██╗███████╗███████╗██████╗     ██████╗  ██████╗  ██████╗███████╗
31 ██╔══██╗██║██╔════╝ ██║    ██║██╔════╝██╔════╝██╔══██╗    ██╔══██╗██╔═══██╗██╔════╝██╔════╝
32 ██████╔╝██║██║  ███╗██║ █╗ ██║█████╗  █████╗  ██║  ██║    ██║  ██║██║   ██║██║     ███████╗
33 ██╔═══╝ ██║██║   ██║██║███╗██║██╔══╝  ██╔══╝  ██║  ██║    ██║  ██║██║   ██║██║     ╚════██║
34 ██║     ██║╚██████╔╝╚███╔███╔╝███████╗███████╗██████╔╝    ██████╔╝╚██████╔╝╚██████╗███████║
35 ╚═╝     ╚═╝ ╚═════╝  ╚══╝╚══╝ ╚══════╝╚══════╝╚═════╝     ╚═════╝  ╚═════╝  ╚═════╝╚══════╝
36 '''
37
38
39 def parse_args() -> argparse.Namespace:
40     """Parses command-line arguments."""
41
42     parser = argparse.ArgumentParser(description=__doc__)
43     parser.add_argument('--sphinx-build-dir',
44                         required=True,
45                         help='Directory in which to build docs')
46     parser.add_argument('--conf',
47                         required=True,
48                         help='Path to conf.py file for Sphinx')
49     parser.add_argument('--gn-root',
50                         required=True,
51                         help='Root of the GN build tree')
52     parser.add_argument('--gn-gen-root',
53                         required=True,
54                         help='Root of the GN gen tree')
55     parser.add_argument('sources',
56                         nargs='+',
57                         help='Paths to the root level rst source files')
58     parser.add_argument('--out-dir',
59                         required=True,
60                         help='Output directory for rendered HTML docs')
61     parser.add_argument('--metadata',
62                         required=True,
63                         type=argparse.FileType('r'),
64                         help='Metadata JSON file')
65     return parser.parse_args()
66
67
68 def build_docs(src_dir: str, dst_dir: str) -> int:
69     """Runs Sphinx to render HTML documentation from a doc tree."""
70
71     # TODO(frolv): Specify the Sphinx script from a prebuilts path instead of
72     # requiring it in the tree.
73     command = [
74         'sphinx-build', '-W', '-b', 'html', '-d', f'{dst_dir}/help', src_dir,
75         f'{dst_dir}/html'
76     ]
77     return subprocess.call(command)
78
79
80 def mkdir(dirname: str, exist_ok: bool = False) -> None:
81     """Wrapper around os.makedirs that prints the operation."""
82     print(f'MKDIR {dirname}')
83     os.makedirs(dirname, exist_ok=exist_ok)
84
85
86 def copy(src: str, dst: str) -> None:
87     """Wrapper around shutil.copy that prints the operation."""
88     print(f'COPY  {src} -> {dst}')
89     shutil.copy(src, dst)
90
91
92 def copy_doc_tree(args: argparse.Namespace) -> None:
93     """Copies doc source and input files into a build tree."""
94     def build_path(path):
95         """Converts a source path to a filename in the build directory."""
96         if path.startswith(args.gn_root):
97             path = os.path.relpath(path, args.gn_root)
98         elif path.startswith(args.gn_gen_root):
99             path = os.path.relpath(path, args.gn_gen_root)
100
101         return os.path.join(args.sphinx_build_dir, path)
102
103     source_files = json.load(args.metadata)
104     copy_paths = [build_path(f) for f in source_files]
105
106     mkdir(args.sphinx_build_dir)
107     for source_path in args.sources:
108         copy(source_path, f'{args.sphinx_build_dir}/')
109     copy(args.conf, f'{args.sphinx_build_dir}/conf.py')
110
111     # Map of directory path to list of source and destination file paths.
112     dirs: Dict[str, List[Tuple[str, str]]] = collections.defaultdict(list)
113
114     for source_file, copy_path in zip(source_files, copy_paths):
115         dirname = os.path.dirname(copy_path)
116         dirs[dirname].append((source_file, copy_path))
117
118     for directory, file_pairs in dirs.items():
119         mkdir(directory, exist_ok=True)
120         for src, dst in file_pairs:
121             copy(src, dst)
122
123
124 def main() -> int:
125     """Script entry point."""
126
127     args = parse_args()
128
129     # Clear out any existing docs for the target.
130     if os.path.exists(args.sphinx_build_dir):
131         shutil.rmtree(args.sphinx_build_dir)
132
133     # TODO(pwbug/164): Printing the header causes unicode problems on Windows.
134     # Disabled for now; re-enable once the root issue is fixed.
135     # print(SCRIPT_HEADER)
136     copy_doc_tree(args)
137
138     # Flush all script output before running Sphinx.
139     print('-' * 80, flush=True)
140
141     return build_docs(args.sphinx_build_dir, args.out_dir)
142
143
144 if __name__ == '__main__':
145     sys.exit(main())