1#!/usr/bin/env python3 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 argparse 22import tempfile 23import subprocess 24import hashlib 25from compat import iteritems 26 27SOURCE_TARGET = [ 28 ( 29 'protos/perfetto/trace_processor/trace_processor.proto', 30 'src/trace_processor/python/perfetto/trace_processor/trace_processor.descriptor' 31 ), 32 ( 33 'protos/perfetto/metrics/metrics.proto', 34 'src/trace_processor/python/perfetto/trace_processor/metrics.descriptor' 35 ), 36] 37 38ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 39 40SCRIPT_PATH = 'tools/gen_binary_descriptors' 41 42 43def hash_path(path): 44 hash = hashlib.sha1() 45 with open(os.path.join(ROOT_DIR, path), 'rb') as f: 46 hash.update(f.read()) 47 return hash.hexdigest() 48 49 50def find_protoc(): 51 for root, _, files in os.walk(os.path.join(ROOT_DIR, 'out')): 52 if 'protoc' in files: 53 return os.path.join(root, 'protoc') 54 return None 55 56 57 58def check(source, target): 59 assert os.path.exists(os.path.join(ROOT_DIR, target)), \ 60 'Output file {} does not exist and so cannot be checked'.format(target) 61 62 sha1_file = target + '.sha1' 63 assert os.path.exists(sha1_file), \ 64 'SHA1 file {} does not exist and so cannot be checked'.format(sha1_file) 65 66 with open(sha1_file, 'rb') as f: 67 s = f.read() 68 69 hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s.decode()) 70 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, \ 74 'In {} hash given for {} did not match'.format(target, path) 75 76 77def generate(source, target, protoc_path): 78 with tempfile.NamedTemporaryFile() as fdescriptor: 79 subprocess.check_call([ 80 protoc_path, 81 '--include_imports', 82 '--proto_path=.', 83 '--proto_path=' + \ 84 os.path.join(ROOT_DIR, "buildtools", "protobuf", "src"), 85 '--descriptor_set_out={}'.format(fdescriptor.name), 86 source, 87 ], 88 cwd=ROOT_DIR) 89 90 s = fdescriptor.read() 91 with open(target, 'wb') as out: 92 out.write(s) 93 94 sha1_path = target + '.sha1' 95 with open(sha1_path, 'wb') as c: 96 c.write(""" 97// SHA1({script_path}) 98// {script_hash} 99// SHA1({source_path}) 100// {source_hash} 101 """.format( 102 script_path=SCRIPT_PATH, 103 script_hash=hash_path(__file__), 104 source_path=source, 105 source_hash=hash_path(os.path.join(source)), 106 ).encode()) 107 108def main(): 109 parser = argparse.ArgumentParser() 110 parser.add_argument('--check-only', action='store_true') 111 parser.add_argument('--protoc') 112 args = parser.parse_args() 113 114 try: 115 for source, target in SOURCE_TARGET: 116 if args.check_only: 117 check(source, target) 118 else: 119 protoc = args.protoc or find_protoc() 120 assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)' 121 assert os.path.exists(protoc), '{} does not exist'.format(protoc) 122 if protoc is not args.protoc: 123 print('Using protoc: {}'.format(protoc)) 124 generate(source, target, protoc) 125 except AssertionError as e: 126 if not str(e): 127 raise 128 print('Error: {}'.format(e)) 129 return 1 130 131 132if __name__ == '__main__': 133 exit(main()) 134