• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    ('protos/perfetto/trace_processor/trace_processor.proto',
29     'python/perfetto/trace_processor/trace_processor.descriptor'
30    ),
31    ('protos/perfetto/metrics/metrics.proto',
32     'python/perfetto/trace_processor/metrics.descriptor'),
33]
34
35ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
36
37SCRIPT_PATH = 'tools/gen_binary_descriptors'
38
39
40def hash_path(path):
41  hash = hashlib.sha1()
42  with open(os.path.join(ROOT_DIR, path), 'rb') as f:
43    hash.update(f.read())
44  return hash.hexdigest()
45
46
47def find_protoc():
48  for root, _, files in os.walk(os.path.join(ROOT_DIR, 'out')):
49    if 'protoc' in files:
50      return os.path.join(root, 'protoc')
51  return None
52
53
54def check(source, target):
55  assert os.path.exists(os.path.join(ROOT_DIR, target)), \
56      'Output file {} does not exist and so cannot be checked'.format(target)
57
58  sha1_file = target + '.sha1'
59  assert os.path.exists(sha1_file), \
60      'SHA1 file {} does not exist and so cannot be checked'.format(sha1_file)
61
62  with open(sha1_file, 'rb') as f:
63    s = f.read()
64
65  hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s.decode())
66  assert sorted([SCRIPT_PATH, source]) == sorted([key for key, _ in hashes])
67  for path, expected_sha1 in hashes:
68    actual_sha1 = hash_path(os.path.join(ROOT_DIR, path))
69    assert actual_sha1 == expected_sha1, \
70        'In {} hash given for {} did not match'.format(target, path)
71
72
73def generate(source, target, protoc_path):
74  # delete=False + manual unlink is required for Windows. Otherwise the temp
75  # file is kept locked exclusively and unaccassible until it's destroyed.
76  with tempfile.NamedTemporaryFile(delete=False) as fdescriptor:
77    subprocess.check_call([
78        protoc_path,
79        '--include_imports',
80        '--proto_path=.',
81        '--proto_path=' + \
82            os.path.join(ROOT_DIR, "buildtools", "protobuf", "src"),
83        '--descriptor_set_out={}'.format(fdescriptor.name),
84        source,
85    ], cwd=ROOT_DIR)
86
87    s = fdescriptor.read()
88    fdescriptor.close()
89    os.remove(fdescriptor.name)
90    with open(target, 'wb') as out:
91      out.write(s)
92
93    sha1_path = target + '.sha1'
94    with open(sha1_path, 'wb') as c:
95      c.write("""
96// SHA1({script_path})
97// {script_hash}
98// SHA1({source_path})
99// {source_hash}
100  """.format(
101          script_path=SCRIPT_PATH,
102          script_hash=hash_path(__file__),
103          source_path=source,
104          source_hash=hash_path(os.path.join(source)),
105      ).encode())
106
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