| #!/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()) |