Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 1 | #!/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 | |
| 16 | from __future__ import absolute_import |
| 17 | from __future__ import division |
| 18 | from __future__ import print_function |
| 19 | import os |
| 20 | import re |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 21 | import sys |
Matthew Clarkson | 9a5dfa5 | 2019-10-03 09:54:04 +0100 | [diff] [blame] | 22 | from codecs import open |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 23 | |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 24 | PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
| 25 | |
| 26 | CONFIG_PROTO_ROOTS = [ |
Matthew Clarkson | 63028d6 | 2019-10-10 15:48:23 +0100 | [diff] [blame] | 27 | 'protos/perfetto/common/data_source_descriptor.proto', |
Primiano Tucci | bd25ec1 | 2020-04-17 10:22:28 +0100 | [diff] [blame] | 28 | 'protos/perfetto/common/tracing_service_state.proto', |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 29 | 'protos/perfetto/config/trace_config.proto' |
| 30 | ] |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 31 | MERGED_CONFIG_PROTO = 'protos/perfetto/config/perfetto_config.proto' |
| 32 | |
Andrew Shulaev | 46b12a9 | 2020-07-09 00:45:37 +0100 | [diff] [blame] | 33 | TRACE_PROTO_ROOTS = CONFIG_PROTO_ROOTS + [ |
| 34 | 'protos/perfetto/trace/trace.proto', |
| 35 | 'protos/perfetto/trace/test_extensions.proto', |
| 36 | ] |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 37 | MERGED_TRACE_PROTO = 'protos/perfetto/trace/perfetto_trace.proto' |
| 38 | |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 39 | METRICS_PROTOS_ROOTS = ['protos/perfetto/metrics/metrics.proto'] |
Lalit Maganti | aa035b2 | 2019-12-20 16:13:09 +0000 | [diff] [blame] | 40 | MERGED_METRICS_PROTO = 'protos/perfetto/metrics/perfetto_merged_metrics.proto' |
| 41 | |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 42 | REPLACEMENT_HEADER = ''' |
| 43 | // AUTOGENERATED - DO NOT EDIT |
| 44 | // --------------------------- |
| 45 | // This file has been generated by |
| 46 | // AOSP://external/perfetto/%s |
| 47 | // merging the perfetto config protos. |
| 48 | // This fused proto is intended to be copied in: |
| 49 | // - Android tree, for statsd. |
| 50 | // - Google internal repos. |
| 51 | |
| 52 | syntax = "proto2"; |
| 53 | |
| 54 | package perfetto.protos; |
| 55 | ''' |
| 56 | |
Matthew Clarkson | 63028d6 | 2019-10-10 15:48:23 +0100 | [diff] [blame] | 57 | |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 58 | def get_transitive_imports(rel_path, visited): |
| 59 | if rel_path in visited: |
| 60 | return [] |
| 61 | visited.add(rel_path) |
| 62 | with open(os.path.join(PROJECT_ROOT, rel_path), 'r', encoding='utf-8') as f: |
| 63 | content = f.read() |
| 64 | imports = re.findall(r'^import "(.*)";\n', content, flags=re.MULTILINE) |
| 65 | res = [] |
| 66 | for child in sorted(imports): |
| 67 | res += get_transitive_imports(child, visited) |
| 68 | res += [rel_path] |
| 69 | return res |
| 70 | |
| 71 | |
| 72 | def merge_protos_content(proto_paths): |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 73 | root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 74 | merged_content = REPLACEMENT_HEADER.lstrip() % __file__ |
| 75 | added_files = set() |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 76 | for proto in proto_paths: |
Lalit Maganti | aa035b2 | 2019-12-20 16:13:09 +0000 | [diff] [blame] | 77 | if proto in added_files: |
| 78 | continue |
| 79 | added_files.add(proto) |
| 80 | |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 81 | path = os.path.join(root_dir, proto) |
Matthew Clarkson | 9a5dfa5 | 2019-10-03 09:54:04 +0100 | [diff] [blame] | 82 | with open(path, 'r', encoding='utf-8') as f: |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 83 | content = f.read() |
| 84 | |
| 85 | # Remove header |
Florian Mayer | 12f0f8e | 2019-04-02 12:31:13 +0100 | [diff] [blame] | 86 | header = re.match(r'\/(\*|\/)(?:.|\s)*?package .*;\n', content) |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 87 | header = header.group(0) |
| 88 | content = content[len(header):] |
Lalit Maganti | aa035b2 | 2019-12-20 16:13:09 +0000 | [diff] [blame] | 89 | |
Isabelle Taylor | 80ec5f7 | 2019-02-27 11:27:41 +0000 | [diff] [blame] | 90 | content = re.sub(r'^import.*?\n\n?', '', content, flags=re.MULTILINE) |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 91 | merged_content += '\n// Begin of %s\n' % proto |
| 92 | merged_content += content |
| 93 | merged_content += '\n// End of %s\n' % proto |
| 94 | |
| 95 | definitions_re = r'^ *(?:message|enum) ([A-Z][A-Za-z0-9].*) {' |
| 96 | definitions = re.finditer(definitions_re, merged_content, re.MULTILINE) |
| 97 | types = set((match.group(1) for match in definitions)) |
| 98 | |
Ryan Savitski | 4756ef4 | 2020-02-12 15:14:06 +0000 | [diff] [blame] | 99 | # Limitation: |types| doesn't track the nesting of messages, so a reference to |
| 100 | # a nested message (optional One.Two f = 1;) is simplified to its leafmost |
| 101 | # name (Two in this example). |
| 102 | uses_re = r'^( +)(?:repeated)?(?:optional)?\s?'\ |
| 103 | r'(?:[A-Z]\w+\.)*([A-Z]\w+)\s+[a-z]\w*\s*=\s*(\d+);' |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 104 | uses = re.finditer(uses_re, merged_content, re.MULTILINE) |
| 105 | substitutions = [] |
| 106 | for use in uses: |
| 107 | everything = use.group(0) |
| 108 | indentation = use.group(1) |
| 109 | used_type = use.group(2) |
| 110 | field_number = use.group(3) |
| 111 | if used_type not in types: |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 112 | replacement = '{}// removed field with id {}'.format( |
| 113 | indentation, field_number) |
| 114 | substitutions.append((everything, replacement)) |
| 115 | |
| 116 | for before, after in substitutions: |
| 117 | merged_content = merged_content.replace(before, after) |
| 118 | |
Lalit Maganti | aa035b2 | 2019-12-20 16:13:09 +0000 | [diff] [blame] | 119 | return merged_content |
| 120 | |
| 121 | |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 122 | def merge_protos(root_paths, output_path): |
Lalit Maganti | aa035b2 | 2019-12-20 16:13:09 +0000 | [diff] [blame] | 123 | root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 124 | all_protos = [] |
| 125 | for root_path in root_paths: |
| 126 | all_protos += get_transitive_imports(root_path, visited=set()) |
| 127 | merged_content = merge_protos_content(all_protos) |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 128 | |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 129 | out_path = os.path.join(root_dir, output_path) |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 130 | prev_content = None |
| 131 | if os.path.exists(out_path): |
Matthew Clarkson | 9a5dfa5 | 2019-10-03 09:54:04 +0100 | [diff] [blame] | 132 | with open(out_path, 'r', encoding='utf-8') as fprev: |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 133 | prev_content = fprev.read() |
| 134 | |
| 135 | if prev_content == merged_content: |
| 136 | return True |
| 137 | |
| 138 | if '--check-only' in sys.argv: |
| 139 | return False |
| 140 | |
| 141 | print('Updating {}'.format(output_path)) |
Matthew Clarkson | 9a5dfa5 | 2019-10-03 09:54:04 +0100 | [diff] [blame] | 142 | with open(out_path, 'w', encoding='utf-8') as fout: |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 143 | fout.write(merged_content) |
| 144 | return True |
| 145 | |
Matthew Clarkson | 63028d6 | 2019-10-10 15:48:23 +0100 | [diff] [blame] | 146 | |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 147 | def main(): |
Primiano Tucci | c98edc4 | 2020-04-08 00:42:11 +0100 | [diff] [blame] | 148 | result = merge_protos(CONFIG_PROTO_ROOTS, MERGED_CONFIG_PROTO) |
| 149 | result &= merge_protos(TRACE_PROTO_ROOTS, MERGED_TRACE_PROTO) |
| 150 | result &= merge_protos(METRICS_PROTOS_ROOTS, MERGED_METRICS_PROTO) |
Eric Seckler | 0c7921b | 2020-01-10 09:46:13 +0000 | [diff] [blame] | 151 | return 0 if result else 1 |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 152 | |
Matthew Clarkson | 63028d6 | 2019-10-10 15:48:23 +0100 | [diff] [blame] | 153 | |
Hector Dearman | 55ef3e0 | 2018-04-11 17:28:55 +0100 | [diff] [blame] | 154 | if __name__ == '__main__': |
| 155 | sys.exit(main()) |