blob: 3468f9e00a28b926c6f5a6ba4c51bea294acee76 [file] [log] [blame]
Wei-Yu Chen49950b92021-11-08 19:19:18 +08001"""
2Copyright 2020 The Magma Authors.
3
4This source code is licensed under the BSD-style license found in the
5LICENSE file in the root directory of this source tree.
6
7Unless required by applicable law or agreed to in writing, software
8distributed under the License is distributed on an "AS IS" BASIS,
9WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10See the License for the specific language governing permissions and
11limitations under the License.
12"""
13import os
14import shutil
15import sys
16from typing import Iterable, List
17
18from grpc.tools import protoc
19
20
21def find_all_proto_files_in_dir(input_dir: str) -> List[str]:
22 """
23 Returns a list of filenames of .proto files in the given directory
24
25 Args:
26 input_dir: Directory to search in
27
28 Returns:
29 list(str): List of .proto filenames in the directory
30 """
31 proto_files = []
32 for root, _, names in os.walk(input_dir):
33 for name in names:
34 full_filename = os.path.join(root, name)
35 extn = os.path.splitext(name)[1]
36
37 # Recurse into subdirectories
38 if os.path.isdir(full_filename):
39 proto_files += find_all_proto_files_in_dir(full_filename)
40 if os.path.isfile(full_filename) and extn == '.proto':
41 # TODO: find a better way to exclude the prometheus proto
42 if not full_filename.endswith('prometheus/metrics.proto'):
43 proto_files.append(full_filename)
44 return proto_files
45
46
47def gen_bindings(
48 input_dir: str,
49 include_paths: Iterable[str],
50 proto_path: str,
51 output_dir: str,
52) -> None:
53 """
54 Generates python and Go bindings for all .proto files in input dir
55 @input_dir - input directory with .proto files to generate code for
56 @include_paths - a list of include paths to resolve relative imports in .protos
57 @output_dir - output directory to put generated code in
58 """
59 protofiles = find_all_proto_files_in_dir(input_dir)
60
61 inouts = [
62 '-I' + proto_path,
63 '--python_out=' + output_dir,
64 '--grpc_python_out=' + output_dir,
65 ]
66 # Only run mypy (dev dependency) when the protoc-consumed executable exists
67 if shutil.which('protoc-gen-mypy') is not None:
68 inouts.append('--mypy_out=' + output_dir)
69
70 protoc.main(
71 ('',) +
72 tuple('-I' + path for path in include_paths) +
73 tuple(inouts) +
74 tuple(f for f in protofiles),
75 )
76
77
78def main():
79 """
80 Default main module. Generates .py code for all proto files
81 specified by the arguments
82 """
83 if len(sys.argv) != 5:
84 print(
85 "Usage: ./gen_protos.py <dir containing .proto's> <include paths CSV> <proto_path for imports> <output dir>",
86 )
87 exit(1)
88 input_dir = sys.argv[1]
89 include_paths = sys.argv[2].split(',')
90 # The deprecated vagrant box image amarpad/magma_dev has grpc installed
91 # from source, with header files located at /usr/local/include. In the new
92 # box image amarpad/debian_jessie, grpc is installed from deb package, with
93 # headers located at /usr/include. Currently, only the magma_test vm uses
94 # amarpad/magma_dev.
95 #
96 # TODO: Migrate magma_test to amarpad/debian_jessie to to remove the
97 # '/usr/local/include'
98 include_paths.append('/usr/local/include')
99 proto_path = sys.argv[3]
100 output_dir = sys.argv[4]
101 gen_bindings(input_dir, include_paths, proto_path, output_dir)
102
103
104if __name__ == "__main__":
105 main()
106