blob: 8c1a27787b4c478c4e0c6b1e1308940ec1d2d407 [file] [log] [blame]
Hector Dearmanb7fa5442018-11-08 18:39:32 +00001#!/usr/bin/env python
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from __future__ import absolute_import
17from __future__ import division
18from __future__ import print_function
19import os
20import re
21import sys
22import argparse
23import tempfile
24import subprocess
25import hashlib
26import textwrap
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +010027from compat import iteritems
Hector Dearmanb7fa5442018-11-08 18:39:32 +000028
29SOURCE_TARGET = {
30 'protos/perfetto/config/perfetto_config.proto':
Primiano Tucci834fdc72019-10-04 11:33:44 +010031 'src/perfetto_cmd/perfetto_config.descriptor.h',
Lalit Magantieb1bf212019-05-08 15:07:16 +010032 'protos/perfetto/metrics/metrics.proto':
Primiano Tucci834fdc72019-10-04 11:33:44 +010033 'src/trace_processor/metrics/metrics.descriptor.h',
Stephen Nuskobc76a6c2019-12-03 11:55:27 +000034 'src/protozero/test/example_proto/test_messages.proto':
35 'src/protozero/test/example_proto/test_messages.descriptor.h',
Stephen Nusko279fb0e2019-12-12 16:51:55 +000036 'protos/perfetto/trace/track_event/track_event.proto':
37 'src/trace_processor/importers/proto/track_event.descriptor.h',
Deepanjan Royf4da5092020-07-15 17:59:04 -040038 'protos/perfetto/metrics/chrome/all_chrome_metrics.proto':
39 'src/trace_processor/metrics/chrome/all_chrome_metrics.descriptor.h',
Anindita Ghoshb6f6a3c2020-07-21 12:47:16 +000040 'protos/perfetto/trace_processor/trace_processor.proto':
Lalit Maganti82a2c042020-07-06 13:50:33 +010041 'src/trace_processor/python/trace_processor/trace_processor.descriptor',
Anindita Ghoshb6f6a3c2020-07-21 12:47:16 +000042 'protos/perfetto/metrics/metrics.proto':
43 'src/trace_processor/python/trace_processor/metrics.descriptor',
Hector Dearmanb7fa5442018-11-08 18:39:32 +000044}
45
46ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
47
48SCRIPT_PATH = 'tools/gen_binary_descriptors'
49
Hector Dearman1e269142018-11-14 13:53:08 +000050
Hector Dearmanb7fa5442018-11-08 18:39:32 +000051def hash_path(path):
52 hash = hashlib.sha1()
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +010053 with open(os.path.join(ROOT_DIR, path), 'rb') as f:
Hector Dearmanb7fa5442018-11-08 18:39:32 +000054 hash.update(f.read())
55 return hash.hexdigest()
56
57
Hector Dearman1e269142018-11-14 13:53:08 +000058def find_protoc():
Primiano Tucci561ba7e2019-10-10 21:23:11 +010059 for root, _, files in os.walk(os.path.join(ROOT_DIR, 'out')):
Hector Dearman1e269142018-11-14 13:53:08 +000060 if 'protoc' in files:
61 return os.path.join(root, 'protoc')
Hector Dearman1e269142018-11-14 13:53:08 +000062 return None
63
64
Lalit Maganti82a2c042020-07-06 13:50:33 +010065def check_using_shas(source, target, file_with_shas):
66 with open(file_with_shas, 'rb') as f:
Hector Dearmanb7fa5442018-11-08 18:39:32 +000067 s = f.read()
68
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +010069 hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s.decode())
Hector Dearmanb7fa5442018-11-08 18:39:32 +000070 assert sorted([SCRIPT_PATH, source]) == sorted([key for key, _ in hashes])
71 for path, expected_sha1 in hashes:
72 actual_sha1 = hash_path(os.path.join(ROOT_DIR, path))
73 assert actual_sha1 == expected_sha1, \
Hector Dearman1e269142018-11-14 13:53:08 +000074 'In {} hash given for {} did not match'.format(target, path)
Hector Dearmanb7fa5442018-11-08 18:39:32 +000075
76
Lalit Maganti82a2c042020-07-06 13:50:33 +010077def check_raw_descriptor(source, target):
78 sha1_file = target + '.sha1'
79 assert os.path.exists(sha1_file), \
80 'SHA1 file {} does not exist and so cannot be checked'.format(sha1_file)
81
82 check_using_shas(source, target, sha1_file)
83
84
85def check(source, target):
86 assert os.path.exists(os.path.join(ROOT_DIR, target)), \
87 'Output file {} does not exist and so cannot be checked'.format(target)
88
89 if target.endswith('.descriptor.h'):
90 check_using_shas(source, target, target)
91 elif target.endswith('.descriptor'):
92 check_raw_descriptor(source, target)
93
94
95def write_cpp_header(source, target, descriptor_bytes):
Hector Dearmanb7fa5442018-11-08 18:39:32 +000096 _, source_name = os.path.split(source)
97 _, target_name = os.path.split(target)
98 assert source_name.replace('.proto', '.descriptor.h') == target_name
99
Lalit Maganti82a2c042020-07-06 13:50:33 +0100100 proto_name = source_name[:-len('.proto')].title().replace("_", "")
101 try:
102 ord(descriptor_bytes[0])
103 ordinal = ord
104 except TypeError:
105 ordinal = lambda x: x
106 binary = '{' + ', '.join('{0:#04x}'
107 .format(ordinal(c)) for c in descriptor_bytes) + '}'
108 binary = textwrap.fill(
109 binary, width=80, initial_indent=' ', subsequent_indent=' ')
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000110
Lalit Maganti82a2c042020-07-06 13:50:33 +0100111 with open(os.path.join(ROOT_DIR, target), 'wb') as f:
112 f.write("""/*
Primiano Tucci94c47f02019-12-05 03:13:11 +0000113 * Copyright (C) 2019 The Android Open Source Project
114 *
115 * Licensed under the Apache License, Version 2.0 (the "License");
116 * you may not use this file except in compliance with the License.
117 * You may obtain a copy of the License at
118 *
119 * http://www.apache.org/licenses/LICENSE-2.0
120 *
121 * Unless required by applicable law or agreed to in writing, software
122 * distributed under the License is distributed on an "AS IS" BASIS,
123 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124 * See the License for the specific language governing permissions and
125 * limitations under the License.
126 */
127
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000128#ifndef {include_guard}
129#define {include_guard}
130
131#include <stddef.h>
132#include <stdint.h>
133
134#include <array>
135
136// This file was autogenerated by tools/gen_binary_descriptors. Do not edit.
137
138// SHA1({script_path})
139// {script_hash}
140// SHA1({source_path})
141// {source_hash}
142
Florian Mayeracedbb62019-01-09 11:24:46 +0000143// This is the proto {proto_name} encoded as a ProtoFileDescriptor to allow
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000144// for reflection without libprotobuf full/non-lite protos.
145
146namespace perfetto {{
147
Lalit Maganti82a2c042020-07-06 13:50:33 +0100148constexpr std::array<uint8_t, {size}> k{proto_name}Descriptor{{
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000149{binary}}};
150
151}} // namespace perfetto
152
153#endif // {include_guard}
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100154""".format(
Lalit Maganti82a2c042020-07-06 13:50:33 +0100155 proto_name=proto_name,
156 size=len(descriptor_bytes),
157 binary=binary,
158 include_guard=target.replace('/', '_').replace('.', '_').upper() + '_',
159 script_path=SCRIPT_PATH,
160 script_hash=hash_path(__file__),
161 source_path=source,
162 source_hash=hash_path(os.path.join(source)),
163 ).encode())
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000164
165
Lalit Maganti82a2c042020-07-06 13:50:33 +0100166def write_raw_descriptor(source, target, descriptor_bytes):
167 with open(target, 'wb') as out:
168 out.write(descriptor_bytes)
169
170 sha1_path = target + '.sha1'
171 with open(sha1_path, 'wb') as c:
172 c.write("""
173// SHA1({script_path})
174// {script_hash}
175// SHA1({source_path})
176// {source_hash}
177""".format(
178 script_path=SCRIPT_PATH,
179 script_hash=hash_path(__file__),
180 source_path=source,
181 source_hash=hash_path(os.path.join(source)),
182 ).encode())
183
184
185
186def generate(source, target, protoc_path):
187 with tempfile.NamedTemporaryFile() as fdescriptor:
188 subprocess.check_call([
189 protoc_path,
190 '--include_imports',
191 '--proto_path=.',
192 '--proto_path=' + \
193 os.path.join(ROOT_DIR, "buildtools", "protobuf", "src"),
194 '--descriptor_set_out={}'.format(fdescriptor.name),
195 source,
196 ],
197 cwd=ROOT_DIR)
198
199 s = fdescriptor.read()
200 if target.endswith('.descriptor.h'):
201 write_cpp_header(source, target, s)
202 elif target.endswith('.descriptor'):
203 write_raw_descriptor(source, target, s)
204 else:
205 raise Exception('Unsupported target extension for file {}'.format(target))
206
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000207def main():
208 parser = argparse.ArgumentParser()
209 parser.add_argument('--check-only', action='store_true')
210 parser.add_argument('--protoc')
211 args = parser.parse_args()
212
Hector Dearman1e269142018-11-14 13:53:08 +0000213 try:
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100214 for source, target in iteritems(SOURCE_TARGET):
Hector Dearman1e269142018-11-14 13:53:08 +0000215 if args.check_only:
Primiano Tucci834fdc72019-10-04 11:33:44 +0100216 check(source, target)
Hector Dearman1e269142018-11-14 13:53:08 +0000217 else:
218 protoc = args.protoc or find_protoc()
219 assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)'
220 assert os.path.exists(protoc), '{} does not exist'.format(protoc)
221 if protoc is not args.protoc:
222 print('Using protoc: {}'.format(protoc))
223 generate(source, target, protoc)
224 except AssertionError as e:
225 if not str(e):
226 raise
227 print('Error: {}'.format(e))
Hector Dearman7e079772018-11-15 16:08:12 +0000228 return 1
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000229
Primiano Tucci834fdc72019-10-04 11:33:44 +0100230
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000231if __name__ == '__main__':
232 exit(main())