188 lines
5.8 KiB
Python
Executable File
188 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (C) 2018 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
import os
|
|
import re
|
|
import sys
|
|
import argparse
|
|
import tempfile
|
|
import subprocess
|
|
import hashlib
|
|
import textwrap
|
|
from compat import iteritems
|
|
|
|
SOURCE_TARGET = {
|
|
'protos/perfetto/config/perfetto_config.proto':
|
|
'src/perfetto_cmd/perfetto_config.descriptor.h',
|
|
'protos/perfetto/metrics/metrics.proto':
|
|
'src/trace_processor/metrics/metrics.descriptor.h',
|
|
'src/protozero/test/example_proto/test_messages.proto':
|
|
'src/protozero/test/example_proto/test_messages.descriptor.h',
|
|
'protos/perfetto/trace/track_event/track_event.proto':
|
|
'src/trace_processor/importers/proto/track_event.descriptor.h',
|
|
'protos/perfetto/metrics/custom_options.proto':
|
|
'src/trace_processor/metrics/custom_options.descriptor.h',
|
|
}
|
|
|
|
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
|
|
SCRIPT_PATH = 'tools/gen_binary_descriptors'
|
|
|
|
|
|
def hash_path(path):
|
|
hash = hashlib.sha1()
|
|
with open(os.path.join(ROOT_DIR, path), 'rb') as f:
|
|
hash.update(f.read())
|
|
return hash.hexdigest()
|
|
|
|
|
|
def find_protoc():
|
|
for root, _, files in os.walk(os.path.join(ROOT_DIR, 'out')):
|
|
if 'protoc' in files:
|
|
return os.path.join(root, 'protoc')
|
|
return None
|
|
|
|
|
|
def check(source, target):
|
|
assert os.path.exists(os.path.join(ROOT_DIR, target)), \
|
|
'Output file {} does not exist and so cannot be checked'.format(target)
|
|
|
|
with open(target, 'rb') as f:
|
|
s = f.read()
|
|
|
|
hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s.decode())
|
|
assert sorted([SCRIPT_PATH, source]) == sorted([key for key, _ in hashes])
|
|
for path, expected_sha1 in hashes:
|
|
actual_sha1 = hash_path(os.path.join(ROOT_DIR, path))
|
|
assert actual_sha1 == expected_sha1, \
|
|
'In {} hash given for {} did not match'.format(target, path)
|
|
|
|
|
|
def generate(source, target, protoc_path):
|
|
_, source_name = os.path.split(source)
|
|
_, target_name = os.path.split(target)
|
|
assert source_name.replace('.proto', '.descriptor.h') == target_name
|
|
|
|
with tempfile.NamedTemporaryFile() as fdescriptor:
|
|
subprocess.check_call([
|
|
protoc_path,
|
|
'--include_imports',
|
|
'--proto_path=.',
|
|
'--proto_path=' + \
|
|
os.path.join(ROOT_DIR, "buildtools", "protobuf", "src"),
|
|
'--descriptor_set_out={}'.format(fdescriptor.name),
|
|
source,
|
|
],
|
|
cwd=ROOT_DIR)
|
|
|
|
s = fdescriptor.read()
|
|
proto_name = source_name[:-len('.proto')].title().replace("_", "")
|
|
constant_name = 'k' + proto_name + 'Descriptor'
|
|
try:
|
|
ord(s[0])
|
|
ordinal = ord
|
|
except TypeError:
|
|
ordinal = lambda x: x
|
|
binary = '{' + ', '.join('{0:#04x}'.format(ordinal(c)) for c in s) + '}'
|
|
binary = textwrap.fill(
|
|
binary, width=80, initial_indent=' ', subsequent_indent=' ')
|
|
include_guard = target.replace('/', '_').replace('.', '_').upper() + '_'
|
|
|
|
with open(os.path.join(ROOT_DIR, target), 'wb') as f:
|
|
f.write("""/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef {include_guard}
|
|
#define {include_guard}
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <array>
|
|
|
|
// This file was autogenerated by tools/gen_binary_descriptors. Do not edit.
|
|
|
|
// SHA1({script_path})
|
|
// {script_hash}
|
|
// SHA1({source_path})
|
|
// {source_hash}
|
|
|
|
// This is the proto {proto_name} encoded as a ProtoFileDescriptor to allow
|
|
// for reflection without libprotobuf full/non-lite protos.
|
|
|
|
namespace perfetto {{
|
|
|
|
constexpr std::array<uint8_t, {size}> {constant_name}{{
|
|
{binary}}};
|
|
|
|
}} // namespace perfetto
|
|
|
|
#endif // {include_guard}
|
|
""".format(
|
|
proto_name=proto_name,
|
|
size=len(s),
|
|
constant_name=constant_name,
|
|
binary=binary,
|
|
include_guard=include_guard,
|
|
script_path=SCRIPT_PATH,
|
|
script_hash=hash_path(__file__),
|
|
source_path=source,
|
|
source_hash=hash_path(os.path.join(source)),
|
|
).encode())
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--check-only', action='store_true')
|
|
parser.add_argument('--protoc')
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
for source, target in iteritems(SOURCE_TARGET):
|
|
if args.check_only:
|
|
check(source, target)
|
|
else:
|
|
protoc = args.protoc or find_protoc()
|
|
assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)'
|
|
assert os.path.exists(protoc), '{} does not exist'.format(protoc)
|
|
if protoc is not args.protoc:
|
|
print('Using protoc: {}'.format(protoc))
|
|
generate(source, target, protoc)
|
|
except AssertionError as e:
|
|
if not str(e):
|
|
raise
|
|
print('Error: {}'.format(e))
|
|
return 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
exit(main())
|