blob: b8e700c80ec289ae9ea22b482d74a2844342e584 [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
27
28SOURCE_TARGET = {
29 'protos/perfetto/config/perfetto_config.proto':
30 'src/perfetto_cmd/perfetto_config.descriptor.h',
Lalit Magantieb1bf212019-05-08 15:07:16 +010031 'protos/perfetto/metrics/metrics.proto':
32 'src/trace_processor/metrics/metrics.descriptor.h',
Hector Dearmanb7fa5442018-11-08 18:39:32 +000033}
34
35ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
36
37SCRIPT_PATH = 'tools/gen_binary_descriptors'
38
Hector Dearman1e269142018-11-14 13:53:08 +000039
Hector Dearmanb7fa5442018-11-08 18:39:32 +000040def hash_path(path):
41 hash = hashlib.sha1()
42 with open(os.path.join(ROOT_DIR, path)) as f:
43 hash.update(f.read())
44 return hash.hexdigest()
45
46
Hector Dearman1e269142018-11-14 13:53:08 +000047def find_protoc():
48 for root, dirs, files in os.walk(ROOT_DIR):
49 if 'protoc' in files:
50 return os.path.join(root, 'protoc')
51 for name in ('src', 'buildtools'):
52 if name in dirs:
53 dirs.remove(name)
54 return None
55
56
Hector Dearmanb7fa5442018-11-08 18:39:32 +000057def check(source, target):
Hector Dearman1e269142018-11-14 13:53:08 +000058 assert os.path.exists(os.path.join(ROOT_DIR, target)), \
59 'Output file {} does not exist and so cannot be checked'.format(target)
Hector Dearmanb7fa5442018-11-08 18:39:32 +000060
61 with open(target, 'rb') as f:
62 s = f.read()
63
64 hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s)
65 assert sorted([SCRIPT_PATH, source]) == sorted([key for key, _ in hashes])
66 for path, expected_sha1 in hashes:
67 actual_sha1 = hash_path(os.path.join(ROOT_DIR, path))
68 assert actual_sha1 == expected_sha1, \
Hector Dearman1e269142018-11-14 13:53:08 +000069 'In {} hash given for {} did not match'.format(target, path)
Hector Dearmanb7fa5442018-11-08 18:39:32 +000070
71
72def generate(source, target, protoc_path):
73 _, source_name = os.path.split(source)
74 _, target_name = os.path.split(target)
75 assert source_name.replace('.proto', '.descriptor.h') == target_name
76
77 with tempfile.NamedTemporaryFile() as fdescriptor:
78 subprocess.check_call([
79 protoc_path,
Lalit Magantieb1bf212019-05-08 15:07:16 +010080 '--include_imports',
Hector Dearmanb7fa5442018-11-08 18:39:32 +000081 '--proto_path=protos',
Lalit Magantieb1bf212019-05-08 15:07:16 +010082 '--descriptor_set_out={}'.format(fdescriptor.name),
Hector Dearmanb7fa5442018-11-08 18:39:32 +000083 source,
84 ], cwd=ROOT_DIR)
85
86 s = fdescriptor.read()
Florian Mayeracedbb62019-01-09 11:24:46 +000087 proto_name = source_name[:-len('.proto')].title().replace("_", "")
88 constant_name = 'k' + proto_name + 'Descriptor'
Hector Dearmanb7fa5442018-11-08 18:39:32 +000089 binary = '{' + ', '.join('{0:#04x}'.format(ord(c)) for c in s) + '}'
90 binary = textwrap.fill(binary,
91 width=80,
92 initial_indent=' ',
93 subsequent_indent=' ')
94 include_guard = target.replace('/', '_').replace('.', '_').upper() + '_'
95
96 with open(os.path.join(ROOT_DIR, target), 'wb') as f:
97 f.write("""
98#ifndef {include_guard}
99#define {include_guard}
100
101#include <stddef.h>
102#include <stdint.h>
103
104#include <array>
105
106// This file was autogenerated by tools/gen_binary_descriptors. Do not edit.
107
108// SHA1({script_path})
109// {script_hash}
110// SHA1({source_path})
111// {source_hash}
112
Florian Mayeracedbb62019-01-09 11:24:46 +0000113// This is the proto {proto_name} encoded as a ProtoFileDescriptor to allow
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000114// for reflection without libprotobuf full/non-lite protos.
115
116namespace perfetto {{
117
118constexpr std::array<uint8_t, {size}> {constant_name}{{
119{binary}}};
120
121}} // namespace perfetto
122
123#endif // {include_guard}
124""".format(**{
Florian Mayeracedbb62019-01-09 11:24:46 +0000125 'proto_name': proto_name,
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000126 'size': len(s),
127 'constant_name': constant_name,
128 'binary': binary,
129 'include_guard': include_guard,
130 'script_path': SCRIPT_PATH,
131 'script_hash': hash_path(__file__),
132 'source_path': source,
133 'source_hash': hash_path(os.path.join(source)),
134 }))
135
136
137def main():
138 parser = argparse.ArgumentParser()
139 parser.add_argument('--check-only', action='store_true')
140 parser.add_argument('--protoc')
141 args = parser.parse_args()
142
Hector Dearman1e269142018-11-14 13:53:08 +0000143 try:
144 for source, target in SOURCE_TARGET.iteritems():
145 if args.check_only:
146 check(source, target)
147 else:
148 protoc = args.protoc or find_protoc()
149 assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)'
150 assert os.path.exists(protoc), '{} does not exist'.format(protoc)
151 if protoc is not args.protoc:
152 print('Using protoc: {}'.format(protoc))
153 generate(source, target, protoc)
154 except AssertionError as e:
155 if not str(e):
156 raise
157 print('Error: {}'.format(e))
Hector Dearman7e079772018-11-15 16:08:12 +0000158 return 1
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000159
160if __name__ == '__main__':
161 exit(main())